IPSec : Sécurité des communications réseau

Pour ce nouvel article, je vais aborder une notion de sécurité assez avancée : la mise en place du système de sécurité IPSec.

Ce système permet de chiffrer toute communication entre deux hôtes correctement configurés, et cela quel que soit le protocole applicatif utilisé puisque le chiffrement et l’authentification des données échangés par les machines seront faits au niveau 3 du modèle OSI, à savoir la couche de réseau.

La mise en application de cet article est la portée de tout le monde, la compréhension de l’intégralité du système de sécurité mise en place et son dépannage demande par contre de solides connaissances en réseau.

Un peu de théorie

Avant de passer à l’étape ligne de commande, tâchons de comprendre ce que nous allons faire.

L’objectif recherché ici est la mise en place d’un chiffrement de toute communication entre deux machines. Généralement lorsque vous souhaitez sécuriser une communication vous utilisez la version avec chiffrement SSL du protocole utile à votre application (HTTPS, IMAPS, etc.). Seulement comment faire lorsque les applications que vous utilisez n’ont pas de version sécurisé ? Votre logiciel de compta par exemple.

La solution se trouve dans le fonctionnement même des communications réseau. Tout protocole se sert aujourd’hui de l’Internet Protocol (IP) pour communiquer avec le reste du réseau. L’idée est donc de faire en sorte que les briques inférieures servant à un protocole non sécurisé servent à chiffrer les communications.

Pour cela, nous allons utiliser la suite d’outils IPSec. Cette suite a été créée pour l’IPv6 puis adaptée à l’IPv4.

IPSec se comporte de plusieurs outils, dont deux que je vais détailler ici.

Le premier se nomme AH pour Authentication Header, son rôle est de garantir l’authenticité des paquets reçus depuis le réseau. Deux machines partagent une paire de clefs symétriques, IPSec AH va faire une empreinte du paquet envoyé et la chiffrer. À la réception, IPSec AH va vérifier tout paquet reçu pour être certain que son contenu n’a pas été modifié durant la communication en déchiffrant l’empreinte et en la comparant avec le paquet reçu, garantissant ainsi qu’il provient bien d’une machine avec qui vous partagez cette clef.

Le second se nomme ESP pour Encapsulating Security Payload, son rôle est de chiffrer le paquet d’origine. Il s’assure ainsi que le contenu du paquet n’est pas dévoilé sur le réseau.

Est-ce bien nécessaire ?

C’est la question que l’on peut légitimement se poser si l’on n’est pas au fait de l’actualité touchant à la sécurité réseau.

Pour vous montrer en quoi cela est nécessaire, je vais simuler une attaque sur mon réseau privé. Une machine A va héberger un site web, une machine B va le consulter en HTTP et une troisième machine va s’interposer entre les deux pour écouter la communication. (Bien entendu ce cas précis pourrait être sécurisé par la mise en place d’un serveur HTTPS mais ce n’est qu’un exemple.)

Je n’expliquerais pas ici les détails de l’attaque, il y a suffisamment de sites web qui expliquent comment faire, les captures d’écrans suffisent à savoir quoi chercher.

Comme vous pouvez le voir sur la machine cliente, le site s’affiche normalement, sans aucune alerte de sécurité alors que la machine attaquante a bien accès au contenu de la communication (et pourrait même dans ce cas le modifier à la volée).

Prise en main d’IPSec

IPSec dispose de plusieurs options de configurations, nous allons le prendre en main progressivement et commencer par lui donner les règles et clefs à la main. Par la suite nous essayerons d’avoir la configuration la plus générique possible.

La configuration manuelle est au final assez simple, il faut lui dire d’une part quelles sont les clefs à utiliser en fonction du type de communication et d’autre part quelles sont les communications à chiffrer.

Pour ce faire nous allons utiliser la commande setkey et son commutateur -c pour passer les commandes de configurations sur l’entrée standard, il faudrait faire un ctrl-D pour sortir de la commande.

La machine yoann-laptop dispose de l’IP 100 et yoann-small-laptop 104 :

