Sondes de détection : performances, évaluations et biais

En avril 2019, l’ANSSI a qualifié les premières sondes pour assurer la supervision de sécurité de réseaux. Les OIV, les OSE et, d’une manière générale, les organismes opérant des fonctions sensibles disposent ainsi de produits français de confiance : Cybels Sensor de Thales et Trackwatch Full Edition de Gatewatcher. La méthodologie d’évaluation des sondes n’est, hélas, pas publique. Les ingénieurs sécurité et réseau devant intégrer ces sondes ne disposent donc pas de guides pour effectuer la recette de leur efficacité en production.

Cet article propose un retour d’expérience sur l’évaluation des sondes, notamment sous l’angle de la performance. Cet aspect est, en effet, particulièrement significatif puisque le taux de détection d’une sonde diminue si elle est submergée, quand bien même elle serait équipée des meilleurs signatures et moteurs d’analyse.

De la notion de budget

Les différents moteurs d’analyse constituant une sonde consomment des ressources machine. Celles-ci sont en quantité finie et dépendante du matériel sur lequel sont installés les mécanismes de détection et d’analyse. Ces ressources comprennent notamment la capacité de calcul (CPU, FPGA, ASIC) et la mémoire (RAM, mémoire de travail des périphériques…).

Il est généralement possible d’effectuer certains compromis calcul/mémoire afin d’optimiser le traitement. Néanmoins, ces ressources confinent, in fine, au temps nécessaire pour traiter un paquet entrant. La variable non ajustable est, en effet, le débit entrant dans une sonde. Ce débit est exprimé en deux unités : le nombre de paquets par seconde, et le nombre d’octets par seconde.

Le nombre de paquets par seconde est significatif, car il définit le budget temporel disponible pour le traitement des paquets. Un million de paquets par seconde signifient que la sonde dispose d’un millionième de seconde pour le traitement de chaque paquet en moyenne. En outre, le nombre de paquets par seconde a une influence sur le nombre d’interruptions (matérielles ou logicielles) qu’un CPU doit traiter. De la même manière qu’un ingénieur est moins productif s’il est constamment interrompu, un CPU perd du temps à chaque interruption. En conséquence, à l’instar de nombreux équipements, il est aisé de noyer une sonde sous de nombreux paquets représentant un trafic extrêmement modéré en octets par seconde.

Le nombre d’octets par seconde reste cependant significatif. Ce dernier a, en effet, un impact sur les temps de transfert des paquets entre les différents composants de la sonde. Cet impact se matérialise notamment pendant les recopies des paquets, entre composants matériels ou logiciels.

Dès lors qu’une sonde épuise son budget pour le traitement d’un paquet, celui des paquets suivants peut en pâtir. S’il ne s’agit que d’un pic de trafic, il est généralement possible d’absorber celui-ci en lissant son coût sur les millisecondes/secondes suivantes. En effet, certains paquets sont traités plus rapidement que d’autres, comme ceux qui sont immédiatement écartés, car faisant partie d’un flux chiffré dont la sonde n’a pas la clé de déchiffrement. Si le pic d’activité se prolonge, la sonde n’a alors d’autre choix que de défausser du trafic. L’endroit et la manière dont le trafic est défaussé sont déterminés en fonction de la localisation du goulot d’étranglement.

Les goulots d’étranglement

Les paquets reçus peuvent être défaussés par de nombreux composants matériels ou logiciels, dès lors qu’une surconsommation budgétaire survient. Cela peut se produire dès la carte réseau recevant les paquets et ne pouvant pas les diffuser au noyau, ou bien plus tard, quelque part dans le noyau ou dans le logiciel de détection en lui-même.

Pertes par la carte réseau

Les cartes réseau disposent d’une mémoire interne relativement réduite ; il s’agit d’une file d’attente. Chaque paquet entrant dans la carte est inséré dans cette file. Celle-ci est ensuite consommée par un procédé qui transfère les paquets dans la mémoire centrale du serveur. Cela s’effectue par des écritures DMA ou des variantes, telles qu’IOAT/DMA).

Une carte réseau peut saturer sa file d’attente, si elle n’arrive pas à effectuer les écritures DMA aussi rapidement que les paquets arrivent depuis le réseau. Outre de possibles lenteurs matérielles sur les bus de communication en eux-mêmes, la cause principale de lenteur est le filtrage des accès mémoire par l’IOMMU 1. Il s’agit d’un gestionnaire des écritures DMA, capable de limiter les plages mémoires sur lesquelles les périphériques d’un serveur sont en mesure d’écrire, à l’instar d’un pare-feu limitant les accès à un réseau. Sa fonction est cruciale pour la sécurité des serveurs, mais totalement contre-productive si elle résulte en l’incapacité de la sonde à remplir son rôle.

Pertes dans le noyau

Lors de son démarrage, le logiciel de détection fait appel au noyau pour configurer une méthode d’acquisition des paquets. Plusieurs existent, parmi lesquels les plus populaires sont certainement AF_Packet (natif dans Linux), PF_Ring, DPDK, ou encore Netmap.

Généralement, le logiciel de détection configure le noyau afin qu’une plage mémoire soit réservée pour la réception des paquets écrits par DMA.

Plus cette plage mémoire est grande, plus la quantité de paquets qui pourront être stockés en attendant leur traitement est importante. Si toutefois cette plage se remplit plus vite qu’elle n’est consommée par le logiciel de détection, alors des paquets sont défaussés.

La lenteur de la consommation des paquets entrants n’est pas systématiquement à imputer aux lenteurs du logiciel de détection. En effet, le noyau effectue des transformations ou ajoute des métadonnées, qui peuvent être plus ou moins coûteuses. Des pertes peuvent donc se produire avant même que le logiciel de détection ne soit prévenu de la réception de paquets ! Ce cas peut être notamment observé si l’on utilise des programmes XDP très gourmands, ou des algorithmes peu performants de répartition des paquets (load-balancing) entre les différents processeurs.

Une autre cause de pertes de paquets impliquant le noyau est l’extraction de fichiers. Les logiciels de détection peuvent, en effet, stocker les paquets reçus (fichiers PCAP) ou les fichiers suspects transitant sur le réseau (HTTP, SMB, SMTP…). Si les périphériques de stockage ne sont pas suffisamment rapides, les appels système d’opération sur les fichiers (write(2), sync(2)…) pourraient être plus lents à rendre la main au logiciel de détection, et donc dépasser le budget. En conséquence, une perte de paquets est possible dès lors qu’une grande quantité de fichiers doivent être extraits pour mise en quarantaine et analyses ultérieures.

Pertes dues au logiciel de détection

L’organisation des composants constituant le logiciel de détection et la complexité des règles d’analyse peuvent avoir un impact significatif sur les performances, et entraîner la perte de paquets.

Les moteurs d’analyse sont découpés, en interne, en plusieurs sous-tâches :

  • acquérir de nouveaux paquets à traiter ;
  • replacer les paquets dans leur contexte (e.g. « fait-il partie d’une session TCP ? », « est-ce un fragment d’un paquet déjà vu ? ») ;
  • effectuer des analyses de sécurité des paquets ou des flux, afin d’inférer des événements de sécurité ou d’extraire des fichiers suspects ;
  • produire des journaux enregistrant les événements générés.

Ces sous-tâches peuvent être gérées par un ou plusieurs processus. Utiliser plusieurs processus peut être avantageux pour paralléliser les traitements, et ne pas se retrouver avec une surcharge de travail qui pourrait saturer les capacités de traitement d’un unique processus. Hélas, utiliser plusieurs processus n’est pas non plus une panacée, car ces sous-tâches peuvent nécessiter des états partagés. Il est alors nécessaire d’organiser l’accès à ces états, par l’intermédiaire de serveurs mandataires (comme le fait Zeek/Bro) ou de verrous (futex/mutex, comme le fait Suricata).

Une analyse de performance assez poussée du logiciel de détection Suricata a été conduite 2 ; elle montre que les verrous constituent un des freins principaux, pouvant causer la perte de paquets. Dans cette analyse, il est notamment stipulé que Suricata effectue beaucoup d’accès concurrents aux états des sessions TCP.

Ainsi, un trafic réseau comportant une grande quantité de sessions TCP simultanées ou de nombreuses nouvelles connexions par seconde peut avoir pour conséquence le ralentissement de Suricata. En effet, tous les processus ayant pour objectif de remplacer un paquet dans son contexte seront alors figés en l’attente de la libération des verrous pour accéder aux états partagés.

En outre, et sans même parler de verrous, une grande quantité de sessions TCP peut saturer les tables de hachage dans lesquelles sont stockés les états. Or, la complexité algorithmique d’accès aux éléments des tables de hachage passe d’O(1) (temps constant) à O(n) (temps linéaire, fonction de la quantité de collisions dans la table de hachage) lorsque celles-ci saturent. Il en résulte alors une surconsommation CPU, et donc une surconsommation du budget temporel pour le traitement d’un paquet.

L’architecture logicielle des moteurs d’analyse peut également influencer les performances en cas de mauvaise répartition des paquets reçus entre les différents processus en charge de leur traitement. La perte de paquets survient lorsqu’un CPU est saturé/noyé sous les traitements qu’un processus d’analyse doit entreprendre. Ce cas de figure se manifeste très facilement lorsque la répartition des paquets reçus n’est pas aléatoire, mais tend à concentrer sur le même processus d’analyse tous les paquets relatifs à un même flux (ex. : sessions TCP). Cette répartition par flux est la plus commune et privilégiée, car elle permet de limiter les accès aux ressources partagées et d’augmenter la localité des accès mémoire 3. Le problème est que cette méthodologie ne répartit pas correctement le trafic incluant des tunnels (IPsec, GRE, L2TP, TLS…). En effet, à moins que le programme en charge de la répartition ne fasse de l’inspection profonde (DPI) du trafic (qui n’est même pas toujours possible, par exemple en cas de paquets fragmentés), l’intégralité des paquets d’un tunnel sera analysée par un même processus d’analyse ! Si ce tunnel est très actif, le processus d’analyse sera facilement débordé, et des paquets commenceront à être perdus.

Finalement, les moteurs d’analyse (ex. : dissecteurs, analyseurs de contenu, greffons d’analyse) peuvent être des sources de problèmes de performance, résultant en la perte de paquets. Le pare-feu applicatif de Cloudflare a causé une indisponibilité de l’ensemble de leurs services en juillet 2019 4, à cause d’une expression rationnelle gourmande en CPU. De même, une règle de détection mal conçue pourra freiner significativement l’analyse des paquets, et surconsommer le budget.

De l’expérience de l’auteur de cet article, le problème est encore pire avec des greffons écrits en Lua. Ce langage utilise, en effet, exclusivement des co-routines pour simuler le parallélisme. En conséquence, si une instruction Lua met en attente l’interpréteur Lua, sans rendre la main pour que ce dernier exécute une autre co-routine en attendant, l’ensemble des processus d’analyse de paquets ayant recours à un greffon Lua se retrouvent figés 5.

Biais introduits par les méthodologies d’évaluation

Les conditions évoquées dans la précédente section de cet article peuvent se manifester lors de la capture de trafic sur des réseaux de production. Néanmoins, étant donné que les sondes sont des composants généralement connectés à des réseaux sensibles, nombre d’opérateurs préfèrent évaluer ces équipements en émulant de tels réseaux, avant d’en sélectionner un et de le raccorder à leur production. De même, les constructeurs de sondes doivent évaluer leur produit afin de s’assurer de leur performance.

L’émulation d’un réseau n’est cependant pas chose aisée, et de nombreux biais peuvent être introduits, faussant positivement ou négativement la perception des performances réelles des sondes ! Cette section détaille quelques erreurs communes que l’auteur de cet article a pu observer ou commettre dans le cadre de son activité professionnelle.

Les outils pour l’émulation de réseaux

Outre les plateformes commerciales, dont l’efficacité et la pertinence des tests pourraient certainement faire l’objet d’études formelles, plusieurs outils libres existent. Parmi ces derniers, il est notamment judicieux de citer :

  • tcpdump, qui permet la capture de trafic, le filtrage et le stockage dans des fichiers PCAP 6 ;
  • tcpreplay, qui permet de rejouer des PCAP à plus ou moins grande vitesse, et même d’éditer les PCAP 7 ;
  • TRex, de Cisco, qui constitue une plateforme de rejeu de trafic complète [^TRex] ;
  • scapy, une bibliothèque Python dédiée à la manipulation de paquets réseau. Elle permet de capturer du trafic, de l’analyser, de le filtrer et de l’éditer, avant de l’enregistrer sous la forme de fichiers PCAP, ou de renvoyer les paquets sur le réseau 8 ;
  • tc qdisc, un ensemble d’outils sous Linux permettant notamment l’émulation de certaines conditions sur un réseau, comme la limitation de débit avec le module tbf, ou la création de latence ou d’instabilités (pertes de paquets, rejeux…) avec le module netem 9.

Tcpdump

tcpdump permet de capturer et d’enregistrer du trafic sur des réseaux modérément actifs. Lorsque les réseaux sont trop rapides, ce dernier ne parvient pas toujours à collecter tous les paquets reçus. Les flux réseau ainsi enregistrés s’en retrouvent alors corrompus. Quelle que soit la technologie employée pour le rejeu du trafic, il est crucial que les captures réseau employées soient représentatives de la situation que l’on cherche à émuler. En outre, il est normal de souhaiter que le trafic envoyé à la sonde contienne des pertes, des rejeux et des réordonnancements de paquets. Il convient cependant que ceux-ci soient désirés et émulés à dessein, plutôt que le résultat du hasard et d’une méthodologie de capture inadéquate.