root@yoann-laptop ~ 22:42 % setkey -c
add 192.168.42.100 192.168.42.104 esp 3000 -m transport -E blowfish-cbc "ABCDEFGHIJKLMNOPQRST";
add 192.168.42.104 192.168.42.100 esp 3001 -m transport -E blowfish-cbc "ABCDEFGHIJKLMNOPQRST";
add 192.168.42.100 192.168.42.104 ah 3002 -m transport -A hmac-sha1 "ABCDEFGHIJKLMNOPQRST";
add 192.168.42.100 192.168.42.104 ah 3003 -m transport -A hmac-sha1 "ABCDEFGHIJKLMNOPQRST";
spdadd 192.168.42.100 192.168.42.104 any -P out ipsec esp/transport//use ah/transport//use;
^D

Ici nous indiquons à la machine les clefs à utiliser pour chiffrer et authentifier les paquets à destination de 192.168.42.104 et vérifier ceux de cette provenance. Puis nous indiquons que toute communication sortante sur n’importe quel port à destination de 192.168.42.104 doit être chiffrée puis authentifié. Reste à faire le même type de configuration de l’autre côté.

root@yoann-small-laptop ~ 22:46 % setkey -c
add 192.168.42.100 192.168.42.104 esp 3000 -m transport -E blowfish-cbc "ABCDEFGHIJKLMNOPQRST";
add 192.168.42.104 192.168.42.100 esp 3001 -m transport -E blowfish-cbc "ABCDEFGHIJKLMNOPQRST";
add 192.168.42.100 192.168.42.104 ah 3002 -m transport -A hmac-sha1 "ABCDEFGHIJKLMNOPQRST";
add 192.168.42.100 192.168.42.104 ah 3003 -m transport -A hmac-sha1 "ABCDEFGHIJKLMNOPQRST";
spdadd 192.168.42.104 192.168.42.100 any -P out ipsec esp/transport//use ah/transport//use;
^D

Maintenant que cette configuration est faite, voici ce que nous pouvons voir du côté de l’attaquant :

Impossible d’accéder au contenu des paquets, la communications est sécurisé (tout du moins si on nous faisons abstraction du niveau de sécurité de la clef).

Cette solution bien que fonctionnelle est encore perfectible, en effet le choix de la clef ici n’était pas anodin, ni même celui des algorithmes de chiffrement. En effet, chaque système nécessite une clef d’une longueur particulière. Voici un extrait de la page de manuel de setkey qui résume les options disponibles :

   Algorithms
     The following list shows the supported algorithms.  protocol and
     algorithm are almost orthogonal.  These authentication algorithms can be
     used as aalgo in -A aalgo of the protocol parameter:
 
           algorithm       keylen (bits)
           hmac-md5        128             ah: rfc2403
                           128             ah-old: rfc2085
           hmac-sha1       160             ah: rfc2404
                           160             ah-old: 128bit ICV (no document)
           keyed-md5       128             ah: 96bit ICV (no document)
                           128             ah-old: rfc1828
           keyed-sha1      160             ah: 96bit ICV (no document)
                           160             ah-old: 128bit ICV (no document)
           null            0 to 2048       for debugging
           hmac-sha256     256             ah: 96bit ICV
                                           (draft-ietf-ipsec-ciph-sha-256-00)
                           256             ah-old: 128bit ICV (no document)
           hmac-sha384     384             ah: 96bit ICV (no document)
                           384             ah-old: 128bit ICV (no document)
           hmac-sha512     512             ah: 96bit ICV (no document)
                           512             ah-old: 128bit ICV (no document)
           hmac-ripemd160  160             ah: 96bit ICV (RFC2857)
                                           ah-old: 128bit ICV (no document)
           aes-xcbc-mac    128             ah: 96bit ICV (RFC3566)
                           128             ah-old: 128bit ICV (no document)
           tcp-md5         8 to 640        tcp: rfc2385
 
     These encryption algorithms can be used as ealgo in -E ealgo of the
     protocol parameter:
 
           algorithm       keylen (bits)
           des-cbc         64              esp-old: rfc1829, esp: rfc2405
           3des-cbc        192             rfc2451
           null            0 to 2048       rfc2410
           blowfish-cbc    40 to 448       rfc2451
           cast128-cbc     40 to 128       rfc2451
           des-deriv       64              ipsec-ciph-des-derived-01
           3des-deriv      192             no document
           rijndael-cbc    128/192/256     rfc3602
           twofish-cbc     0 to 256        draft-ietf-ipsec-ciph-aes-cbc-01
           aes-ctr         160/224/288     draft-ietf-ipsec-ciph-aes-ctr-03
 
     Note that the first 128 bits of a key for aes-ctr will be used as AES
     key, and the remaining 32 bits will be used as nonce.

Dans mon exemple, j’ai choisi les algorithmes blowfish et sha1, car ils sont compatibles au niveau des longueurs de clef. Pour autant, ce n’est pas pratique de devoir trouver une clef d’une longueur bien précise et de penser à la renouveler le plus souvent possible. D’autant qu’une clef pour être sécurisé devrait être aléatoire et sans aucune signification humaine…

Racoon, l’échange de clef automatisé

Racoon est l’implémentation utilisée par Mac OS X pour un autre outil de la suite IPSec, l’IKE pour Internet Key Exchange. Cet outil va nous permettre de configurer l’échange de clef de manière automatisée entre deux hôtes disposant d’un même secret partagé.

Cet outil est d’ailleurs utilisé par le service Back To My Mac de Mobile Me pour la négociation de clef entre votre machine et les serveurs d’Apple pour sécuriser la communication.

Nous allons nous en servir ici de différente manière, toujours en partant de la plus simple à la plus complexe.

Le but de Racoon est de créer des clefs sécurisées après authentification de l’hôte distant, pour cela il existe plusieurs possibilités, dont l’utilisation d’un secret partagé.

Avec la méthode du secret partagé, nous allons devoir éditer le fichier /etc/racoon/psk.txt pour y ajouter une ligne associant l’IP de la machine distante et la clef allant avec :

Sur yoann-laptop

192.168.42.104 toomanysecret

Sur yoann-small-laptop

192.168.42.100 toomanysecret

Attention à ne pas changer les droits d’accès de ce fichier, personne ne doit y avoir accès !

Maintenant que les secrets sont en place, nous allons configurer les règles du noyau avec setkey pour les utiliser :

root@yoann-laptop ~ 22:42 % setkey -c
spdadd 192.168.42.100 192.168.42.104 any -P out ipsec esp/transport//require ah/transport//require;
spdadd 192.168.42.104 192.168.42.100 any -P in ipsec esp/transport//require ah/transport//require;
^D
root@yoann-small-laptop ~ 22:46 % setkey -c
spdadd 192.168.42.104 192.168.42.100 any -P out ipsec esp/transport//require ah/transport//require;
spdadd 192.168.42.100 192.168.42.104 any -P in ipsec esp/transport//require ah/transport//require;
^D

Vous remarquerez que nous sommes passés de //use à //require. Ce mot clef est ici pour spécifier comment sont trouvés les secrets à utiliser pour chiffrer la communication.

Il y en a trois différents : default utilise les règles par défaut du noyau (voir dans sysctl) ; use essaye d’utiliser des polices provenant de Racoon et s’il n’en trouve pas il utilise les polices réglées à la main avec setkey ; require, il impose l’usage de règle venant d’un échange de clef avec Racoon.

Il manque encore une chose pour que l’échange de clef se fasse. Donner à Racoon des règles de comportement face à des étrangers. Il faut lui dire comment négocier les clefs et avec quelles options en fonction de la personne distante.

Nous verrons comment gérer des politiques différentes en fonction de la cible plus tard, pour le moment nous allons nous contenter de travailler avec un cas générique, en ciblant les pairs anonymes, soit tous ceux n’ayant pas de règles spécifiques.