Il convient également de noter que la capture de trafic d’un réseau réel peut générer des fichiers PCAP non représentatifs, malgré une source de données bien légitime. En effet, il est absolument capital de nettoyer ces captures, car celles-ci contiennent des demi-flux 10. Ces demi-flux sont des flux qui ont commencé avant le début de la capture ou qui se termineront après la fin de la capture.

Les demi-flux commencés avant le début de la capture sont problématiques si la sonde est configurée pour ignorer de tels flux. En rejouant ces demi-flux, l’évaluateur néophyte pourrait alors avoir l’impression d’envoyer une quantité importante de trafic à la sonde et que cette dernière se comporte parfaitement, sans perdre le moindre paquet. En réalité, la sonde n’effectuera aucune analyse des paquets reçus et les défaussera, sans lever la moindre alerte, même en présence d’un trafic malveillant.

Les demi-flux ne se terminant pas pendant la capture sont également problématiques si la capture est relativement courte, et rejouée en boucle, par exemple avec tcpreplay. En effet, ces flux ne se terminant jamais, ils vont créer à chaque itération de nouveaux états à maintenir dans la sonde, pouvant ainsi causer une explosion en coût mémoire, et une saturation de différentes tables de hachage internes. Or, si les logiciels de détection sont optimisés pour ne pas s’écrouler face à des DDoS de type SYN Flood, une explosion du nombre de flux tombe dans le spectre des attaques logiques. Les sondes n’ont alors d’autres choix, pour ne pas s’écrouler, que de défausser arbitrairement des flux, parmi lesquels des flux potentiellement malveillants. Pour ce faire, des délais de grâce (timeout) agressifs sont employés.

Tcpreplay

tcpreplay permet de rejouer des PCAP contenant des flux de toute nature et peut être un outil efficace pour évaluer une sonde. Des biais peuvent cependant être introduits dès lors que le PCAP est rejoué en boucle à l’aide de l’option --loop.

Le premier biais constaté par l’auteur de cet article survient si la périodicité des rejeux en boucle est inférieure à la valeur du délai de grâce (timeout) CLOSE_WAIT configuré dans la sonde. Dans l’absolu, CLOSE_WAIT est un état de la machine à états du protocole TCP, qui est indépendant des paquets reçus, et qui évolue seulement après un certain délai. Son objectif est d’empêcher qu’un serveur croie à l’établissement d’une nouvelle connexion TCP à cause de paquets réseau dupliqués trouvant leurs chemins après la fermeture de la session originale. Les sondes devant émuler les piles TCP des serveurs qu’elles protègent, elles doivent avoir un délai de grâce pour l’état CLOSE_WAIT représentatif de ces serveurs. Or, si tcpreplay rejoue en boucle « trop rapidement » (relativement au délai de grâce) le même PCAP, alors le trafic sera partiellement ignoré par la sonde, comme il l’aurait été par le serveur auquel s’adressait le trafic original, en vertu des spécifications du protocole TCP ! Il en résulte une sonde donnant l’impression de traiter énormément de paquets, alors qu’en pratique, elle les ignore.

Pour éviter le biais précédent, il est possible d’utiliser l’option --unique-ip de tcpreplay qui fait varier les adresses IP à chaque nouvelle itération d’un PCAP. Hélas, cette option conduit au second biais !

Ce second biais est une amusante et improbable coïncidence. Il existe, en effet, une interaction entre l’algorithme utilisé par --unique-ip et certaines méthodes de hachage des paquets en vue d’effectuer la répartition des paquets entre les processus d’analyse !

Les méthodes de hachage des paquets pour répartir les flux nécessitent une propriété assez inhabituelle. En effet, il est nécessaire de hacher vers le même processus d’analyse, tant les requêtes que les réponses d’un même flux. Il faut donc utiliser un algorithme dit symétrique, qui hachera les adresses IP de manière identique même si les adresses IP source et destination sont inversées. Or, certains mécanismes de répartition, comme celui de la méthode de capture des paquets PF_Ring, utilisent une simple addition modulaire des octets des adresses IP. Ainsi, un paquet allant de 192.168.0.1 à 192.168.0.2 donnera un haché égal à $192+168+1+192+168+2 = 723 modulo N$.

De son côté, l’implémentation de --unique-ip dans tcpreplay se contente de soustraire le nombre d’itérations du PCAP à une adresse IP, et d’ajouter le nombre d’itérations du PCAP à l’autre adresse IP. Or il s‘agit d’une opération mathématique à somme nulle qui conduira donc l’algorithme de répartition des paquets de la sonde à toujours envoyer les paquets vers les mêmes processus d’analyse. Si le PCAP est suffisamment court, alors la sonde se trouvera submergée artificiellement au niveau de certains processus, tandis que tous les autres ne recevront pratiquement aucun flux !

TRex

TRex est une plateforme développée par Cisco permettant le rejeu d’une gamme de PCAP. Chaque PCAP ne doit contenir qu’un seul flux. La configuration de cette plateforme permet ensuite de spécifier la fréquence relative de chaque PCAP par rapport aux autres. Il est alors possible d’envoyer plus ou moins de flux, en sachant que la quantité et la nature des flux envoyés sont maîtrisées.

TRex évite les biais introduits par tcpreplay, en faisant varier les adresses IP de manière aléatoire à chaque nouvel envoi d’un flux. En outre, pour l’expédition des flux, il envoie les paquets d’une adresse A vers une adresse B sur une interface réseau, et les paquets retour, de B vers A sur une autre interface réseau. Cela résulte en une méthode d’acquisition des flux par la sonde qui est plus réaliste, car plus proche de la méthode d’acquisition des flux sur une fibre optique.

La seule ombre au tableau de TRex est sa complexité ; il est, en effet, aisé d’envoyer à une sonde du trafic dépassant l’une de ses spécifications, soit en nombre de paquets par seconde, de nouveaux flux par seconde, de nombre de flux totaux, de fichiers à extraire, ou autre.

Scapy

Scapy est un outil probablement indispensable pour les évaluateurs de sonde. Il leur permet, en effet, de retravailler un fichier PCAP, notamment pour y nettoyer les demi-flux, altérer les flux pour dupliquer des paquets ou en supprimer, corrompre sciemment des sommes de contrôle. Son seul véritable défaut est sa relative lenteur, due principalement à son modèle d’abstraction des paquets, et au langage Python. Il est donc peu pratique d’opérer sur des PCAP de plusieurs gigaoctets.

Tc qdisc

tc qdisc (traffic control – queue discipline) est un cadriciel reposant sur le noyau Linux et des outils de l’espace utilisateur (userland) pour altérer l’écoulement des paquets sur des interfaces réseau spécifiques. Cet outil est notamment utile lorsqu’un évaluateur cherche à créer des PCAP pour TRex. En effet, il est possible de créer un environnement contrôlé, par exemple avec une paire d’interfaces virtuelles (veth). L’une des interfaces fait alors tourner le serveur et l’autre accueille le client. tc permet d’altérer cet environnement de tests pour y introduire des perturbations volontaires (ex. : délais, pertes, réduction de débit…).

Biais introduits par l’injection de flux non représentatifs

Le comportement d’une sonde peut varier significativement en fonction du trafic reçu. Leurs logiciels de détection doivent, en effet, être en mesure de s’adapter à tout type de trafic susceptible d’être reçu par les équipements qu’elles protègent. Or le traitement d’un grand nombre de petits paquets, ou à l’inverse le traitement de jumbo frames (des trames dont la taille excède les classiques 1514 octets) demande des allocations mémoire contradictoires, ne serait-ce que pour stocker les paquets en attendant leur traitement. De même, de nombreux flux distincts ne se gèrent pas de la même manière que quelques flux bien connus, mais massifs.

Or, une sonde, par défaut, doit savoir gérer toutes ces situations. Leur configuration doit donc être suffisamment générique pour accorder au logiciel la flexibilité nécessaire pour les encaisser. Il en résulte une allocation des ressources potentiellement inadéquates pour des cas extrêmes, comme le traitement d’un trafic réseau à très haut débit. Pire, ces configurations génériques ont tendance à « surbooker » les ressources à disposition. L’hypothèse optimiste est, en effet, que plusieurs situations extrêmes ne se présenteront pas simultanément. Les ressources de la machine étant en quantité finie, il peut alors en résulter des dénis de service du logiciel de détection (ex. : déclenchement de l’OOM Killer de Linux, qui tue les processus consommant beaucoup de mémoire).

Finalement, la nature des flux injectés peut également influencer le comportement de la sonde. Une grande quantité de flux chiffrés est, en général, facile à gérer pour une sonde. Cette dernière n’a, en effet, pas accès aux clés de déchiffrement ; le flux peut donc généralement être ignoré, pour privilégier l’analyse de paquets en clair. À l’inverse, une grande quantité de flux distincts (ex. : sessions TCP ou questions/réponses sur UDP…) peuvent faire exploser les états dans la sonde, comme cela a été détaillé plus haut dans cet article.

Conclusion

Au fil de cet article ont été présentés différents :

  • goulots d’étranglement d’une sonde ;
  • ressources critiques ;
  • sources de lenteur ;
  • biais pouvant être introduits involontairement lors de l’évaluation.

À moins d’avoir développé une expertise notable dans l’intégration de ce genre d’équipements, il est donc nécessaire de se référer à des guides de déploiement, et des méthodologies de tests éprouvées et génériques. Hélas, de tels documents n’existent pas encore, et les ingénieurs doivent réinventer la roue systématiquement, quitte à en produire des carrées, de temps à autre.

Dans le monde des systèmes industriels, souvent considéré par la communauté de la sécurité des systèmes d’information IT comme le vilain petit canard, ce problème a pourtant déjà été résolu ! La certification ANSI/ISA 62443 et le programme ISA-Secure 11 spécifient une méthodologie d’évaluation très précise des systèmes industriels, et des équipements pouvant automatiser ces tests. Les exigences sont donc clairement établies, les méthodologies de tests documentées, et les produits d’évaluation certifiés. Ces tests incluent la conformité, la robustesse au trafic anormal, et la robustesse contre la montée en charge.

Ces éléments manquent cruellement dans le monde des sondes de détection, dont la réaction peut varier significativement, comme décrit dans cet article, en fonction du trafic reçu, de la nature de ses flux et de son intensité.

Remerciements

Je tiens à remercier mes relecteurs : Erwan Abgrall, Baptiste Bone, Piotr Chmielnicky, Sebastien Larinier, ainsi que ceux qui ont souhaité rester anonymes, et les employés de Gatewatcher. Les avis exprimés dans cet article ne sauraient les engager.

Références

Publié par les Editions Diamond sous licence CC-BY-NC-ND.


  1. Neugebauer et alii., « Understanding PCIe performance for end host networking », août 2018 ↩︎

  2. Étude sur l’incidence des verrous dans Suricata : https://xbu.me/article/performance-characterization-of-suricata-thread-models/ ↩︎

  3. Document sur l’amélioration des performances d’acquisition de Suricata : https://github.com/pevma/SEPTun ↩︎

  4. Rapport d’incident de Cloudflare impliquant leur pare-feu applicatif web : https://blog.cloudflare.com/cloudflare-outage/ ↩︎

  5. Exemples cassant le modèle de threads collaboratifs de Lua : https://stackoverflow.com/a/18964444 ↩︎

  6. Site de l’outil Tcpdump : https://www.tcpdump.org/ ↩︎

  7. Site de l’outil Tcpreplay : https://tcpreplay.appneta.com/ ↩︎

  8. Dépôt de l’outil Scapy : https://github.com/secdev/scapy ↩︎

  9. Documentation sur l’émulation d’incidents réseau avec Traffic Control : https://wiki.linuxfoundation.org/networking/netem#packet_duplication ↩︎

  10. Script permettant de nettoyer les demi-flux : https://frama.link/RfNczV0d ↩︎

  11. Site de la certification ISA Secure : https://www.isasecure.org/en-US/ ↩︎

Python String Emptiness Test

Security specialists have this tendency to focus on the most mundane things, and overthink them to the point where they may actually find something interesting to say about them.

Is that a useful use of their time? That question is open to debate ;p

But I believe writing about them IS a useful use of my time on a gray Sunday morning!

Python String Emptiness Test

A while back, I entered a lengthy debate about condition expressions in Python with one of my colleagues during a merge conflict. We both wrote a utility function expressing the exact same condition, but we had written it in a different way.

He wrote this:

def should_i_do_smth():
    # ...
    return bool(some_string) and some_int == 0

I wrote that:

def should_i_do_smth():
    # ...
    return len(some_string) != 0 and some_int == 0

The only use case of that function was in an if condition:

if should_i_do_smth():

Whose code was merged is not really relevant, but I decided to create a Twitter poll to probe my followers on the topic of writing emptiness tests of Python strings.

The poll was:

According to you, which of the four following lines of #Python code (poll) is the most self-explanatory and the safest to express that the string variable “value” is not empty? All answers are valid Python.

  • if value:
  • if bool(value):
  • if len(value) != 0:
  • if value != '':

Regarding the poll itself

The wording of the poll is vague on purpose. Depending on the reader, some of the words have different meanings. That was a deliberate choice. It is very hard to express formal things in a natural language. So, even if you have clear instructions, and documentation, and code comments, in the end, what really matters is what was on the mind of the dev when they wrote that line of code.

People who answered the poll may have read differently:

  • Safest: did I mean that the code must be robust (i.e. not crash) or secure (i.e. act consistently and fail during static analysis)?

  • String variable: did I mean str or Optional[str], only Unicode string ('') or also bytestring (b'')? Was there a test to control the type? Or static typing analysis?

  • Not empty: did I mean that we should refuse the empty string only, or should we also refuse None?

  • Self-explanatory: did I mean that the code should be readable by Python developers abiding to PEP8 and the Zen, or should the code be readable by most people, including security auditors or junior developers that may not be knowledgeable of PEP8 best current practices. Is readable equivalent to explicit and unambiguous?