En lisant le fichier de configuration /etc/racoon.conf nous pouvons remarquer que les règles d’identification remote anonymous et d’association de sécurité sainfo anonymous sont commentés, d’après les commentaires ces règles sont censé se trouver dans un fichier inexistant /etc/racoon/remote/anonymous.conf. Même en créant ce dossier et ce fichier à la main, ils ne sont pas inclus dans le fichier de configuration de Racoon, il faudra donc rajouter une directive include dans le fichier principal (prendre exemple sur la dernière ligne)

Nous allons donc créer le dossier /etc/racoon/remote sur chaque machine et y ajouter un fichier anonymous.conf avec le contenu suivant :

remote anonymous
{
       exchange_mode main,aggressive;
       #exchange_mode aggressive,main;
       doi ipsec_doi;
       situation identity_only;
 
       my_identifier address;
       #my_identifier user_fqdn "macuser@localhost";
       #peers_identifier user_fqdn "macuser@localhost";
       #certificate_type x509 "mycert" "mypriv";
 
       nonce_size 16;
       lifetime time 1 min;    # sec,min,hour
       initial_contact on;
       proposal_check obey;    # obey, strict or claim
 
       proposal {
               encryption_algorithm 3des;
               hash_algorithm sha1;
               authentication_method pre_shared_key ;
               dh_group 2;
       }
}
 
sainfo anonymous
{
       pfs_group 1;
       lifetime time 30 sec;
       encryption_algorithm aes, 3des ;
       authentication_algorithm hmac_sha1;
       compression_algorithm deflate ;
}

ATTENTION : Si vous avez Back To My Mac de configurer, il configure déjà une règle de type anonymous, vous aurez donc un conflit… Je vous recommande de prendre d’autres machines le temps de finir la lecture de cet article ou de désactiver BTMM.

Il reste maintenant à lancer Racoon via la commande du même nom. Pour avoir plus de détails durant les phases de test j’utilise la commande avec les options de debug suivantes :

racoon -v -dddddd -l /var/log/racoon.log

Si vous avez correctement suivi cet article, votre configuration est fonctionnelle, si vous faites un ping vers l’autre machine, vous verrez que les ping n’aboutissent pas au début, le temps que l’échange de clef se fasse, ensuite tout reviens à la normale :

yoanngini@yoann-laptop ~ 10:08 % ping 192.168.42.104
PING 192.168.42.104 (192.168.42.104): 56 data bytes
Request timeout for icmp_seq 0
Request timeout for icmp_seq 1
Request timeout for icmp_seq 2
Request timeout for icmp_seq 3
Request timeout for icmp_seq 4
Request timeout for icmp_seq 5
Request timeout for icmp_seq 6
64 bytes from 192.168.42.104: icmp_seq=7 ttl=64 time=168.401 ms
64 bytes from 192.168.42.104: icmp_seq=8 ttl=64 time=294.608 ms
64 bytes from 192.168.42.104: icmp_seq=9 ttl=64 time=216.441 ms
64 bytes from 192.168.42.104: icmp_seq=10 ttl=64 time=137.616 ms
64 bytes from 192.168.42.104: icmp_seq=11 ttl=64 time=371.061 ms

Notre configuration simplifiée de Racoon est donc fonctionnelle. Il est temps de voir comment stabiliser tout cela.

Racoon, options avancées

Ce que nous allons voir maintenant, c’est comment remplacer les règles anonymes actuelles par des règles ciblant correctement les machines distantes.

Dans la foulée nous allons configurer les options concernant les algorithmes utilisés ainsi que les durées de vie des clefs.

Pour cela nous allons supprimer le fichier anonymous.conf pour le remplacer par un autre qui ne concernera que votre réseau. Je vais nomme le mien office.inig-services.com.conf, toujours dans /etc/racoon/remote.

En voici le contenu :

remote 192.168.42.104
{
	my_identifier fqdn "yoann-laptop.office.inig-services.com";
 
	exchange_mode base;
 
	doi ipsec_doi;
	situation identity_only;
 
	nonce_size 16;
	lifetime time 15 min;
 
	initial_contact on;
	support_proxy on;
 
	proposal_check obey;
	proposal {
		encryption_algorithm aes;
		hash_algorithm sha256;
		authentication_method pre_shared_key;
		dh_group 2;
		lifetime time 15 min;
	}
}
 
sainfo address 192.168.42.100 any address 192.168.42.104 any
{
	pfs_group 2;
	lifetime time 10 min;
	encryption_algorithm aes;
	authentication_algorithm hmac_sha256;
	compression_algorithm deflate;
}
 
sainfo address 192.168.42.104 any address 192.168.42.100 any
{
	pfs_group 2;
	lifetime time 10 min;
	encryption_algorithm aes;
	authentication_algorithm hmac_sha256;
	compression_algorithm deflate;
}

En regard de la clef remote on place l’IP de l’autre machine et au niveau de my_identifier, c’est bien entendu l’identifiant de la machine locale.

Il n’y a pas de grande différence avec l’étape précédente sinon la possibilité de spécifier pour une cible particulière une méthode d’authentification et de chiffrement adéquat.

Attention, les commandes setkey sont toujours nécessaire ici, si vous avez redémarré votre machine, il faudra les retaper :

root@yoann-laptop ~ 22:42 % setkey -c
spdadd 192.168.42.100 192.168.42.104 any -P out ipsec esp/transport//require ah/transport//require;
spdadd 192.168.42.104 192.168.42.100 any -P in ipsec esp/transport//require ah/transport//require;
^D
root@yoann-small-laptop ~ 22:46 % setkey -c
spdadd 192.168.42.104 192.168.42.100 any -P out ipsec esp/transport//require ah/transport//require;
spdadd 192.168.42.100 192.168.42.104 any -P in ipsec esp/transport//require ah/transport//require;
^D

L’intérêt de cette étape va se trouver dans la suite de l’article.

La même chose en IPv6

Déjà on peut se demander pourquoi passer en IPv6. La réponse est simple, nous utilisons les IP des machines distantes pour savoir si nous devons ou non chiffrer la communication. J’ai ici configuré tout cela avec des IP venant d’une classe non routable sur Internet et réservée aux réseaux privés. Cela pose un gros problème, lorsque ma machine va se retrouver dans un autre réseau avec le plan d’adressage, je ne pourrais pas communiquer avec les machines ayant des IP utilisant IPSec chez moi.

L’IPv6 (pour qui a originellement été conçu IPSec) devient donc extrêmement intéressant puisque cela va permettre de faire une configuration IPSec sans aucune collision possible.

Je vais donc modifier mon fichier de configuration pour l’adapter à mon serveur. L’objectif va être de sécuriser les communications IPv6, et cela quelle que soit la source de la communication. Il faudra donc que le serveur rajoute des règles de chiffrement à la volée (puisque les adresses IP distantes sont inconnues à la base).

Le fichier de configuration client ne change que très peu :

remote 2a01:e35:8b17:35b0:20c:29ff:fe98:9fca
{
        my_identifier fqdn "client.office.inig-services.com";
 
        exchange_mode base;
 
        doi ipsec_doi;
        situation identity_only;
 
        nonce_size 16;
        lifetime time 15 min;
 
        initial_contact on;
        support_proxy on;
 
        proposal_check obey;
        proposal {
                encryption_algorithm aes;
                hash_algorithm sha256;
                authentication_method pre_shared_key;
                dh_group 2;
                lifetime time 15 min;
        }
}
 
sainfo anonymous address 2a01:e35:8b17:35b0:20c:29ff:fe98:9fca any
{
        pfs_group 2;
        lifetime time 10 min;
        encryption_algorithm aes;
        authentication_algorithm hmac_sha256;
        compression_algorithm deflate;
}

Ici j’ai tout simplement remplacé les adresses IPv4 par leur pendant IPv6 et j’en ai également profité pour remplacer les sainfo pour les rendre plus générique, ici peu importe l’adresse source de la communication, c’est la cible qui compte. De la même manière, l’identification se fera avec un FQDN générique (puisque partagé entre les machines clientes).