Of course, the poll results are heavily biased. Most of my followers are security specialists, not software engineers, and certainly not full-time Python developers.

At any rate, I find the results quite interesting, because a majority of people did NOT follow the PEP-8 recommendation when asked this question.

At the time of writing, with 54 voters, the poll results is:

  • if value: 38%
  • if bool(value): 4%
  • if len(value) != 0: 34%
  • if value != '': 24%

Answer analysis

Each of the poll answers is valid Python, but they all also have merits.

First Answer

if value: might be readable by most full-time Python developers because it is the Python way, recommended by PEP-8. It works because the empty string '' is evaluated to False in the context of a condition expression.

To some extent, it is comparable to the following C code :

char * value;
... instructions ...
if (value && *value) {

This code plays on the fact that a NULL pointer values 0, which is evaluated to False in C. It also plays on the fact that if the string is empty, the first character will be the NULL byte (\0), which is also evaluated to False. This type of syntax requires your reader to be knowledgeable about the language. Thus, if they are, it is very readable. If they are not, then the jury is out.

But the real issue of this syntax is that there is absolutely no type checking whatsoever. That’s not really a problem if you embrace Python’s duck typing and you are well prepared for the consequences of that choice. If you only consider the poll question as it is formulated, and the code is properly guarded so that you are certain that the value variable is a Unicode string, this approach bares no risks.

But what if I lied and the value variable is not a string? What if it is a bytestring? The None value? An integer? An arbitrary object? What if the code is not properly guarded?

I mean, this can happen easily when you refactor your code or when you meddle with some code you don’t fully understand. Sure, unit tests and static analysis are valid answers to refactoring problems… but let’s be honest here: correctly written unit tests are not frequent in the startup industry.

And mistakes happen. One of my followers told me a “war story”:

if i:

Yeah, that’s it ^_^ A colleague of them wrote this test to guard against the None value… but i was an integer. And some day, that integer equaled 0. If you don’t know, 0, in Python, is evaluated as False in a condition expression. Oops.

But let’s say that this integer war story is a corner case. What would happen if the value variable was in fact an instance of a type implementing __bool__ or __len__?

In Python, truth evaluation on arbitrary object is done by trying to call __bool__ that should return the truth value for this object. If __bool__ is not implemented, __len__ is tried. If __len__ returns 0, then the evaluation result is False, else True. Finally, if __len__ is not implemented, then it returns True for variable that are not None nor a scalar that evaluates to None.

class Test:
    def __bool__(self):
        print('>>Bool!')
        return True

value = Test()
if value():
    print('>>Hey!')
>>Bool!
>>Hey!

class Test:
    def __len__(self):
        print('>>Len!')
        return 1

value = Test()
if value:
    print('>>Hey!')
>>Len!
>>Hey!

class Test:
    def __len__(self):
        print('>>Len!')
        return 0

value = Test()
if value():
    print('>>Hey!')
>>Len!

class Test: pass

value = Test()
if value:
    print('>>Hey!')
>>Hey!

With such a high risk of confusion on the actual type of the object, I would personally bet that there is a very high probability of having some unstable code that will assume something about what the value variable is capable of, resulting in the infamous AttributeError: 'Foo' object has no attribute 'bar'. Or worse: no crash and a very stupid result.

You understood it, this all boils down to the discussion about typing, and the fact that the more checks (notably typing checks) are done statically, the more robust the code. And that is a fact that many languages have caught on. PHP, Python, Javascript, Perl, almost all interpreted languages (with the exception of Ruby 😂) have adopted a type hinting syntax to help static analyzers verify the code sanity. In Python, PEP-484 defines the syntax and you can use MyPy to do the checking.

So, if you hinted that the type of value was str before the if value: statement, then your code is probably safe and robust if you use a static analyzer.

def foo(value: str):

If you do not have a type hint and you don’t use a static analyzer, then your code is not readable because your intention about what is acceptable is not explicit. Thus, and your code is not robust/safe because you will probably end up crashing.

Second Answer

The second answer is nonsensical and I admittedly did a poor job at representing the opinion of my colleague when writing this poll. Let’s put it on the fact that I was forced to use their solution.

if bool(value): is stupid because we already are in the context of a boolean evaluation, so the bool casting is redundant. However, their opinion is not without ground in other contexts.

For instance, in the following code, what would you replace XXX with?

def foo() -> Tuple[str, int]:
    """some instructions"""
    # ...
 
def bar() -> XXX:
    s, i = foo()
    return s and i

If you answered bool, you are wrong. XXX must be replaced by Union[str, int].

error: Incompatible return value type (got "Union[str, int]", expected "bool")

That’s because Python logical operators do not return booleans! In the case of the and operator, it returns the first value that cannot be evaluated to True.

Thus, if you meant the bar function to return a boolean, you need to cast the whole expression as bool before returning it.

def bar() -> bool:
    s, i = foo()
    return bool(s and i)

You can also only cast elements that are not comparisons, because, at least, comparisons do return booleans:

def bar() -> bool:
    s, i = foo
    return bool(s) and i != 0

The fact that Python logical operators return arbitrary values is very surprising to people that come from some other languages, such as C or even PHP, where the logical operators return a truth value. For people coming from very strongly typed languages such as Ocaml or Rust, this is difficult to even consider, because logical operators are typed and would only accept booleans as operands in the first place.

$ echo '''#include <stdio.h>

int main(){
  printf("> %d\n", 2 && 3);
  return 0;
}''' | gcc -o /tmp/condition -x c -

$ /tmp/condition
>1

$ php -r 'echo 2 && 3;'
1

Once you consider that you need to explicitly cast to bool all of your values in a logical expression to output a boolean, the readability and robustness/safety arguments are identical to those of the first answer.

Third Answer

The third answer is the first that is not relying on the Python language specification to express a condition. It explicitly states which particular characteristic of the content of the value variable is studied and must not be equal to 0 and it returns an unambiguous result: a truth value: True or False.

Regarding code safety, the result is mixed. It is the only answer out of the four that will crash the program during runtime if value is the None value.

TypeError: object of type 'NoneType' has no len()

Depending on the purpose of the program, crashing early may or may not be desirable. A ex-colleague working on machine learning told me that they would prefer to have a program crash early because of a type bug like this, than to have the program run for hours only to crash later with a AttributeError: 'NoneType' object has no attribute 'foo'.

Of course, the best option is to test the program, and check the parameters against the API contract so that this situation never occurs. But what if the test is broken (for instance, because it was written with the syntax from the first answer) and it let through a value that was not intended?

Unfortunately, this answer is also susceptible to cause late crashes because of duck typing. The len() function is only a keyword that calls on the __len__ implementation of the receiver (that is the object provided as len()’s argument. This means that this test won’t guard against objects implementing __len__, just like str, but not being a string. The perfect builtin example would be the bytestring.

value = b'bonjour'
if len(value) != 0:
    l = a.split('o')
TypeError: a bytes-like object is required, not 'str'

All in all, this answer is relatively explicit in what is tested and what’s the intended result. But even if an early crash might be desirable, a crash is not certain because duck typing will let invalid objects go through.

Fourth Answer

The fourth answer is pretty straightforward. The meaning is crystal clear: it evaluates to True as long as value is not the empty Unicode string. Anybody gifted with eyes can read this expression and understand what is the intent of the author.

It won’t be abused by the empty bytestring. It won’t be abused by the None value. It won’t be abused by objects implementing __str__.

class Test:
    def __str__(self) -> str:
        return ""

value = Test()
if value != "":
    print("Foo")
Foo

Wait, what? It printed Foo?! Oh, yeah. Right. All objects of a different type than str, and even objects of type str if they are not the empty string will make this condition evaluate to True. They are not equal to the empty string. That is exactly what is expressed by the condition.

If what you really mean is that the value must be a string and not the empty string, then, you need to write an even more explicit version of this:

if isinstance(value, str) and value != "":

(note: using isinstance() is prefered to type(value) is str just in case someone got the extra-weird idea to subclass str; don’t do that. Unfortunately, type(value) is str would have been so much more readable)

A Word About Efficiency

To my very own surprise, there is a significant difference of performance between the four answers. The slowest take twice as much time as the fastest (2.19 times more, to be precise).

It is in the realm of micro-optimizations but since the difference is so large, I think the result is worth including in this post.

For 10 million iterations, run 100 times to clear out statistical noise, the average results are:

Answer Time Ratio
First 1.28s 1
Second 2.81s 2.19
Third 1.92s 1.5
Fourth 1.52s 1.19

Conclusion

As I stated in the poll itself, all four of the answers are totally valid Python code. However some answers will make full-time Python developers abiding by the PEP-8 recommendations cringe. Some even implemented tools that would whine specifically on one of the answers. That’s the case of the third answer that will make pylint, a Python code linter, complain about the use of len() to test if an sequence is empty (because a str is also an character sequence):

Do not use `len(SEQUENCE)` to determine if a sequence is empty (len-as-condition)

We also saw during the discussion about the advantages and drawbacks of the first answer that if one makes a proper use of type hinting and static code analysis (e.g. mypy), there may be little code safety problems with it; just a readability issue because the intent of the developers about which use cases are covered remains obscure.

Overall, my personal belief is that the fourth answer (especially when guarded with the isinstance() call) should be prefered because the developer’s intent is explicit and one gets exactly what they asked for, without any of the magic offered by the language.


Please post your comments as answers on Twitter or on the Fediverse!

A PKI Rant: the Free (as in free beer) Certificate Problem

Intro

Someone asked me what I had to object to this article about free certificates versus paying ones.

The competing interests problem

First of all, I agree that many CAs (Certificate Authorities) are overselling their certificates, granting them properties or responsibilities that are not factual or even accurate on the technical level. The examples provided in the article are excellent. Where my opinion starts to diverge is near the conclusion. Most people will say that the following is pure FUD, and they would not be absolutely wrong. I have nothing to prove my statements; these are hypotheses, and things to look out for. Truth is I don’t feel like I am not FUDing, or I would not speak up. I think I am just being extra precautious.

First, I find amusing that many people like to quote “if that is free, then you are the product”, but when it comes to Let’s Encrypt, they forget this statement and enjoy their certificates carelessly. So, you might ask: “How am I a product, when I am a client of Let’s Encrypt? They are not selling my information, and even if they were, all they have on me and my website are public data”. True. Your information is not a good for Let’s Encrypt, as far as I know. What you are, however, is a wallet, who is no longer opening to give money to any CAs. You see, operating a CA is not free, nor even cheap (especially when you consider that Let’s Encrypt staffing budget was a whooping $2.06M for 10 people in 2017 ). So if you get your certificates for free, someone is paying for them. Let’s see, “platinum sponsors” (over $300K annually):

  • EFF: OK.
  • OVH: they make a heavy usage of Let’s Encrypt for their shared hosting; OK.
  • Cisco and Akamai: hmm, OK.
  • Mozilla and Chrome? Uh-oh.

You see, if Let’s Encrypt is giving certificates for free, other CAs won’t sell any, because people know that there is no difference between a paying DV certificate and a Let’s encrypt DV certificate (or now, they know, thanks to the aforementioned article). Since browsers are increasingly lowering the value of EV certificates, people have less and less incentive to pay for them. (Did you notice there is no longer any green bar (or indicator for that matter) in Chrome?) Thus, people won’t buy DV or EV certificates from commercial CAs. What will happen to them? They will either shut down their business or become increasingly less secure, because of the lack of funding. Good riddance will say those that consider they have been swindled enough by these CAs. But what the sponsors of Let’s Encrypt are doing, really, is leading a war of attrition on commercial CAs by sponsoring an organization that is losing money with each emitted certificate. That’s called unfair competition and that is the road to monopolies, too-big-to-fail entities, and single point of failure. That is also the road to an entity whose main sponsors are consumers of the product, and who may have competing interests.

What do you think will happen if, say, Google requires drastic changes in CA policies at the CA/B Forum and the main CA is also dependent on Google’s funding to exist and operate properly?

The Certificate Transparency problem

Also, you may consider that free certificates are a bane because people act more carelessly with what is literally worthless, than if they had paid $1 for it. Did you ever come across people who are registering certificates during their boot-up procedures and throw them away during the shutdown procedure (docker containers, hello!)? Well, these certificates are ephemeral only if you consider the registrant.

You see, Let’s Encrypt is not all bad; they have implemented ACME, and they started registering all their certificates to Certificate Transparency (CT) logs long before April 2018, when it became required by some browsers. For those not familiar with CT, it is a collection of append-only logs where certificates emitted by (“public”) CAs are registered, for them to be publicly auditable. The important word in the previous sentence is “append-only”. That means that the so-called ephemeral certificates are logged forever in these CT logs. This causes massive scaling issues on the CT ecosystem, because log operation requires a lot of memory and the CT logs are literally spammed with free certificates. This, in turn, causes CT log sharding (certificates are logged into different CT logs based on some criteria), which increases the difficulty for website owners to monitor these logs and use them properly.

Conclusion

If DV certificate price was low but non-null, commercial CAs would still be able to exist, and Let’s Encrypt would be less dependent on their sponsor and less influenced by their agenda and pressures. So I dare say that free certificates are actively harming the web PKI.

This content was originally posted by myself on https://fediverse.blog/~/InfiniteTypingPlatypuses/a-pki-rant-the-free-as-in-beer-certificate-problem.

SMTP : la « killer app » de DNSSEC

Huit ans après le déploiement de DNSSEC par la racine du DNS, cette technologie peine encore à trouver son public et à prouver son utilité. Cet article démontre que la sécurité des échanges de courriers électroniques avec SMTP contre des attaquants actifs ne peut être atteinte en l’absence de DNSSEC, compte tenu des standards et implémentations actuels.

DNSSEC assure l’intégrité cryptographique des enregistrements DNS. Sa faible adoption peut s’expliquer par une complexité à l’implémentation et lors de sa maintenance, et par le fait que cette technologie est inutile, la plupart du temps. En effet, le DNS est principalement utilisé pour la résolution de noms de domaine en adresses IP, en vue d’accéder à un service tiers. Si ce service est authentifié et protégé en confidentialité et en intégrité, comme c’est le cas avec TLS, alors l’attaque active est contrée au moment de l’établissement de cette communication sécurisée. À l’inverse, protéger en intégrité le DNS alors que le service contacté n’est pas lui-même authentifié semble au mieux inutile : l’attaquant actif pourra généralement attaquer le service directement.

SMTP, le protocole d’échange de courriers électroniques se trouve, hélas, dans le second cas de figure, bien que la plupart des implémentations prennent en charge TLS. En effet, pour des raisons historiques et de déploiements progressifs transparents, les serveurs de courriers électroniques ne vérifient pas ou mal les certificats X.509 fournis dans le cadre de SMTP sur TLS. Ainsi, les communications entre serveurs de courriers électroniques ne bénéficient généralement que d’une protection contre les écoutes passives ; un attaquant actif pourra effectuer une interception aisément, sans même avoir à fournir un certificat frauduleux usurpant l’identité de la victime.

Les attaques actives ne se limitent cependant pas au protocole SMTP, mais s’étendent à son écosystème. En effet, les serveurs de courriers emploient de nombreuses techniques pour éviter l’usurpation d’identité de l’expéditeur d’un courrier électronique, dont des politiques de sécurité publiées dans le DNS.

Cet article expose l’impossibilité de sécuriser les échanges SMTP en l’absence d’intégrité cryptographique des enregistrements DNS, que ce soit pour récupérer les politiques de sécurité évoquées ci-dessus, ou pour effectuer une vérification de certificats efficace.

1. État des lieux

Cette section dresse un état des lieux du déploiement des technologies utilisées dans l’écosystème SMTP et qui peuvent être sécurisées grâce à DNSSEC. Des mesures actives ont été effectuées par l’auteur de cet article en vue de présenter au lecteur une image dénombrée. L’outil de mesures, la méthodologie, ainsi que les résultats bruts peuvent être consultés en ligne 1.

1.1. TLS pour SMTP

Dans le précédent numéro de MISC, Arthur Provost et Olivier Levillain présentaient les résultats de mesures actives sur les serveurs SMTP afin d’évaluer la qualité des déploiements de TLS. Leur étude permet d’obtenir une estimation intéressante de la sensibilisation des administrateurs de serveurs de courriers électroniques aux bonnes pratiques de sécurité. Elle ne permet, cependant, pas d’évaluer la quantité de courriers électroniques ainsi protégés, car elle comptabilise les serveurs et non les messages envoyés entre ces serveurs. Or, le trafic des courriers électroniques est extrêmement concentré sur quelques plateformes d’hébergement mutualisé 2.

Cette concentration implique que la sécurisation de quelques acteurs permet de protéger un grand pourcentage des communications. Ainsi, plusieurs initiatives nationales et internationales ont été lancées, afin d’encourager l’adoption de TLS pour sécuriser les échanges entre les grands fournisseurs de service de transport de courriers électroniques, au nombre desquelles celle de Google, de l’ANSSI ou encore du BSI, l’agence nationale de sécurité des systèmes d’information allemande.

À ce titre, Google publie des statistiques publiques sur l’utilisation de TLS entre ses serveurs SMTP et les serveurs SMTP des organismes avec lesquels ils échangent [“SaferEmail]. Il y est notamment possible d’observer le pourcentage de courriers envoyés sur un canal chiffré, par domaine expéditeur/destinataire.

L’ANSSI a également rédigé une charte 3, en collaboration avec plusieurs fournisseurs de service français, afin d’ériger des engagements de sécurité minimaux devant être mis en œuvre par les signataires (Orange, SFR/Numéricable, Bouygues Télécom, Free et La Poste).

Finalement, le BSI a publié un document 4 fournissant des recommandations de sécurité pour les fournisseurs de service de courriers électroniques allemand s’étant autosaisis de la problématique. Il est intéressant de noter que le BSI encourage l’emploi de DNSSEC dans son document.

1.2. DNSSEC

L’auteur de cet article décrivait dans ces mêmes colonnes, en 2012, trois mécanismes employant DNSSEC afin de venir au secours de la validation des certificats X.509 : DANE 5, CAA 6 et un mécanisme non standard d’épinglage des certificats par l’entremise de DNSSEC. Six ans plus tard, force est de constater que ces mécanismes sont peu implémentés 7 8. Et pour cause : DNSSEC peine à se généraliser, avec un taux d’adoption autour de 12,5% des noms de domaine se terminant en « .fr. », dont la majorité sont signés automatiquement par les bureaux d’enregistrement dans le cadre de la création de nouveaux noms de domaine 2.

Du côté des autorités de certification, la prise en charge de DNSSEC n’est pas obligatoire, même pour les autorités de certification émettant des certificats où seul le contrôle temporaire d’un nom de domaine est validé (certificats dits « DV », pour « Domain Validation »). En fait, la seule mention de DNSSEC dans les prérequis minimaux édictés par le CA/B Forum – une entité réunissant les autorités de certification et les principaux navigateurs web – a trait au comportement à adopter dans le cas d’un échec de vérification d’une signature DNSSEC dans le cadre de CAA 9.

Certaines autorités de certification, comme Let’s Encrypt, implémentent cependant la validation DNSSEC de leur propre chef pour l’émission de certificats DV ; un fait à porter à leur crédit.

1.3. SPF

SPF 10 est une politique de sécurité permettant à un émetteur de courriers électroniques de spécifier la liste des serveurs/adresses IP autorisés à envoyer des courriers provenant de son nom de domaine. Cette politique est publiée sous la forme d’un enregistrement DNS de type TXT à l’apex (c’est-à-dire « tout en haut ») de la zone DNS correspondant au domaine DNS expéditeur à protéger. Par exemple, pour l’expéditeur john@example.com, l’enregistrement SPF suivant sera consulté :

example.com. 86400 IN TXT “v=spf1 ip4:192.0.2.1 -all”

Cette donnée est directement consommée par un validateur SPF et aucun autre mécanisme de sécurité n’intervient ultérieurement pour la protéger, comme c’est le cas avec TLS pour les courriers électroniques. Les enregistrements SPF mériteraient donc d’être protégés en intégrité grâce à DNSSEC. La RFC7208 n’oblige cependant pas la signature ou la validation cryptographique de cet enregistrement DNS, permettant ainsi à un attaquant actif de modifier cet enregistrement à la volée et autoriser des adresses IP sous son contrôle à émettre des courriers.

Le déploiement de SPF pour les domaines délégués depuis le nom de domaine de premier niveau (en anglais, TLD) « .fr » est d’environ 37%. Cependant, seuls 7,4% des zones étudiées contiennent des enregistrements SPF signés avec DNSSEC.

1.4. DKIM

DKIM Signatures 11 est une politique de sécurité permettant à un émetteur de courriers électroniques de signer cryptographiquement certains en-têtes et tout ou partie du contenu des courriers provenant de son domaine. Cette technologie vise ainsi à prévenir l’usurpation d’identité de l’expéditeur et permet la détection en cas d’altération des courriers pendant leur transit.

La signature DKIM est placée dans les en-têtes d’un courrier électronique. En voici un exemple :

DKIM-Signature: d=example.net; s=chaine_arbitraire; …

La clé publique utilisée pour effectuer la vérification de cette signature est publiée dans le DNS, dans un enregistrement TXT. Cet enregistrement est publié dans un nom de domaine composé du domaine spécifié dans la métadonnée d= de la signature, préfixée de la chaîne constante _domainkey, elle-même préfixée d’un sélecteur (une chaîne de caractères arbitraire, spécifiée dans la métadonnée s= de la signature). Ainsi pour la signature donnée en exemple ci-dessus, l’enregistrement DNS suivant est récupéré :

chaine_arbitraire._domainkey.example.net. 86400 IN TXT “v=DKIM1; k=rsa; p=base64clef”

Bien que la RFC6376 ne requière pas l’authentification cryptographique de la clé publique servant à vérifier la signature des courriers électroniques, DNSSEC permet de « certifier » cette clé, la protégeant ainsi d’attaquants actifs.

Le déploiement de DKIM ne peut être mesuré avec précision, les sélecteurs étant imprédictibles par l’outil de mesure. Il est cependant possible d’inférer l’absence d’enregistrements relatifs à DKIM grâce à la RFC8020 12. Celle-ci dicte que le DNS est une base de données arborescente, et donc qu’un domaine ne peut exister que si tous les domaines parents existent aussi. Ainsi, il est possible de déterminer un pourcentage de domaines n’utilisant pas DKIM, en comptant les domaines pour lesquels le sous-domaine _domainkey n’existe pas. Les autres domaines utilisent peut-être DKIM ou sont des faux positifs.

Pour les domaines délégués depuis le TLD « .fr », 81% des domaines n’emploient pas DKIM. Seul 1% des domaines étudiés sont susceptibles d’utiliser DKIM et sont signés avec DNSSEC. Ces 1% constituent la borne haute du nombre de noms de domaine utilisant DKIM avec une protection contre les attaquants actifs.

1.5. DMARC

DMARC 13 est une politique de sécurité publiée dans le DNS, permettant de spécifier des actions à prendre en cas de violation des politiques SPF et DKIM. Cette politique est publiée dans un enregistrement TXT localisé dans le sous-domaine _dmarc du domaine de l’expéditeur d’un courrier, dont voici un exemple :

_dmarc.example.net. 86400 IN TXT “v=DMARC1; p=none; pct=100; ruf=mailto:dmarc-feedback@example.com"

Des exemples d’actions à prendre en cas de violation de SPF et DKIM incluent de défausser les courriers jugés frauduleux, de les mettre en quarantaine, et éventuellement de rapporter cet échec auprès d’un serveur. De manière cruciale, ces rapports peuvent contenir des extraits de courriers électroniques. Pour un domaine n’étant pas protégé par DNSSEC, un attaquant est donc en mesure de modifier les enregistrements DKIM, de façon à faire passer un courrier électronique pour frauduleux, puis de retourner un faux enregistrement DMARC permettant l’exfiltration d’informations du courrier.

Le déploiement de DMARC est très faible, avec seulement 1,4% des noms de domaine délégués depuis le TLD « .fr » l’implémentant. Seuls les enregistrements de 1,5 domaine pour mille sont, en outre, protégés par DNSSEC. Finalement, comme noté dans la section 1.2, seuls 12,5% des domaines étudiés sont signés avec DNSSEC et sont donc à l’abri de toute attaque active impliquant DMARC en vue d’exfiltrer le contenu des courriers électroniques.

2. Modélisation d’un attaquant actif

Dans cette section, nous allons exposer une liste non exhaustive des possibilités d’un attaquant actif à l’encontre de SMTP sur TLS, en vue de casser la confidentialité des métadonnées ou des échanges en général.

2.1. Négociation TLS

Certains protocoles, comme IMAP ou POP disposent d’un mode d’usage de TLS dit « implicite ». Cela signifie que la version sécurisée de ces protocoles dispose d’un numéro de port TCP spécifique (IMAPS/993, POPS/995), et que lorsqu’un serveur est contacté sur ce port, TLS doit être employé dès les premiers segments échangés sur une nouvelle connexion TCP. La version TLS implicite de SMTP, appelée SMTPS et employant le port 465, a hélas été supprimée des registres de l’IANA, et le port 465 a été réalloué pour d’autres usages. SMTPS n’existe donc plus.

Certains protocoles disposant de TLS implicite existent également dans une version dite « explicite ». Dans ce cas, la connexion TCP est effectuée sur les ports « en clair » (IMAP/143, POP/110). C’est alors à la couche applicative (IMAP, POP), d’exprimer dans son dialecte qu’une amélioration de la sécurité de la communication est désirée. Cela s’exprime généralement par l’affichage d’une option STARTTLS par le serveur, et que le client est libre de solliciter en envoyant le message STARTTLS. Lorsque le client sollicite l’usage de TLS proposé par le serveur, les échanges en clair sont interrompus et la même connexion TCP est subitement employée pour échanger des messages TLS en vue de négocier des clés, puis de transférer du trafic chiffré. L’extrait de session SMTP ci-dessous illustre une négociation de STARTTLS. Les lignes préfixées par S: sont envoyées par le serveur, et celles par C: par le client.

S: 220 smtp.gmail.com ESMTP 186sm7907497wmm.32 - gsmtp
C: EHLO x-cli.eu
S: 250-smtp.gmail.com at your service, [2001:41d0:51:1::716]
S: 250-SIZE 35882577
S: 250-8BITMIME
S: 250-STARTTLS
S: 250-ENHANCEDSTATUSCODES
S: 250-PIPELINING
S: 250-CHUNKING
S: 250 SMTPUTF8
C: STARTTLS
S: 220 2.0.0 Ready to start TLS

L’avantage de l’emploi de TLS de façon implicite est que si la connexion TCP/TLS est ouverte avec succès, il n’y a aucun doute sur le fait que les messages transférés sont protégés. Avec TLS en mode explicite, la même assurance ne peut être fournie. Certains clients codés « un peu rapidement » poursuivent, en effet, l’envoi du courrier en clair, sans noter les erreurs renvoyées par les serveurs ne souhaitant pas recevoir en l’absence de TLS.

En outre, l’indication que le serveur prend en charge TLS et la sollicitation de chiffrement du client sont échangées en clair. Un attaquant actif est donc en mesure de corrompre le trafic afin de dissimuler/supprimer l’option/la sollicitation, afin que la négociation TLS ne soit pas effectuée. Cette attaque porte le nom de STARTTLS Stripping. Ce risque n’est pas théorique ; dans un excellent papier de Google, l’université du Michigan et l’université de l’Illinois 14, des chercheurs ont effectué une étude des connexions SMTP vers les serveurs de Gmail. Ils ont ainsi découvert qu’une grande quantité des connexions SMTP avec TLS explicite à destination de Gmail était altérée par des attaquants actifs. Dans certains pays, comme la Tunisie, jusqu’à 96% des connexions sont affectées par un attaquant, tandis que 9% des connexions sont affectées en France, et plus particulièrement à l’île de la Réunion.

Le mode opératoire de l’attaquant est de remplacer à la volée dans la connexion TCP l’option du serveur ou la sollicitation du client par une chaîne de même longueur que STARTTLS, non reconnue par l’autre partie, comme XXXXXXXX. En conséquence, le client ne verra pas l’option STARTTLS, mais une option XXXXXXXX qu’il ne sait pas utiliser, ou le serveur recevra une commande XXXXXXXX du client, à laquelle il répondra avec un message d’erreur indiquant qu’il s’agit d’une commande invalide.

Finalement, la validation des certificats TLS dans le cadre de SMTP est très en retard par rapport à celle de HTTPS. Par exemple, dans l’étude 14, environ 66% des certificats présentés par les serveurs SMTP sont invalides (mauvais sujet, principalement, mais aussi certificats périmés ou autosignés).

Le chiffrement est dit « opportuniste » lorsque les serveurs SMTP acceptent aveuglément tout certificat présenté. C’est le cas de la plupart des déploiements de SMTP sur l’Internet. De plus, au moment où ces lignes sont écrites, aucune implémentation de SMTP sur TLS connue de l’auteur n’est compatible avec Certificate Transparency. Comparativement, pour le web, tout certificat émis à partir d’avril 2018 et n’étant pas dans Certificate Transparency est jugé invalide par le navigateur Chrome.


Certificate Transparency est une technologie et un écosystème qui permettent au titulaire d’un nom de domaine de lister les certificats émis pour son nom de domaine, et d’ainsi vérifier qu’ils ont tous été émis avec son accord. Certificate Transparency a été présenté dans MISC Hors-Série n°13, article « Souriez ! Les autorités de certification sont filmées ! ».


2.2. Remplacement des enregistrements MX

Lorsqu’un serveur SMTP cherche à envoyer un courrier électronique à un tiers inconnu, la recherche du serveur SMTP à contacter s’effectue grâce au DNS. Pour cela, une recherche d’enregistrement de type MX (pour Mail eXchanger, ou relais de courriers, en français) est initiée. Ces enregistrements contiennent les noms des serveurs SMTP à contacter, noms qui doivent ensuite être résolus en adresse IP. Voici un exemple d’enregistrements MX :

example.com. 86400 IN MX 5 mail1.example.com.
example.com. 86400 IN MX 10 smtp.example.net.

Dans le même papier 14, les chercheurs ont également évalué la propension des attaquants à remplacer les enregistrements MX légitimes par des enregistrements MX contenant des noms de domaine sous son contrôle. Ce faisant, le serveur expéditeur enverra le courrier directement aux serveurs de l’attaquant, qui pourra prendre connaissance du contenu. L’attaquant peut, ensuite, éventuellement faire suivre le courrier aux vrais serveurs destinataires afin de rendre « transparente » l’attaque, en l’absence d’une politique SPF sur le domaine expéditeur. En présence de SPF, l’attaquant peut émuler un problème serveur, à la suite de la réception du contenu du courrier, par exemple, en renvoyant une erreur temporaire, indiquant un espace de stockage insuffisant (erreur 452). Le serveur expéditeur original réessaiera alors de transmettre ultérieurement le courrier, cette fois-ci au serveur destinataire légitime, qui saura valider la légitimité de l’expéditeur avec SPF.

Les auteurs de 14 ont interrogés les serveurs DNS récursifs et les relais DNS (forwarders) souffrant d’un défaut de contrôle d’accès (serveurs appelés résolveurs DNS ouverts) afin de collecter des réponses DNS depuis de nombreux points d’observation de l’Internet. Le résultat de ces mesures actives a révélé que 2% des serveurs DNS interrogés renvoyaient une réponse frauduleuse pouvant mener au détournement de courriers électroniques.

Il convient de noter que cette attaque ne saurait être prévenue même si l’expéditeur exigeait l’utilisation de TLS avec des certificats X.509 valides (sujet, dates, usage, etc.) de la part du destinataire. En effet, l’hébergement mutualisé de plusieurs domaines sur un seul serveur SMTP de réception n’emploie pas l’extension TLS appelée SNI. À la place, c’est le nom du serveur SMTP fourni dans l’enregistrement MX qui est généralement recherché à l’intérieur du certificat présenté par le serveur SMTP destinataire. Or, si l’enregistrement MX n’est pas signé avec DNSSEC, celui-ci peut être modifié à la volée par un attaquant pour y mettre tout nom sous son contrôle et pour lequel il est en mesure d’obtenir un certificat valide et légitime.


SNI permet de spécifier lors de l’initialisation de la connexion TLS, un nom de domaine spécifique parmi plusieurs domaines cohébergés sur la même machine ; c’est ainsi que l’on peut avoir plusieurs hôtes virtuels (Virtual Host) sur une même adresse IP servant du HTTPS.


L’emploi de SNI aurait permis à un expéditeur de préciser pendant la négociation TLS qu’il envoyait un courrier électronique à destination d’une adresse en @example.com. Le serveur de destination aurait alors pu fournir un certificat valide pour example.com.

Plusieurs explications existent pour justifier ce choix qui semble sous-optimal. En premier lieu, les serveurs SMTP réutilisent les connexions TCP/TLS ouvertes entre deux hôtes, afin de créer un pipeline. Cette réutilisation vise à éviter, lorsque c’est possible, le coûteux établissement d’une connexion TCP/TLS pour l’envoi d’un unique courrier. Il ne semblerait donc pas correct de réutiliser une connexion établie et authentifiée pour example.com pour l’envoi d’un courrier au nom de domaine cohébergé example.net. À la place, deux connexions indépendantes vers la même adresse IP devraient être employées ; un coût que tous les opérateurs ne souhaitent pas payer.

Ensuite, utiliser SNI présente le défaut de divulguer une partie des métadonnées (le nom du domaine du destinataire parmi les N domaines cohébergés) à un attaquant passif écoutant le réseau.

3. La contre-mesure : DNSSEC et DANE

Comme vu dans les précédentes sections de cet article, DNSSEC fournit une aide contre les attaquants actifs. Notamment, les signatures cryptographiques des enregistrements DNS permettent d’assurer l’intégrité et l’authentification de la source des données des technologies SPF, DKIM et DMARC. En outre, une vérification effective des informations contenues dans les certificats TLS pourrait être effectuée puisque DNSSEC confirme l’authenticité des noms présents dans les enregistrements MX.

Un aspect « chiffrement opportuniste » demeure néanmoins, lors du signalement de la prise en charge de TLS par le client et le serveur, avec STARTTLS, comme expliqué dans la section 2.1 de cet article. Il est, bien sûr, possible de refuser de communiquer avec toute personne n’offrant pas TLS. L’attaquant qui corrompt la négociation de TLS ne pratique alors qu’un déni de service, puisque les deux parties refuseront de communiquer en l’absence de canal chiffré. Ce choix peut être raisonnable pour certains types d’infrastructures, d’interconnexions ou d’organismes. Sur l’Internet, et en particulier dans un réseau comme SMTP où toute partie peut écrire à un autre, une telle intransigeance n’est cependant pas réaliste. En conséquence, il est nécessaire de disposer d’un mécanisme de signalement de la prise en charge de TLS qui soit lui-même résistant aux attaquants actifs, largement déployable, et ce de manière incrémentale.

DNS remplit le cahier des charges, avec son rôle d’annuaire protégé en intégrité par DNSSEC. Il est ainsi possible de publier un enregistrement DNS indiquant que le serveur SMTP contacté prend en charge TLS ; cet enregistrement pourra alors être récupéré par un client SMTP, au moment où il demande les enregistrements MX.

La technologie DANE 5 permet d’effectuer ce signalement de la prise en charge de TLS par la simple présence d’un enregistrement DNS de type TLSA. Il convient de noter que la spécification requiert que l’enregistrement TLSA soit signé et vérifiable par DNSSEC, ce qui apporte la protection contre l’attaquant actif.

Cet enregistrement est situé dans un sous-domaine des noms de domaine contenus dans les enregistrements MX. Plus précisément, le nom du MX est préfixé de la chaîne _25._tcp.. Ainsi, le serveur smtp.gmail.com pourrait disposer d’un enregistrement TLSA comme celui-ci :

_25._tcp.smtp.gmail.com. IN TLSA 3 1 1 Base64DuCertificatOuDeLaClefPublique

L’objectif de DANE dépasse celui du simple signalement de prise en charge de TLS, et permet notamment d’épingler le certificat ou la clé publique qui doivent être présentés par le serveur contacté. Pour cela, des outils comme 15 permettent de générer l’enregistrement TLSA à partir d’un certificat. Il suffit alors de le publier dans la zone DNS appropriée et de signer cette dernière avec DNSSEC.

Côté serveurs SMTP expéditeurs, la configuration pour la prise en compte de DANE est un peu moins aisée, puisqu’il faut valider les réponses DNSSEC d’une part, et configurer le serveur pour demander les enregistrements DANE d’autre part. La validation DNSSEC en elle-même devrait être effectuée par un résolveur validant local (Unbound ou Knot-Resolver sont de bons choix). Ensuite, avec Postfix, l’administrateur doit indiquer dans son fichier de configuration main.cf les lignes suivantes :

smtp_tls_security_level = dane
smtp_dns_support_level = dnssec

Ces lignes indiquent à Postfix de se comporter comme suit : en présence d’un enregistrement TLSA validé, le serveur contacté doit prendre en charge TLS ; si un attaquant actif corrompt l’échange et que l’option STARTTLS n’est pas négociée, Postfix ne transmet pas le courrier électronique. En cas d’erreur de validation de l’enregistrement TLSA, ou d’absence de réponse du serveur, le même comportement conservatoire doit être adopté. Dans les cas où la réponse DNS n’est pas signée, ou si elle ne contient pas d’enregistrement TLSA, alors le chiffrement opportuniste est employé avec le serveur contacté. En conséquence, le mode dane de Postfix permet un déploiement progressif, offrant une sécurité contre les attaquants actifs si DANE est employé, et conservant le chiffrement opportuniste dans le cas contraire.

4. Conclusion

Dans cet article, nous avons étudié différentes menaces pouvant affecter les échanges de courriers électroniques, en présence d’un attaquant actif. La figure 1 rappelle ces dernières de manière synthétique.

Synthèse des menaces étudiées dans cet article
Fig. 1 : Synthèse des menaces étudiées dans cet article pouvant affecter les échanges de courriers électroniques. Les flux en rouge sont créés ou modifiés par l’attaquant.

Nous avons également observé l’effet positif que DNSSEC peut avoir pour améliorer la sécurité des échanges de courriers électroniques. Hélas, son faible taux de déploiement à ce jour, signifie que la plupart des courriers électroniques peuvent être et sont la proie d’attaques actives plus ou moins ciblées (comme le cas tunisien, évoqué en section 2.1 nous l’a montré).

Les utilisateurs souhaitant échanger de manière confidentielle sont encouragés à chiffrer le contenu de leurs courriers électroniques, en complément de la protection offerte, de manière opportuniste ou non, par TLS. Il existe pour cela plusieurs options, dont des moyens intégrés (comme S/MIME ou, dans une moindre mesure, OpenPGP), ou non (comme ceux listés dans le catalogue des produits certifiés par l’ANSSI). Dans le cas du chiffrement opportuniste, les métadonnées de ces échanges ne sont, cependant, protégées que contre les écoutes passives lors de leur transit sur le réseau. Les administrateurs de serveurs de courriers électroniques souhaitant offrir une sécurité adéquate à leurs utilisateurs contre les attaques actives devraient donc signer leurs zones DNS avec DNSSEC, publier des enregistrements TLSA, et configurer leurs serveurs pour utiliser DANE lorsqu’il est disponible.

Pour finir, publier des enregistrements SPF, DKIM et DMARC signés participe à lutter contre les usurpations d’identité. Il convient cependant d’exiger des signatures DNSSEC sur les enregistrements DMARC ou de désactiver l’envoi de rapports dans son validateur DMARC, lorsque la configuration logicielle le permet, afin d’éviter les exfiltrations de métadonnées sur les courriers électroniques.

5. Remerciements

Je tiens à remercier mes relecteurs, Baloo (@baloose), Olivier Levillain et Christophe Malinge, pour leurs remarques constructives qui ont significativement contribué à l’amélioration de cet article.

Merci également à Claudio Fiandrino pour son code TikZ pour topologies réseaux, publié en 16.

6. Références

Publié par les Editions Diamond sous licence CC-BY-NC-ND.


  1. Outil de mesures DNS développé pour cet article : https://github.com/X-Cli/collectDNSSECEmailStats ↩︎

  2. Observatoire de la résilience de l’Internet français : https://www.ssi.gouv.fr/observatoire ↩︎ ↩︎

  3. Charte de l’ANSSI pour l’amélioration de la sécurité des échanges de courriers électroniques : https://www.ssi.gouv.fr/particulier/precautions-elementaires/charte-pour-la-securite-des-courriers-electroniques/ ↩︎

  4. Document équivalent au lien précédent, rédigé par l’homologue de l’ANSSI en Allemagne : http://www.project-consult.de/files/BSI_TR03108-1_Sichere_EMail.pdf ↩︎

  5. The DNS-Based Authentication of Named Entities (DANE) Transport Layer Security (TLS) Protocol : TLSA https://tools.ietf.org/html/rfc6698 ↩︎ ↩︎

  6. DNS Certification Authority Authorization (CAA) Resource Record : https://tools.ietf.org/html/rfc6844 ↩︎

  7. CAA Study : https://caastudy.github.io/ ↩︎

  8. Measuring DANE TLSA Deployment : https://www.isi.edu/~liangzhu/presentation/dns-oarc/dane_tlsa_survey.pdf ↩︎

  9. Baseline Requirements Documents : https://cabforum.org/baseline-requirements-documents/ ↩︎

  10. Sender Policy Framework (SPF) for Authorizing Use of Domains in Email, Version 1 : https://tools.ietf.org/html/rfc7208 ↩︎

  11. DomainKeys Identified Mail (DKIM) Signatures : https://tools.ietf.org/html/rfc6376 ↩︎

  12. NXDOMAIN : There Really Is Nothing Underneath : https://tools.ietf.org/html/rfc8020 ↩︎

  13. Domain-based Message Authentication, Reporting, and Conformance (DMARC) : https://tools.ietf.org/html/rfc7489 ↩︎

  14. Neither Snow Nor Rain Nor MITM… An Empirical Analysis of Email Delivery Security : https://static.googleusercontent.com/media/research.google.com/fr//pubs/archive/43962.pdf ↩︎ ↩︎ ↩︎ ↩︎

  15. https://www.huque.com/bin/gen_tlsa ↩︎

  16. Attribution 2.5 Generic : https://creativecommons.org/licenses/by/2.5/ ↩︎

Chiffrement de messagerie quasi instantanée : à quel protocole se vouer ?

Telegram, WhatsApp, Signal, OTR… et autant de protocoles de messagerie quasi instantanée, de modèles de sécurité et de protocoles cryptographiques : lesquels choisir ? Et si la solution idéale n’était pas dans la liste précédente ? Cet article évoque les limites de plusieurs de ces solutions, et présente le cœur cryptographique de Signal, WhatsApp et du protocole OMEMO. Il met finalement en exergue, par une analyse comparative, certaines limites de Signal et des qualités d’OMEMO.

Chiffrement des messages de bout en bout ou chiffrement du canal, qualité des algorithmes cryptographiques et de l’authentification des pairs, confidentialité persistante (PFS) ou non, fiabilité de l’équipement faisant tourner la solution, limitation de l’exposition des métadonnées, fuite du carnet d’adresses, localisation des serveurs, capacité à dénier l’envoi d’un message : des critères rarement considérés par les utilisateurs de messagerie. Leurs véritables critères de sélection sont souvent la taille du réseau social joignable, la facilité d’utilisation, l’accessibilité de la solution sur l’équipement de l’utilisateur ou encore la liste des services annexes. Un constat compréhensible, puisque la première liste est formée de critères abscons et rarement absolus, tandis que la seconde liste affecte l’usage quotidien.

Certains utilisateurs restent néanmoins soucieux de leur vie privée ou sont contraints par la nature de leurs activités en ligne à un niveau de sécurité plus élevé. Ils disposent alors d’une myriade d’options, dont Telegram, WhatsApp, Signal, ou Apple iMessage. Ils peuvent aussi se tourner vers des solutions de messagerie instantanées traditionnelles augmentées du protocole OTR 1 ou encore des e-mails augmentés grâce à OpenPGP 2.

Se pose alors la question de séparer le bon grain de l’ivraie ; une tâche qui est simplifiée par la forte concentration des applications autour des protocoles X3DH 3 et Double Ratchet 4. Ces deux protocoles, spécifiés récemment dans le domaine public par les auteurs de Signal, sont employés par plusieurs vendeurs, dont Signal et WhatsApp. En outre, la communauté de XMPP, un protocole de messagerie quasi instantanée, a également choisi X3DH+Double Ratchet, afin de remplacer leur usage d’OpenPGP et OTR.

La combinaison X3DH+Double Ratchet n’est cependant qu’une partie de la solution pour sécuriser les communications. Plus spécifiquement, ces protocoles permettent, respectivement, la négociation des clés et leur rafraîchissement. L’utilisation de ces clés, afin de créer des sessions cryptographiques entre les utilisateurs, est dévolue à d’autres composants : le protocole Signal, dans le cas de Signal et de WhatsApp, et le protocole OMEMO 5, dans le cas de XMPP.

X3DH+Double Ratchet, OMEMO et Signal sont étudiés dans la suite de cet article.

Pour le lecteur intéressé, la sécurité de Telegram a fait l’objet de discussions 6 et d’études 7 et l’université de Johns Hopkins a étudié celle d’Apple iMessage 8. WeChat ou encore Slack sont hors sujet, puisqu’ils ne proposent pas de chiffrement de bout en bout.

1. Les protocoles inadéquats pour la messagerie quasi instantanée

1.1. OpenPGP

OpenPGP est un format de stockage de messages et de clés cryptographiques, spécifié dans sa version la plus récente en 2007 2. Il est notamment employé pour sécuriser des messages électroniques. Ce format étant agnostique vis-à-vis de la nature des messages, il convient pour des réseaux de messagerie décentralisés ou lorsque le destinataire est hors-ligne (protocole non interactif). Il permet également d’assurer de la protection de bout en bout, puisque ce sont les messages qui sont chiffrés et non le canal de transport de ces derniers.

En outre, il est possible d’utiliser OpenPGP pour envoyer des messages à un groupe d’utilisateurs. Pour ce faire, la clé de chiffrement du message est chiffrée avec les clés publiques de chacun des destinataires. Les clés publiques ainsi utilisées doivent être préalablement créées, et stockées dans des certificats OpenPGP. Ces certificats permettent d’associer des identités — éventuellement des pseudonymes — à ces clés publiques. Ces certificats sont transmis ponctuellement aux autres utilisateurs grâce à des annuaires ou par une remise en main propre.

OpenPGP présente cependant des limites, en regard de solutions alternatives spécialisées pour le chiffrement de messagerie quasi instantanée. Ainsi, il n’offre pas, de manière inhérente, de confidentialité persistante du fait de la transmission ponctuelle des certificats : le rafraîchissement des clés est du ressort de l’utilisateur. En outre, pour la protection en intégrité des messages, l’utilisateur n’a le choix qu’entre des solutions imparfaites. L’une est sujette à des attaques par dégradation du niveau de sécurité (downgrade attack) 9 et l’autre use de signatures cryptographiques non répudiables, ce qui n’est pas toujours souhaitable.

1.2. Off-the-Record

Le protocole Off-the-Record a été spécifié, pour la première fois, en 2004 ; sa version la plus récente date de 2012. Ce mécanisme permet l’échange de clés et de messages sécurisés de bout en bout. L’établissement de la session protégée est effectué entre deux parties de manière interactive. Autrement dit, il est nécessaire que les participants soient en ligne simultanément pour l’établissement de cette session. Cette propriété exclut un usage asynchrone, et restreint donc ce protocole à la messagerie instantanée. Une variante, appelée mpOTR 10, permet d’échanger des messages au sein d’un groupe d’utilisateurs.

Avec OTR, les utilisateurs sont identifiés par des clés publiques à long terme. Les clés à long terme servent à signer/authentifier des échanges de clés Diffie-Hellman (DH) éphémères. Ces clés éphémères servent, à leur tour, à générer les clés protégeant les messages. Il convient de noter que les signatures émises par les clés à long terme affectent la vie privée ; elles constituent, en effet, une preuve non répudiable qu’une conversation a eu lieu entre deux parties, même si le contenu de la conversation reste inconnu d’un observateur.

Une fois la négociation de clés initiale accomplie, de nouvelles biclés DH sont introduites à chaque nouveau message. Cela permet ainsi de rafraîchir les secrets et d’apporter la confidentialité persistante. En effet, la compromission d’une clé privée DH n’affecte la confidentialité que d’un unique message ; de même, la compromission de la clé à long terme n’affecte que les futurs messages.

Le protocole Off-the-Record présente également une propriété de sécurité qui serait favorable à la vie privée. Ainsi, Off-the-Record permettrait à un expéditeur de dénier le contenu d’un message, tout en garantissant au destinataire la légitimité et l’intégrité du message reçu. Pour ce faire, les clés utilisées pour calculer des motifs d’intégrité de messages sont divulguées en clair après réception et vérification de ces messages. Conjuguée à un mode de chiffrement malléable et à un clair connu, cette méthode peut permettre à un observateur de forger un message chiffré et intègre arbitraire. Cet observateur serait cependant incapable de prouver à un tiers l’authenticité d’un message qu’il détient. L’efficacité de ce mécanisme fait néanmoins débat parmi les experts, car il n’a jamais été éprouvé dans le cadre d’un procès, afin de décrédibiliser une conversation enregistrée et utilisée comme preuve incriminante.

Malgré ses nombreux avantages, le protocole Off-the-Record, tel que spécifié dans sa version la plus récente (3.4), souffre d’un problème d’obsolescence cryptographique. En effet, l’absence d’un mécanisme de négociation des algorithmes fait d’Off-the-Record un musée des algorithmes cryptographiques des années 2000. Sont notamment employés l’algorithme de signature DSA, des empreintes cryptographiques avec SHA-1, ou encore des échanges DH sur corps entiers de 1536 bits avec un groupe fixé par la spécification. L’usage de cette cryptographie datée est contraire aux bonnes pratiques actuellement reconnues.

2. X3DH+Double Ratchet

Les protocoles X3DH et Double Ratchet ont été inventés par Trevor Perrin et Moxie Marlinspike. En 2013, il s’agissait, en fait, d’un seul et même protocole connu sous le nom d’Axolotl. Ce n’est qu’en 2016 qu’Axolotl fut divisé et que ses parties furent renommées afin de mettre fin à des confusions fréquentes entre Axolotl et le protocole Signal. Il faut dire que le protocole Signal, qui fait usage d’une variante d’Axolotl, n’a, à ce jour, jamais été spécifié ou documenté et que la frontière entre les deux protocoles était donc pour le moins floue. Les spécifications complètes de X3DH et Double Ratchet ont finalement été publiées en novembre 2016. Cette publication a également permis de mettre fin à de récurrentes menaces judiciaires que les auteurs de Signal ont pu proférer contre des vendeurs prétendant implémenter le protocole Signal, alors qu’ils utilisaient réellement Double Ratchet 11.

X3DH est responsable de la négociation de clés cryptographiques. Celle-ci prend place lors d’une phase initiale. Les clés évoluent ensuite par dérivations, selon le protocole Double Ratchet. Ce dernier rafraîchit les clés à l’aide de cryptographie symétrique, ainsi que par l’apport régulier de nouveaux éléments secrets asymétriques.

Pour effectuer ces opérations sur les clés, les deux protocoles emploient de la cryptographie moderne : XEdDSA, une extension à EdDSA, sur les courbes elliptiques curve25519 ou curve448 12, SHA2 et HKDF 13.

2.1. X3DH

Chaque utilisateur du protocole X3DH doit générer et publier un ensemble de biclés cryptographiques. Ces clés doivent être compatibles avec les fonctions X25519 ou X448 de XEdDSA.

La première biclé est appelée clé à long terme. Elle sert dans le cadre d’échanges DH, mais elle est également employée pour signer d’autres biclés, appelées clés à moyen terme. Des biclés à usage supposément unique sont également générées en grande quantité ; Signal et Conversations en génèrent ainsi une centaine. Générer autant de clés à usage unique permet qu’un grand nombre de sessions puissent être établies avec la confidentialité persistante dès le premier message, et ce alors que le destinataire n’est pas en ligne.

La génération de ces trois types de biclés (à long et moyen termes et à usage unique) doit être répétée pour chacun des périphériques avec lesquels un utilisateur est susceptible d’accéder à ses messages. L’utilisateur disposant d’un PC, d’une tablette et d’un téléphone portable se retrouve ainsi rapidement avec plusieurs centaines de biclés associées à son identifiant. Seule la clé à long terme de chaque équipement nécessite cependant une vérification d’authenticité par les autres utilisateurs.

Ces biclés sont utilisées afin d’établir des sessions entre un expéditeur et l’ensemble des périphériques des destinataires. Ces périphériques peuvent être possédés par un même destinataire ou par plusieurs destinataires, dans le cadre d’une discussion de groupe. La liste des périphériques destinataires peut même contenir les équipements de l’expéditeur, afin de permettre la synchronisation des messages émis entre équipements.

Autant de sessions sont créées qu’il y a d’équipements destinataires. Cette étape n’a cependant besoin de se produire qu’une seule fois, lors de la première conversation entre deux périphériques. Ces sessions ont, en effet, une durée de vie illimitée.

Pour établir une session, la première étape consiste à récupérer les clés publiques des périphériques destinataires. La manière dont elles sont publiées et récupérées est laissée ici volontairement abstraite ; elle varie d’une implémentation à l’autre, comme le détaillera la section 3 de cet article.

Une fois les clés publiques des destinataires en possession de l’expéditeur, ce dernier effectue les mêmes étapes avec les clés de chaque périphérique pour lequel une session doit être établie. La première étape consiste à générer une nouvelle biclé DH éphémère. Trois à quatre échanges DH sont ensuite effectués, entre les clés de l’équipement expéditeur et celles de l’équipement destinataire. L’appariement des clés publiques DH est détaillé dans la figure 1.

Illustration d&rsquo;un échange de clé avec X3DH
Fig. 1 : Illustration des échanges de clés DH effectués dans le cadre de X3DH. Le trait en pointillé représente un échange optionnel, qui n’a lieu que si une clé à usage unique est disponible pour l’équipement destinataire.

La variabilité du nombre d’échanges DH résulte de la capacité à récupérer une des clés à usage unique pour l’équipement destinataire. Certains dépôts de clés tiennent, en effet, une comptabilité afin d’assurer qu’une clé à usage unique n’est bien distribuée qu’une seule fois. Si toutes les clés ont été distribuées, aucune n’est fournie à l’expéditeur et seuls trois échanges DH sont opérés. Ceci peut affecter la confidentialité persistante, car le destinataire ne fournit alors que des clés qui sont partagées entre plusieurs sessions. Dans la section 2.2 traitant de Double Ratchet, il sera détaillé comment cette faiblesse est cicatrisée dès la réception d’un message de la part de l’équipement destinataire.

L’ensemble des secrets résultant des échanges DH est ensuite concaténé et passé à travers la fonction HKDF pour former une valeur secrète, appelée secret racine de la session.

Cet échange de clés a la particularité de négocier un secret tout en préservant la capacité des deux parties de nier avoir tenu une conversation ensemble. Cette propriété est dérivée de l’hypothèse de difficulté calculatoire de DH (Computational DH Assumption). La signature XEdDSA des clés à moyen terme, qui elle est non répudiable, ne prévient pas cette propriété puisqu’elle est totalement décorrélée de l’échange de clés et n’intervient que pour « certifier » la clé à moyen terme.

2.2. Double Ratchet

Double Ratchet repose sur deux mécanismes de rafraîchissement des clés. Ces deux mécanismes confèrent son nom à cet algorithme, puisqu’ils utilisent tous deux, à l’instar d’une roue à rochet, des fonctions cryptographiques à sens unique pour faire « évoluer » des secrets.

Le premier, représenté sur fond jaune dans la figure 2, utilise exclusivement la cryptographie symétrique. Il permet de générer les clés secrètes protégeant les messages. Avec ce mécanisme, chaque message bénéficie d’une clé secrète à usage unique. Cette clé de protection d’un message est obtenue par dérivation d’une clé, tirée d’un ensemble appelé chaîne de clés. Cette chaîne est formée par des dérivations successives de secrets. Le secret initial de cette chaîne est le secret racine actuel. La notion d’actualité du secret racine provient du second mécanisme de rafraîchissement des clés.

Ce second mécanisme, représenté sur fond vert dans la figure 2, utilise de la cryptographie asymétrique. Il vise à faire évoluer la clé racine qui a été négociée initialement, par exemple avec X3DH. Avec ce mécanisme, une nouvelle biclé DH est tirée aléatoirement chaque fois qu’un périphérique s’apprête à envoyer un message consécutif à la réception d’un message par un autre périphérique. La clé publique de cette nouvelle biclé DH est jointe à l’ensemble des messages envoyés par ce périphérique jusqu’à la réception d’un message de la part d’un autre périphérique. Cette gymnastique est représentée dans la figure 3.

La nouvelle clé DH fraîchement tirée est utilisée dans un échange DH en conjonction avec les clés publiques les plus récentes reçues dans des messages émis par les autres périphériques. Le résultat de cet échange est ensuite « mélangé » avec le secret racine actuel à l’aide de la fonction HKDF. Le résultat de cette opération devient le nouveau secret racine actuel.

Illustration de l’algorithme Double Ratchet
Fig. 2 : Illustration de l’algorithme Double Ratchet. Les clés composant la chaîne de clés sont représentées dans des diamants. Les clés de messages sont représentées dans des ellipses. Les algorithmes sont dessinés dans des boîtes roses aux bords arrondis. Les composants sur fond vert représentent la roue à rochet asymétrique. Les composants sur fond jaune représentent la roue à rochet symétrique.

Illustration d’un enchaînement de messages avec un protocole de messagerie employant Double Ratchet
Fig. 3 : Illustration d’un enchaînement de messages avec un protocole de messagerie employant Double Ratchet. De nouvelles clés asymétriques sont générées juste avant l’envoi d’un message faisant suite à une réponse. Cette clé asymétrique est répétée dans tous les messages suivants.

L’utilisation de ces deux mécanismes de rafraîchissement de clés permet de bénéficier de clés secrètes uniques pour chaque message envoyé, y compris lorsqu’un des participants se lance dans un monologue de plusieurs messages. La compromission d’une clé symétrique ne mène alors qu’à la compromission d’un seul message. La réception d’un message de la part de l’autre participant permet ensuite de rafraîchir le secret racine. Ceci permet ainsi de prévenir la compromission de plus d’un monologue en cas de compromission d’une clé asymétrique.

Outre ces propriétés, les protocoles de messageries sécurisées reposant sur Double Ratchet peuvent également se montrer tolérants vis-à-vis de la perte de messages ou de la livraison de messages dans le désordre. Il suffit à ces applications de conserver les différentes chaînes de clés, et de « sauter » les messages encore non reçus, en appliquant plusieurs fois de suite la fonction HMAC-SHA256 avec la « constante 2 » de la figure 2. Il convient néanmoins de noter que conserver ainsi les clés, au lieu de les supprimer dès que possible, peut mettre en péril la confidentialité persistante, en cas de compromission d’un équipement.

2.3. Intégration de X3DH+Double Ratchet dans OMEMO

La première version d’OMEMO a été spécifiée par Andreas Straub en 2015, avec l’aide de Daniel Gultsch, développeur principal du client XMPP Conversations. En décembre 2016, OMEMO a été officiellement acceptée comme extension expérimentale du protocole XMPP (XEP-0384).

Avec XMPP, chaque utilisateur est identifié par un JID. Il s’agit d’un identifiant qui ressemble fort à une adresse e-mail, mais il est suivi d’une barre oblique (slash) et du nom d’un équipement ou d’un logiciel. florian@im.x-cli.eu/phone est, par exemple, le JID de l’auteur de cet article lorsqu’il est connecté avec son téléphone. À l’instar des adresses e-mail, la partie précédant l’arobase désigne un utilisateur local, tandis que la partie suivant l’arobase et jusqu’à la barre oblique désigne le serveur sur lequel est hébergé cet utilisateur. XMPP est donc un système fédéré, où chaque utilisateur choisit son fournisseur de service.

Les messages à destination d’un utilisateur, désigné par son bare JID (c.-à-d. son JID sans le nom de l’équipement), sont délivrés au dernier périphérique actif de cet utilisateur. Ce fonctionnement peut être altéré grâce aux extensions Carbon Messages (XEP-0280) et Message Archive Management (XEP-0313) afin que tous les équipements d’un utilisateur aient accès à tous les messages reçus. En outre, si un utilisateur est hors-ligne, ses messages peuvent être stockés sur le serveur responsable du compte de l’utilisateur. Ces messages lui seront alors délivrés lors de sa prochaine connexion. Par ailleurs, des informations relatives à un utilisateur peuvent être stockées, en clair, sur le serveur responsable de son compte, grâce à l’extension XMPP XEP-0163, appelée Personal Eventing Protocol (PEP). Ce mécanisme, lui-même extensible, permet ainsi à un utilisateur connecté ou hors-ligne de mettre à la disposition d’autres utilisateurs diverses informations comme son avatar, son dernier message de statut, ou encore sa « carte de visite ».

OMEMO utilise ces différentes extensions XMPP pour offrir une méthode de chiffrement de bout en bout à l’ergonomie moderne. Chaque équipement, lorsqu’il active OMEMO, génère sa clé à long terme, sa clé à moyen terme et d’une vingtaine à une centaine de clés à usage « unique ». Les jeux de clés de chaque équipement sont stockés dans le profil PEP utilisateur. Lorsqu’un expéditeur souhaite établir une nouvelle session, il récupère toutes les clés auprès du serveur responsable du compte du destinataire. Ensuite, il effectue un échange de clés en suivant le protocole X3DH. Par équipement avec lequel une session doit être établie, il sélectionne aléatoirement une clé à « usage unique ». Cette sélection aléatoire permet de s’affranchir du risque qu’un serveur malveillant dégrade la confidentialité persistante en diffusant sciemment une clé à usage unique déjà employée par ailleurs. Le risque de dégradation de la confidentialité persistante n’est cependant pas totalement évité. Il est, en effet, possible que plusieurs sessions soient établies pendant qu’un périphérique est hors-ligne, et que la sélection aléatoire provoque une collision. Plus un périphérique tarde à remplacer les clés utilisées, et plus le risque de collision grandit. Cette collision a une portée limitée puisqu’elle n’a un impact que sur tout ou partie du premier monologue d’un utilisateur. Si l’équipement, dont l’une des clés à usage unique a été réutilisée, se connecte et détecte cette situation, il est alors en mesure de rétablir la confidentialité persistante. Il lui suffit d’envoyer un message « de service » dont le seul objet est de rafraîchir le secret racine. Cette situation semble, dans tous les cas, préférable à l’absence totale du quatrième échange DH.

3. Des divergences entre Signal et le protocole OMEMO

Signal et le protocole OMEMO sont par certains aspects très similaires. Certaines implémentations d’OMEMO utilisent, en effet, la bibliothèque cryptographique libsignal 14 d’Open Whisper Systems, la société éditrice de Signal. Ses usages sont cependant cantonnés aux échanges de clés X3DH et à la maintenance des secrets avec Double Ratchet. Les points de divergences entre Signal et les implémentations d’OMEMO se situent donc sur les points suivants : les identifiants et l’architecture réseau, l’infrastructure de gestions de clés, l’usage qui est fait de ces clés, l’existence de documentation de qualité et la capacité à auditer le protocole.

3.1. Les identifiants et l’infrastructure réseau

Alors qu’OMEMO utilise une infrastructure répartie, où chaque utilisateur choisit son fournisseur de services, grâce au réseau fédéré XMPP, Signal préfère une infrastructure centralisée. Les auteurs de Signal ont, en effet, exprimé une opinion très négative sur les notions de fédération et d’interopérabilité, les qualifiant de causes génératrices de l’ossification des protocoles 15. Au diable donc l’Internet ouvert, le succès de HTTP ou encore celui des courriers électroniques. Moxie Marlinspike a même demandé à des clones (fork) de Signal de ne pas employer les serveurs opérés par Open Whisper Systems, quand bien même le protocole employé était le même 16. Signal est donc un système clos ; la porte de la fédération a été fermée à clé, clé qui est maintenant au fond d’un lac.

Signal utilise les numéros de téléphone des utilisateurs comme identifiants. Cette pratique a certainement pour origine l’usage des SMS/MMS comme première méthode de transport des messages de Signal. En 2015, les développeurs ont cependant décidé arbitrairement d’arrêter de prendre en charge le transport par SMS/MMS, et d’utiliser, à la place, exclusivement les serveurs d’Open Whisper Systems, situés aux États-Unis. Cette décision a fait réagir une fraction de la communauté qui a créé un clone de l’application, désormais appelé Silence 17.

Le choix d’Open Whisper Systems d’arrêter la prise en charge des SMS/MMS n’a cependant pas causé l’arrêt de l’usage des numéros de téléphone comme identifiants. Il en résulte un problème de vie privée, dû au fait que les métadonnées relatives aux expéditeurs et destinataires ne sont pas chiffrées par le protocole Signal. En effet, ces identifiants pourraient permettre aux opérateurs d’Open Whisper Systems de tracer le graphe social des utilisateurs, ou encore de les géolocaliser, grâce au réseau SS7 18.

Le choix des numéros de téléphone comme identifiant est également fortement discutable depuis la publication de Signal Desktop. Ce logiciel permet aux utilisateurs de converser depuis des PC avec les utilisateurs Signal ; il n’est cependant pas possible d’employer ce logiciel sans s’être enrôlé préalablement sur téléphone portable !

Pour finir, cette centralisation du service présente également des risques topologiques. En effet, la géolocalisation aux États-Unis de la société Open Whisper Systems et de ses serveurs signifie qu’elle est soumise à l’arsenal légal américain. Celui-ci a d’ailleurs déjà été mis en œuvre à l’encontre de Signal 19. En outre, la centralisation facilite la censure administrative du service, comme cela s’est déjà produit plusieurs fois au Brésil pour WhatsApp 20, et en Égypte pour Signal 21. Une technique expérimentale 22, inspirée du module meek pour Tor et appelée Domain Fronting, a été déployée en réponse à ce dernier blocage. Son déploiement hâtif laisse cependant en suspens des questions de vie privée, de confidentialité et d’intégrité, eu égard à l’absence de protection de bout en bout de certaines (méta-)données transitant par Google AppEngine lors du Domain Fronting.

En comparaison, les JID de XMPP/OMEMO peuvent être des pseudonymes n’offrant aucune corrélation avec un utilisateur particulier. Les utilisateurs les plus prudents peuvent même se connecter à XMPP au travers de Tor, ou utiliser des hidden services XMPP sur Tor. En outre, les identifiants ne sont pas liés à un type d’équipements. Ils peuvent ainsi être utilisés sur PC ou téléphone exclusivement ou sur un mélange des deux. Finalement, pour la géolocalisation des serveurs, l’infrastructure répartie de XMPP permet de jongler à volonté avec la localisation administrative et juridique des serveurs.

3.2. L’infrastructure de gestion de clés

Les serveurs gérés par Open Whisper Systems sont responsables du stockage des clés publiques de tous les utilisateurs, et de distribuer ces clés aux nouveaux utilisateurs. Ainsi, lorsqu’un nouvel utilisateur installe Signal, le logiciel prélève les numéros de téléphone de l’intégralité du carnet d’adresses de l’utilisateur, et les envoie aux serveurs de Signal, qui retournent en échange les clés des utilisateurs connus 23. Les utilisateurs figurant dans le carnet de contacts sont également notifiés qu’un de leurs contacts vient d’installer Signal.

En vue de protéger la vie privée des utilisateurs, les numéros de téléphone des contacts sont hachés avec une fonction cryptographique et le résultat est tronqué ; cette technique s’avère cependant insuffisante et une recherche exhaustive permet de recouvrer ces numéros de téléphone.

Pour chaque utilisateur du carnet d’adresses ayant Signal, les serveurs d’Open Whisper Systems retournent donc une clé à long terme, une clé à moyen terme et optionnellement une clé à usage unique. Cette méthode de distribution centralisée des clés exige de faire confiance aux serveurs. Ces derniers peuvent, en effet, dégrader sciemment la confidentialité persistante en ne retournant pas de clé à usage unique. Ils peuvent, en outre, tout simplement fournir de fausses clés, en vue d’effectuer une interception de messages. Cette éventualité peut être contrée si les utilisateurs effectuent une vérification des clés retournées et les valident. L’usage des clés préalable à cette vérification n’est cependant pas empêché, et nombre d’utilisateurs font donc probablement une confiance aveugle aux serveurs de Signal.

Les utilisateurs méfiants qui voudraient effectuer cette vérification ne sont malheureusement pas dotés d’outils adaptés. Ainsi, s’il était auparavant possible de vérifier la clé du destinataire d’un message, les développeurs de Signal ont dégradé cette possibilité en novembre 2016. Au nom d’études sur l’expérience utilisateur, ils ont ainsi remplacé la vérification d’empreintes cryptographiques des clés par la comparaison de « nombres de sûretés » (safety number) 24, supposément plus faciles à comparer. Cette opération a ainsi réduit la sécurité de l’empreinte de 256 bits à 100 bits. Plus incompréhensible encore, l’empreinte a également été réduite dans le QRCode utilisé pour la comparaison des clés, alors qu’il ne peut y avoir d’impact sur l’expérience utilisateur, que l’on photographie un QRCode de 100 ou 256 bits de sécurité ! Pour finir, la vérification des empreintes est impossible lors d’une conversation de groupe 25.

Pour enfoncer le dernier clou, Signal envisage de réviser à la baisse son mécanisme de sécurité concernant le signalement d’un changement de clés d’un pair 24. Auparavant, lorsqu’un utilisateur changeait de clé à long terme (une opération rarissime), une notification était affichée et une confirmation manuelle était exigée. Avec la nouvelle option, dont il est envisagé qu’elle soit activée par défaut, seule une petite ligne sera affichée au milieu de la conversation.

En comparaison, les clés OMEMO sont récupérées auprès d’un serveur au choix du destinataire. Avec le logiciel Conversations, par défaut depuis la version 1.15 de novembre 2016, les clés peuvent être employées sans avoir été vérifiées ; un indicateur visuel différencie cependant les échanges avec les clés vérifiées et les échanges sans vérification 26. De plus, dès qu’une première clé d’un utilisateur est vérifiée, seules ses clés vérifiées sont utilisables. Dans le cas où plusieurs périphériques seraient destinataires, chaque clé doit être individuellement validée au premier usage, à l’aide d’une empreinte cryptographique de 256 bits. Il existe un risque d’utiliser plusieurs fois une clé à usage unique, mais le protocole prévoit une contre-mesure pour raccourcir la durée de l’incident.

3.3. Usage des clés symétriques

Signal chiffre les messages à l’aide d’AES256 en mode CBC et ses motifs d’intégrité sont calculés avec HMAC-SHA256 dont le résultat est tronqué à 64 bits.

Ces choix peuvent faire débat. Ainsi, bien que Signal use d’une composition chiffrement/intégrité satisfaisante (Encrypt-then-Mac), l’implémentation incorrecte du mode CBC s’est révélée à l’origine de nombreuses vulnérabilités au fil des années. Cela a été notamment le cas dans TLS. En conséquence, l’existence de meilleures alternatives, tant en performances qu’en sécurité, a valu à ce mode d’être déconseillé par les auteurs du RFC de HTTP/2 27. La prochaine version de TLS ne la prend même tout simplement pas en charge 28.

En outre, si l’algorithme HMAC-SHA256 est, à ce jour, irréprochable, la troncature du motif d’intégrité à 64 bits affaiblit son efficacité de manière significative. Ce choix tient peut-être sa justification dans l’usage des SMS comme méthode originelle de transport des messages. À l’heure actuelle, tous les messages de Signal sont notifiés à l’aide de Firebase Cloud Messaging (anciennement Google Cloud Messaging), et transportés sur le canal de données des téléphones portables. Les problèmes de bande passante utile ne peuvent donc plus constituer une justification. En fait, la grande bande passante désormais disponible joue même à l’encontre de cette troncature, rendant plus facile le bombardement de messages frauduleux jusqu’à réussir à forger un motif correct.

En comparaison, OMEMO emploie AES256 avec le mode de chiffrement authentifié GCM, considéré à l’état de l’art.

3.4. Documentation et audits

Signal est une cible mouvante. Jusqu’alors dénué de documentation, par une volonté affichée de ses développeurs, ce n’est que sur la pression croissante de la communauté que les algorithmes XEdDSA, X3DH et Double Ratchet ont été finalement spécifiés et publiés dans le domaine public. Si des études formelles vont désormais pouvoir être menées sur ces trois protocoles, effectuer ce même type d’études sur le protocole Signal reste encore un défi. Quelques-uns s’y sont néanmoins essayés, documentant leurs découvertes du protocole par « ingénierie inverse du code source », afin de dégager des propriétés de sécurité 29 30. Aucune attaque réellement significative n’a été découverte, à ce jour.

En comparaison, le protocole OMEMO est documenté et standardisé dans une extension expérimentale du protocole XMPP. Il a récemment subi un audit, ayant révélé divers points d’attention 31, qui ont été rapidement pris en compte par le protocole et au moins certaines implémentations.

4. Conclusion

Cet article a détaillé les atouts et inconvénients de plusieurs protocoles permettant la sécurisation de messageries quasi instantanées. La figure 4 reprend les observations de manière synthétique.

Synthèse des points forts et faibles de plusieurs protocoles dans le cadre de la messagerie (quasi) instantanée.
Fig. 4 : Synthèse des points forts et faibles de plusieurs protocoles dans le cadre de la messagerie (quasi) instantanée. Les justifications ou références ont été apportées dans l’article.

Les utilisateurs souhaitant protéger leur messagerie quasi instantanée de bout en bout disposent d’options valables, comme Signal, WhatsApp, ou encore OMEMO. Ces outils ont en commun un cœur cryptographique formé des protocoles X3DH et Double Ratchet, dont il ressort de plusieurs études indépendantes qu’ils seraient fiables.

Malgré cela, ces différentes solutions offrent un niveau de protection de la vie privée et de la confidentialité des messages qui varie de manière significative. Ainsi, cet article a rappelé, à l’instar d’une conférence lors de la conférence 33c3 32, que les numéros de téléphone sont à la fois des identifiants de compte pratiques, puisque déjà enregistrés dans le téléphone, mais aussi une donnée personnelle sensible. Outre leur usage éventuel pour géolocaliser des utilisateurs, ils sont nécessairement transmis en clair, en tant que métadonnées de tout message : une situation préoccupante lorsque les messages du réseau doivent passer par une infrastructure centralisée. Cette dernière est, en effet, en mesure d’observer le graphe social de ses utilisateurs et la fréquence de leurs échanges, quand bien même leurs concepteurs s’en défendent 19. Par ailleurs, comme cet article l’a présenté, les serveurs de Signal et WhatsApp sont en charge de la délivrance des clés publiques des contacts d’un utilisateur. Pour cela, un dérivé cryptographique des numéros de tous les contacts d’un utilisateur est envoyé aux serveurs, qui répondent avec des clés publiques associées. Cette dérivation cryptographique est hélas aisément réversible 23, et il est possible de retrouver la liste des contacts d’un utilisateur de ces applications. En outre, il est à la charge des utilisateurs de vérifier l’authenticité des clés remises par les serveurs, une étape probablement rarement effectuée et dont les mécanismes de vérification ont été récemment dégradés dans Signal, parfois de façon inexplicable 24. Pour WhatsApp, ce mécanisme de distribution de clés a même été à l’origine d’un tumulte, en janvier 2017, lorsque le journal Guardian a rapporté qu’une vulnérabilité publique depuis huit mois et non corrigée permet l’interception de messages en clair 33.

Finalement, cet article a détaillé le protocole OMEMO, qui utilise le réseau XMPP pour la distribution des clés et des messages. Le réseau XMPP utilise des serveurs répartis et des identifiants indépendants de l’identité propre de l’utilisateur. Chaque utilisateur de XMPP est libre d’employer le serveur de son choix, dont la sécurité peut être catastrophique ou excellente. Une sécurité serveur excellente n’exempte cependant pas les utilisateurs de la nécessité de vérifier les clés cryptographiques.

Heureusement, grâce à la publication récente dans le domaine public des spécifications de X3DH et de Double Ratchet par les auteurs de Signal, de nombreuses applications peuvent s’équiper de ce cœur cryptographique robuste tout en faisant des choix d’infrastructures plus respectueux de la vie privée que ne le sont Signal ou WhatsApp.

Les arguments de l’éditeur de Signal concernant l’agilité d’un écosystème fermé, soumis aux décisions unilatérales des développeurs, sont certainement fondés. À l’instar du régime politique démocratique, les réseaux fédérés, comme XMPP, nécessitent des négociations, des ententes et des compromis. Le résultat peut cependant, au long cours, se montrer supérieur à la somme des idées exprimées par les différents intervenants de l’écosystème.

Ainsi, grâce la stabilité de sa spécification, sa licence ouverte, ses primitives cryptographiques à l’état de l’art et son architecture répartie, OMEMO offre aux utilisateurs de XMPP une méthode de communication protégée de bout en bout efficace, auditable, et potentiellement durable.


Pour le lecteur intéressé, l’application libre Conversations implémente OMEMO et des extensions permettant l’économie de la batterie du périphérique le faisant tourner 34. Un compte est optionnellement fourni à tout utilisateur faisant l’acquisition de l’application au travers du Google Play Store. Les utilisateurs d’iOS peuvent utiliser ChatSecure 35. Les utilisateurs PC peuvent, quant à eux, se tourner vers Gajim et son implémentation expérimentale d’OMEMO. Pour les utilisateurs souhaitant effectuer un auto-hébergement de leur serveur XMPP, Prosody 36 implémente la partie serveur des optimisations permettant des économies de batterie. Enfin, la Quadrature du Net fournit un service XMPP ouvert à tous 37.


5. Remerciements

Je tiens à remercier mes relecteurs : Piotr Chmielnicki, François Contat, Arnaud Ebalard, Sarah De Haro, Olivier Levillain, Mickaël Salaün, et Guillaume Valadon. Les idées exprimées dans cet article ne sauraient les engager.

6. Réferences

Publié par les Editions Diamond sous licence CC-BY-NC-ND.


  1. https://otr.cypherpunks.ca/ ↩︎

  2. https://www.rfc-editor.org/rfc/rfc4880.txt ↩︎ ↩︎

  3. https://whispersystems.org/docs/specifications/x3dh/ ↩︎

  4. https://whispersystems.org/docs/specifications/doubleratchet/ ↩︎

  5. https://xmpp.org/extensions/xep-0384.html ↩︎

  6. https://news.ycombinator.com/item?id=6913456 ↩︎

  7. https://cs.au.dk/~jakjak/master-thesis.pdf ↩︎

  8. https://isi.jhu.edu/~mgreen/imessage.pdf ↩︎

  9. https://www.ssi.gouv.fr/uploads/2015/05/format-Oracles-on-OpenPGP.pdf ↩︎

  10. https://www.cypherpunks.ca/~iang/pubs/mpotr.pdf ↩︎

  11. https://moderncrypto.org/mail-archive/messaging/2016/002275.html ↩︎

  12. https://whispersystems.org/docs/specifications/xeddsa/ ↩︎

  13. https://www.rfc-editor.org/rfc/rfc5869.txt ↩︎

  14. https://github.com/WhisperSystems/libsignal-protocol-java ↩︎

  15. https://whispersystems.org/blog/goodbye-encrypted-sms/ ↩︎

  16. https://github.com/LibreSignal/LibreSignal/issues/37 ↩︎

  17. https://silence.im/ ↩︎

  18. https://www.youtube.com/watch?v=lQ0I5tl0YLY ↩︎

  19. https://whispersystems.org/bigbrother/eastern-virginia-grand-jury/ ↩︎ ↩︎

  20. https://techcrunch.com/2016/07/19/whatsapp-blocked-in-brazil-again/ ↩︎

  21. https://whispersystems.org/blog/doodles-stickers-censorship/ ↩︎

  22. https://www.bamsoftware.com/papers/fronting/ ↩︎

  23. https://whispersystems.org/blog/contact-discovery/ ↩︎ ↩︎

  24. https://whispersystems.org/blog/safety-number-updates/ ↩︎ ↩︎ ↩︎

  25. https://support.whispersystems.org/hc/en-us/articles/213134107-How-do-I-verify-the-person-I-m-sending-messages-to-is-who-they-say-they-are- ↩︎

  26. https://gultsch.de/trust.html ↩︎

  27. https://www.rfc-editor.org/rfc/rfc7540.txt ↩︎

  28. https://tools.ietf.org/html/draft-ietf-tls-tls13-18 ↩︎

  29. https://eprint.iacr.org/2014/904.pdf ↩︎

  30. https://eprint.iacr.org/2016/1013.pdf ↩︎

  31. https://conversations.im/omemo/audit.pdf ↩︎

  32. https://media.ccc.de/v/33c3-8062-a_look_into_the_mobile_messaging_black_box ↩︎

  33. https://www.theguardian.com/technology/2017/jan/13/whatsapp-backdoor-allows-snooping-on-encrypted-messages ↩︎

  34. https://conversations.im ↩︎

  35. https://chatsecure.org/blog/chatsecure-v4-released/ ↩︎

  36. https://prosody.im ↩︎

  37. https://jabber.lqdn.fr ↩︎