Il va également falloir éditer le fichier psk.txt du client pour y ajouter le secret partagé concernant ce serveur :

2a01:e35:8b17:35b0:20c:29ff:fe98:9fca   toomanysecret

Comme à chaque fois, il faut également préciser avec setkey les machines qui demandent de l’IPSec, sauf que cette fois la règle sera également anonyme :

root@yoann-laptop ~ 22:42 % setkey -c
spdadd ::/0 2a01:e35:8b17:35b0:20c:29ff:fe98:9fca any -P out ipsec esp/transport//require ah/transport//require;
^D

Côté serveur, si vous avez un serveur VPN en L2TP il serait bon de le désactiver le temps de suivre cet article. En effet, le serveur L2TP via IPSec utilise les mêmes options que nous. Il faudra donc faire attention à avoir des configurations compatibles si votre serveur Mac fait serveur VPN.

L’astuce consiste à dire à racoon de travailler avec des anonymes et de créer les polices à la volée, tout en n’étant pas lui même à l’origine de la connexion.

remote anonymous
{
        my_identifier fqdn "ipsec.office.inig-services.com";
 
        exchange_mode base;
 
        generate_policy on;
        passive on;
 
        doi ipsec_doi;
        situation identity_only;
 
        nonce_size 16;
        lifetime time 15 min;
 
        initial_contact on;
        support_proxy on;
 
        nat_traversal_multi_user on;
 
        proposal_check obey;
        proposal {
                encryption_algorithm aes;
                hash_algorithm sha256;
                authentication_method pre_shared_key;
                dh_group 2;
                lifetime time 15 min;
        }
}
 
sainfo anonymous
{
        pfs_group 2;
        lifetime time 10 min;
        encryption_algorithm aes;
        authentication_algorithm hmac_sha256;
        compression_algorithm deflate;
}

Ce qui revient à lui dire « pour toute connexion anonyme entrante et demandant une connexion sécuriser, tu crées la règle, sinon tu ne fais rien ».

Et de la même manière, on modifie le fichier psk.txt côté serveur :

client.office.inig-services.com   toomanysecret

Il va également falloir éditer le fichier psk.txt du client pour y ajouter le secret partagé concernant ce serveur :

2a01:e35:8b17:35b0:20c:29ff:fe98:9fca   toomanysecret

Si maintenant vous souhaitez que votre serveur n’accepte que des communications entrantes en IPSec, il va falloir jouer au niveau de votre firewall.

Le redémarrage

Comme vous pouvez vous en douter, tout ce qui fut écrit dans un fichier de configuration est persistant au redémarrage, par contre les règles entrées avec setkey ne le sont pas. À vous de créer un script au lancement de la machine qui utilisera le commutateur -f de cette commande pour charger toutes les informations depuis un fichier de configuration à vous.

J’arrive au terme de cet article, c’est une introduction qui se veut simple pour que vous commenciez à essayer IPSec de votre côté et éventuellement à avoir envie d’IPv6 chez vous :-)

Quelques recommandations de dernières minutes, assurez-vous d’avoir un accès console à vos machines de test les premiers temps.

Comme toujours, les commentaires sont là si besoin !

2 réflexions au sujet de « IPSec : Sécurité des communications réseau »

  1. Merci pour cet article, j’ai souvent entendu parler d’IPSec sans aller regarder ce que c’était, maintenant je sais.

    Juste une petite remarque de vocabulaire (parce que mon domaine c’est les PKI). Ce que tu appelles signature n’en est pas une car le hash est chiffré avec une clé symétrique et pas asymétrique (à part ça, techniquement c’est le même principe). Le secret étant partagé, la non répudiation n’est pas assurée.
    Ca s’appelle un HMAC. Seules l’intégrité et l’authenticité sont assurées. Avec la signature électronique, tu as aussi la non répudiation.

Laisser un commentaire