TousAntiCovid Verif : vulnérabilité et développement défensif

L’application TousAntiCovid Verif sur Android nous a récemment régalé d’une vulnérabilité permettant d’afficher comme valides des pass sanitaires au format 2D-DOC manifestement invalides. Le bug n’intervient pas dans la vérification cryptographique de l’authenticité du pass sanitaire. Il se situe dans le reste du code métier qui vérifie la validité du pass, ne se déclenche que si l’appareil faisant tourner TousAntiCovid Verif utilise la locale anglaise.

Une vidéo de démonstration a été publiée par l’auteur de cet article. La démonstration a été effectuée avec la version 1.6.1 de TousAntiCovid Verif. La version 1.6.2 publiée le 4 août n’a pas corrigé la vulnérabilité.

Cet article propose d’étudier le bug, ses causes, et comment se protéger de tels bugs lorsqu’on pratique le développement défensif.

La vulnérabilité

Comme le code source de TousAntiCovid Verif n’a été publié que très tardivement, et que la vulnérabilité était présente dès cette publication initiale, il n’est pas possible de déterminer la date d’introduction du bug. En outre, tous les commits étant fusionné sous un unique commit à l’intitulé laconique “initial commit”, il n’est pas possible de faire une revue de code des changements dans le détail et de déterminer si l’auteur de ce bug a également commis d’autres impairs dans le code source de l’application. Bref, nous avons affaire à une parodie de code en sources ouvertes.

Toujours est-il que l’excellent @Gilbsgilbs a détecté, puis identifié la vulnérabilité. Elle se situe à aux lignes suivantes :

(oui, parce que non contents de faire un bug, ils font des copier-coller du bug pour être sûrs de l’avoir dans plusieurs branches de code…)

Au niveau le plus basique de l’analyse, le hic se situe sur le fait que status, en anglais, ne vaut pas Not Valid mais Invalid.

Cette variable est assignée ici : https://gitlab.inria.fr/tousanticovid-verif/tousanticovid-verif-android/-/blob/master/app/src/main/java/com/ingroupe/verify/anticovid/ui/result/ResultScanPresenterImpl.kt#L590

La valeur assignée à cette variable est, elle-même, assignée ici : https://gitlab.inria.fr/tousanticovid-verif/tousanticovid-verif-android/-/blob/master/app/src/main/java/com/ingroupe/verify/anticovid/service/document/StaticDataService.kt#L68

On peut noter que la valeur est issue d’un fichier de traduction : en français ou en anglais.

Le niveau zéro de la correction de cette vulnérabilité serait donc de remplacer Not Valid par Invalid… Mais il y a bien plus d’enseignements à tirer de cette erreur criante. Le reste de cet article s’attache à expliquer les stratégies de développement défensif visant à prévenir de ce genre de bugs.

Tester

Le code de TousAntiCovid Verif ne semble manifestement pas faire l’objet de tests unitaires (à l’exception de trois fichiers). Plusieurs indices le laissent penser. D’une part, il n’y a aucune trace de ces tests dans le dépôt de code source. Pour autant, on trouve des fichiers qui sont peu pertinents comme les fichiers de proguard pour rendre le code compilé moins facilement lisible par rétro-ingénierie. Cela pourrait donc laisser à penser qu’ils ont commité tout ce qu’ils avaient (à l’exception des fichiers exclus par .gitignore, et qui ne font pas mention des tests unitaires).

Ensuite, on peut voir que le code fautif était déjà présent dans le commit initial tandis que le fichier de langue contenant la chaine de caractères a été introduit dans un commit ultérieur. Il est donc probable que le code a été poussé en production, sans même avoir de fichier de langue de test pour vérifier que le code soit fonctionnel.

La première stratégie de développement défensif, qui constitue une bonne pratique standard de l’industrie, est de tester son code.

Utiliser les bons types (booléens) et les bonnes variables

Le code fautif effectue des comparaisons de chaines de caractères pour déterminer le statut de validité de la vérification cryptographique. La comparaison de chaines de caractère est fragile, en cela qu’elle repose sur la comparaison de nombreux octets qui doivent être tous justes pour que le test réussisse. À l’inverse, la comparaison d’une valeur booléenne ou même numérique (nulle ou non nulle, par exemple), aurait permis de discriminer de manière bien moins ambiguë et surtout moins susceptible à des erreurs comme celle vu dans TousAntiCovid Verif.

Le plus navrant avec TousAntiCovid Verif, c’est qu’il y a dans la même structure que celle dont est extraite cette chaine de caractères, un attribut isValid de type booléen et qui aurait pu être avantageusement utilisé pour ce test. C’est à se demander s’il y a eu une revue de code !

Utiliser des symboles plutôt que des littéraux

Comme discuté dans le point précédent, les chaines de caractères sont souvent des ennemis du code rigoureux. En effet, leur usage est bien souvent la cause de bugs lorsqu’elles contiennent de manière aléatoire des coquilles. Il est donc généralement considéré que leur usage sous la forme de valeurs hardcodées est une mauvaise pratique de développement. Il est généralement préférable d’utiliser des symboles de langages, comme des constantes nommées ou des symboles. L’usage de symboles présente l’avantage qu’en cas de coquille dans le nom du symbole : une erreur sera levée au moment de la compilation ou de l’interprétation, suivant le langage, et la coquille ne se traduira pas par une erreur de logique métier. Même Javascript, qui est un langage très souple, a un mode strict pour forcer la déclaration des variables, ce qui permet de détecter des coquilles dans les noms des variables.

Utiliser l’approche liste autorisée (“blanche”), plutôt que liste interdite (“noire”)

L’approche utilisée par le code fautif de TousAntiCovid Verif est celle de la liste interdite. En effet, le test vérifie que le status de validité du pass est “Non valide”. Si ce test échoue, alors le statut du pass est réputé valide. Cette approche a montré ses limites en de multiples occasions lors du développement d’applications sécurisées, car il est en général bien plus difficile d’envisager l’infinité des valeurs susceptibles d’être invalides, alors que les valeurs valides sont bien souvent en quantité très limitée.

Une manière de programmer de manière défensive le test fautif aurait été d’inverser sa nature : plutôt que de tester si le statut du pass est “Non valide”, il aurait été préférable de tester s’il n’était pas “Valide”. Ainsi, en cas d’oubli, de coquille, ou de toute autre raison inattendue, le résultat de la validation aurait été un échec et non un succès.

Émuler le pattern matching complet

Une méthode employée par des langages très rigoureux pour prévenir ce genre de bugs est également de proposer des instructions de contrôles exhaustives.

Par exemple, en Caml ou en Rust (parmi tant d’autres ; je ne fais que citer ceux que j’ai pratiqués), il existe du pattern matching dont l’exhaustivité des cas est vérifiée à la compilation. Si vous ne connaissez pas ce mécanisme, imaginez une sorte d’instruction switch qui refuse de compiler si tous les case possibles n’ont pas été énumérés.

Typiquement, ici, il aurait pu être pertinent d’utiliser une telle instruction de contrôle pour énumérer de façon exhaustive les cas “Valide”, “Non valide”, “Valid” et “Invalid” à l’exclusion de tout autre, sauf à encourir une erreur de compilation.

Même quand le langage ne dispose pas de telles instructions de pattern matching (ou même de switch !), il est possible de l’émuler.

Par exemple, en Python :

  if status in ["Non valide", "Invalid"]:
    handle_invalid_case()
  else if status in ["Valide", "Valid"]:
    handle_valid_case()
  else:
    raise NotImplementedError()

Employer les design patterns lorsqu’ils sont pertinents

Finalement, on peut noter que les développeurs de TousAntiCovid Verif n’ont absolument pas respecté les patrons de conception (“design patterns”) pourtant standard dans l’industrie. Je pense notamment à Model View Controler (MVC), introduit dans les années 80. En effet, les développeurs de TousAntiCovid Verif ont initialisé l’attribut status de type string de la structure DocumentSignatureResult avec le résultat d’une interrogation du module d’internationalisation. Cette initialisation est faite dès l’acquisition du code-barre 2D-DOC. Il s’agit donc d’une violation du patron MVC qui réserve l’affichage (éventuellement internationalisé) à la View, alors que l’initialisation du résultat de l’acquisition du code barre est clairement du code métier, devant être développé dans le Model.

Il est de bon aloi pour tout développeur, débutant ou moins débutant de se familiariser avec les patrons de conception classiques. Il est notamment chaudement recommandé de lire “Design Patterns: Elements of Reusable Object-Oriented Software”.

Conclusion

L’application TousAntiCovid Verif présente de nombreux signes d’une application développée sans respect des bonnes pratiques et des standards de l’industrie. L’absence de tests unitaires, et le manque de vigilance lors des revues de code (s’il y en a eu), indiquent également une très faible qualité code. Il est également permis de douter qu’un tel code ait été validé par l’ANSSI ou ait même subi un audit externe indépendant.

Compte tenu de la criticité de cette application dans la stratégie gouvernementale de déploiement universalisé du pass sanitaire comme panacée contre la COVID-19, et son installation sur les téléphones de centaines de milliers de citoyens/contrôleurs, il est regrettable de constater la faible qualité de son développement et l’incompétence manifeste de ses développeurs.

7 gestes barrières contre le pass sanitaire et pour préserver sa vie privée

Cet article présente une série de gestes barrières visant à lutter activement contre le pass sanitaire, et à préserver la confidentialité de ses données personnelles et médicales contenues dans le pass sanitaire.

Avertissement : je ne suis pas juriste. Tous les points listés ci-dessous me semblent légaux, au meilleur de mes connaissances actuelles, mais vous prenez vos responsabilités personnelles en les appliquant. Ce document ne constitue pas un conseil juridique.

1. Stratégie d’évitement : boycotter les lieux qui exigent le pass sanitaire

Le premier geste barrière est d’adopter une stratégie d’évitemment de l’emploi du pass sanitaire. En boycottant les lieux qui l’exigent, on créé une pression que nos gouvernants, adeptes du néolibéralisme, comprennent. Boycott = pas de revenu. Alors évidemment, certains diront que la stratégie d’évitemment est la seule option des non-vaccinés. Ce n’est pas faux. Mais c’est aussi une stratégie qui peut, et à mon sens doit, être entreprise par les vaccinés, par solidarité, et pour rejeter cette société de controle permanent qui nous est proposée. Nous sommes des citoyens, et nous méritons la liberté de choix, en conscience, et l’égalité en droit.

2. Stratégie d’obstruction : maximiser le temps requis pour faire le contrôle du pass sanitaire, sans toutefois refuser

Le deuxième geste barrière est à appliquer lorsque la stratégie d’évitemment n’est pas possible ou n’est pas appropriée. L’objectif reste le même : maximiser les pertes de profit, seul argument compris par les néolibéraux. Ce geste consiste à maximiser le temps requis pour qu’un controleur vérifie le pass sanitaire.

Même 10 secondes, multipliées par le nombre de personnes qui ont à présenter le pass sanitaire, cela créé des retards significatifs et un impact sur l’activité économique.

N’hésitez pas à présenter des pass sanitaires de type tests (PCR ou antigéniques) périmés (“oh, je me suis trompé ; le voici”), à baisser la luminosité du téléphone pour gêner la lecture du code barre. Galérez à trouver le bouton pour l’augmenter. Présentez une photocopie chiffonnée.

Tout ce qui montre que vous êtes en train de vous plier au contrôle mais qui cause un délai est bon à appliquer. En revanche, ne soyez pas agressif, ou violent, et ne refusez pas de présenter le pass, à moins d’appliquer au final la stratégie d’évitemment. Les contrôleurs suivent les instructions du gouvernement et préfèreraient sûrement faire le vrai métier. Blamez les vrais coupables du pass sanitaire.

3. Ne jamais diffuser son pass sanitaire, même partiellement masqué à des personnes n’ayant pas le besoin d’en connaitre

Votre pass sanitaire contient de nombreuses données personnelles et de santé. Il contient notamment, vos noms, prénoms, date de naissance. En outre la nature des données médicales qu’il contient dépend du type de pass que vous détenez. Pour un pass de type vaccinal, il contient des informations générales comme le nombre de doses reçues, le nombre de doses requises pour être protégé et un indicateur de complétion de votre parcours vaccinal. En outre, il contient le nom, la marque, l’agent prophylactique et la date d’injection du dernier vaccin reçu.

Ces informations sont lisibles par n’importe qui qui peut visualiser votre code barre et qui dispose d’un logiciel dédié. Certains sont librement accessibles sur le net. Cette petite vidéo vous en convainvra.

En outre, les code barres 2D (datamatrix et qrcode) contiennent des codes correcteurs d’erreurs. Un code correcteur d’erreurs, c’est un outil mathématique qui vise à compenser la destruction partielle du code barre. Dans le cas des qrcodes, c’est le même code correcteur d’erreurs que celui qui est utilisé sur les CD, pour compenser les micro-rayures, par exemple. Dissimuler une partie de votre code barre peut ne pas être suffisant pour empecher la lecture complète du code, et des données qu’il contient.

Finalement, la diffusion de son pass sanitaire avec l’intention d’encourager son emploi par un tiers est puni selon le code pénal de 75 000 € d’amende et de 5 ans de prison.

Le troisième geste barrière est donc de ne pas diffuser son pass sanitaire.

4. Privilégier le papier

Ce quatrième geste barrière consiste à ne pas numériser son pass sanitaire afin de limiter les risques de sa diffusion. Utiliser le pass sanitaire au format papier limite sa diffusion aux moments où vous sortez le pass de votre poche.

Si votre poche n’est pas un endroit sûr (?), alors un téléphone avec un code d’accès fort peut éventuellement mieux le protéger. Notez bien que vous n’avez pas besoin d’installer TousAntiCovid sur votre téléphone pour numériser le pass sanitaire. TousAntiCovid ne présente aucun intérêt particulier pour la numérisation du pass sanitaire. Une simple photo suffit ! Attention cependant à ne pas la stocker dans un dossier synchronisé avec le cloud (e.g. Google Photos). Si vous êtes d’humeur très prudente, il existe des logiciels qui permettent de stocker les photos de manière chiffrée sur votre téléphone. Rien que s’envoyer à soi-même (pléonasme pour insister sur le fait de ne pas communiquer son pass à un tiers) la photo avec un logiciel de messagerie comme Signal peut faire l’affaire.

5. Vérifier le logiciel utilisé par le controleur

Comme détaillé plus haut, votre pass sanitaire contient de nombreuses données personnelles et médicales. Or, vous devez les présenter à des inconnus. Comment leur faire confiance pour qu’ils ne stockent pas ces données à des fins commerciales, marketing, ou statistiques. La loi les en défend, mais si personne ne vérifie, il y a fort à parier que cela sera fait. Contrôlez les controleurs !

Ce cinquième geste barrière consiste à exiger du controleur qu’il lance l’application de vérification (par exemple TousAntiCovid Verif) depuis l’app store, devant vos yeux. Si le controleur refuse, insistez (stratégie d’obstruction). Finalement, en cas de refus ferme, appliquez la stratégie d’évitemment : il en va de la sécurité de vos données personnelles et médicales.

6. Refuser la vérification d’identité par les personnes non habilitées

Le contrôle d’identité est un acte qui ne peut être effectué que par certains membres des forces de l’ordre. Aucun contrôleur de pass sanitaire employé par le secteur privé, ni même certains agents des forces de l’ordre ne sont habilités à contrôler votre identité.

En conséquence, ce sixième geste barrière consister à refuser de présenter sa carte d’identité ou tout autre justificatif d’identité à ces personnes. Appliquez la stratégie d’obstruction en cas de refus, et faites intervenir les forces de l’ordre.

Lors d’un contrôle d’identité par les forces de l’ordre, privilégiez la preuve d’identité par témoignage, si vous êtes dans un groupe d’amis, plutôt que de présenter vos papiers d’identité. C’est peu connu, mais des personnes attestant de votre identité sont suffisantes pour satisfaire un contrôle d’identité. Il n’y a pas besoin de présenter des titres émis par l’État.

7. Ne pas convertir son pass avec TousAntiCovid

EDIT du 4 août 2021 : ce geste barrière n’est plus nécessaire. La version 3.6.0 de TousAntiCovid introduit un mécanisme de protection des données pendant leur transfert, préservant leur confidentialité lors de leur passage via les serveurs américains.


L’application TousAntiCovid permet la conversion des pass sanitaires français, au format 2D-DOC (datamatrix) en pass européens, de type DCC (Digital Covid Certificate). Cette conversion s’effectue par l’envoi du pass sanitaire à un serveur central, via des serveurs américains, qui peuvent voir le contenu du pass sanitaire dans son intégralité.

Ce septième geste barrière consiste donc à ne pas utiliser TousAntiCovid pour effectuer cette conversion. À la place, rendez vous sur Ameli.fr pour télécharger votre pass au format européen, ou rendez vous dans un centre de vaccination ou une pharmacie.

Conclusion

Je doute qu’il y a ait un jour une chanson de Mc Fly et Carlito pour diffuser ces gestes barrières, mais je vous encourage à les faire connaitre. N’hésitez pas à redistribuer cet article. Vous pouvez le republier, le commenter, en faire des travaux dérivés. Sa licence est CC-0.

Si vous souhaitez me contacter, je suis disponible sur Twitter ou le Fédiverse.

Merci à toutse de m’avoir lu.

Vive la Nation !


BONUS : gestes barrières relatifs à TousAntiCovid Signal

Limiter la diffusion d’informations personnelles dans les carnets de rappel (TousAntiCovid Signal)

Lorsque l’on se rend dans certains lieux, il est requis de s’enregistrer soit avec l’application TousAntiCovid en scannant un QRCode de l’établissement, soit en ajoutant ses informations de contact dans un carnet de rappel papier.

Dans le carnet de rappel papier, il est demandé de renseigner son nom, prénom, et une information de contact (généralement le numéro de téléphone).

Ce geste barrière consiste à donner de faux noms et prénoms, car ils ne sont pas utiles pour la finalité du traitement, et une adresse email à la place du numéro de téléphone. Cette adresse email peut être une adresse email temporaire, comme celles proposées par le service Yopmail. Ainsi, vous restez contactables en cas de cluster, mais vous ne diffusez aucune information personnelle durable. Si la personne en charge de l’enregistrement dans le carnet de rappel refuse l’usage d’une adresse email, prétexter que vous n’avez pas de téléphone, ou que vous êtes sur un numéro temporaire car vous changez d’opérateur.

Utiliser ou non TousAntiCovid Signal avec prise de photo d’un QRCode est un sujet complexe en matière de respect de la vie privée ; il y a du pour et du contre. Il n’est donc pas possible de donner une recommandation universelle quant à son emploi ou non.

Régénérer très fréquemment les QRCodes TousAntiCovid Signal

Si vous êtes gestionnaire de lieux devant afficher des QRCode TousAntiCovidSignal, ce geste barrière consiste à renouveller le plus fréquemment possible le QRCode que votre clientèle peut scanner. Un bon rythme pourrait être une fois par jour, à intégrer dans les gestes du quotidien lors de l’ouverture de l’établissement.

Changer le code régulièrement aide vos clients à préserver leur vie privée lorsqu’ils se déclarent malades. Cela limite la possibilité de désanonymiser le malade, et de tracer ses lieux de fréquentation d’une manière disproportionnée par rapport à la finalité de détection de clusters. 

Vacciné et contre le pass sanitaire

Un billet d’humeur contre l’extension du pass sanitaire, son principe en général et ses dérives autoritaires.

Je suis contre le pass sanitaire, et je suis pourtant vacciné.

Comme il semble importer à certains de comprendre qui parle pour ensuite savoir l’écouter, voici un court résumé sur ma personne. Les gens intéressés uniquement par le fond peuvent sauter la prochaine section de ce billet.

Qui suis-je ?

Je suis Florian Maury. J’ai 38 ans, et je suis en surpoids (IMC 29.5), sans autre comorbidité connue. Je ne suis ni rattaché, ni sympathisant d’aucun parti politique. Mon seul engagement politique significatif est l’antispécisme.

Pendant la pandémie, mon emploi a été maintenu et j’ai pu le continuer, en bénéficiant du télétravail à 100%. Ce jour encore, je suis en télétravail.

Ma compagne, elle, travaille avec des enfants et est donc exposée à un risque de contamination plus important que d’autres corps de métier.

J’ai fait le choix de me vacciner parce que j’ai considéré les risques de ne pas me vacciner, et ceux de me vacciner, et j’ai jugé que la balance bénéfices/risques, dans mon cas, penchait vers l’intérêt d’être vacciné. C’est un calcul personnel, effectué exclusivement sur des considérations égoïstes, et à aucun moment pour protéger les autres. À ma place, vous auriez pu faire un choix différent ; chacun son corps.

Pour protéger les autres, je respecte les gestes barrières depuis la première heure. J’ai porté un masque, conformément aux directives sanitaires, y compris en forêt, lorsque je croisais d’autres promeneurs (ce qui pourra paraître hygiéniste à certains). En fait, je portais même un masque dans les transports en commun et sur mon lieu de travail AVANT la pandémie de covid-19, lorsque j’étais malade. Par respect pour mes collègues de travail, et mes compagnons de voyage de la région parisienne.

Quels sont les problèmes du pass sanitaire ?

Le pass sanitaire présente de nombreux problèmes, sur le plan technique, sur le plan juridique et sur le plan éthique. Dans ce billet, il pourra être question du vaccin, puisque les deux sont quasiment indissociables depuis les annonces d’Emmanuel Macron, ce 12 juillet 2021.

Aspect technique

Depuis la parution du pass sanitaire, de nombreuses critiques sont formulées sur sa réalisation technique.

Dans cet article, Piotr Chmielnicki et moi-même avons analysé le contenu du pass sanitaire, et l’avons comparé aux annonces gouvernementales, aux déclarations sur les sites gouvernementaux, et à l’avis de la CNIL.

Nous avons révélé que le pass contenait de nombreuses informations sans rapport avec la finalité du pass, dont des informations médicales, et des informations affectant la vie privée, et pouvant causer des risques dans le cadre du vol d’identité. Ces affirmations ont été confirmées par de nombreuses études indépendantes et publiées à la même période. On pensera à celle de Mathis Hammel, celle de Christian Quest, aux excellentes analyses de TousAntiCovid Verif par Gilbsgilbs, ou à l’implémentation de preuves de concept comme sanipasse.fr et celle de Bastien Le Querrec, de la Quadrature du Net.

Il est intéressant de noter que dans son avis du 12 mai, la CNIL disait d’ailleurs à juste titre :

  1. La Commission estime que l’accès à un lieu ne saurait, par principe, être conditionné à la divulgation d’informations relatives à l’état de santé des personnes, y compris s’agissant de lieux qui n’ont pas trait à la vie quotidienne. En effet, si la vérification de l’identité des personnes peut être exigée pour l’accès à certains lieux, l’exigence de divulgation d’autres informations relatives à la vie privée des personnes, a fortiori de données sensibles, ne saurait être admise qu’au regard de la nature du lieu ou de l’événement fréquenté et dans le cadre de la stricte application du principe de minimisation de la collecte de ces données. La possibilité d’accéder aux lieux de sociabilité sans avoir à prouver son état de santé fait partie des garanties apportées à l’exercice des libertés et participe à dessiner une frontière raisonnable entre ce qui relève de la responsabilité individuelle et du contrôle social.

En outre, principalement grâce à Gilbsgilbs, le peuple français a pu prendre conscience que TousAntiCovid Verif fuitait de manière systématique, à chaque scan d’un pass, le contenu de ce pass sanitaire (c’est-à-dire nos données privées et de santé) à un acteur américain (Akamai), puis à une société française : IN Groupe, l’imprimerie nationale. L’application TousAntiCovid Verif pouvait donc être transformée en une application de surveillance de masse, permettant de savoir qui se rendait où et quand. Cette fuite de données était, par ailleurs, parfaitement injustifiable d’un point de vue technique, d’après de nombreux spécialistes en cryptographie. D’ailleurs, Olaf et le créateur de sanipasse.fr l’ont prouvé en fournissant au public des vérificateurs de pass sanitaires hors-ligne, c’est-à-dire sans connexion à Internet nécessaire. En outre, TousAntiCovid Verif contenait des logiciels de tracking des utilisateurs provenant de Google.

De nombreux journaux ont relayé l’information, parmi lesquels NextInpact, Numerama, 01net, Mediapart, Contrepoints, Le Monde Informatique. Il y eut aussi d’autres formes de relais dont Developpez ou iGeneration. Finalement, le gouvernement a annoncé, lors d’une conférence de presse, l’élaboration dans l’urgence d’un mode “offline” (hors-ligne). Cette version avec un mode offline a été mise en ligne deux jours après. À ce jour, le code source de TousAntiCovid Verif n’a toujours pas été publié, contrairement aux annonces gouvernementales effectuées durant cette même conférence de presse.

Depuis, Olaf et Gilbsgilbs ont pu noter que la fonctionnalité de conversion des pass sanitaires français en pass sanitaires européens, par l’entremise de TousAntiCovid, avait recours à l’envoi du pass sanitaire dans son intégralité, toujours via les serveurs américains d’Akamai, puis via les serveurs d’IN Groupe.

Le gouvernement a annoncé une migration vers Orange, afin d’éviter la fuite des données en Amérique. À l’instar de la publication du code source de TousAntiCovid Verif, le cierge est allumé…

Aspect juridique

Le pass sanitaire présente de nombreuses faiblesses juridiques.

Pour commencer, le pass sanitaire a failli être retoqué par le Parlement puisqu’il a été nécessaire de faire deux votes, le premier ayant eu pour résultat son rejet. C’est au prix d’amendements, à l’initiative du Modem, visant à restreindre la durée du pass, que celui-ci a été finalement accepté par le Parlement.

Parmi les dysfonctionnements persistants, on note ainsi dans la loi n° 2021-689 du 31 mai 2021 relative à la gestion de la sortie de crise sanitaire :

La présentation, sur papier ou sous format numérique, des documents mentionnés au premier alinéa du présent B est réalisée sous une forme ne permettant pas aux personnes habilitées ou aux services autorisés à en assurer le contrôle de connaître la nature du document ni les données qu’il contient.

Or il se trouve que le pass sanitaire est librement lisible par tous, à l’aide d’un lecteur de code barre 2D, et qu’il contient les noms, prénoms, date de naissance, date de la dernière injection, agent prophylactique, état du cycle vaccinal, et nom et marque du vaccin, dans le cas d’un pass sanitaire de type vaccinal. Des informations différentes sont présentées dans le cas d’un pass sanitaire de type test. Le pass est donc contraire à cette loi en cela qu’il permet aux personnes habilitées ou aux services autorisés à en assurer le contrôle de connaître la nature du document et les données qu’il contient. Peu importe que l’application TousAntiCovid Verif dissimule certaines informations ; n’importe quel lecteur de code barres peut en révéler le contenu intégral.

En outre, il est attendu, pour qu’il soit efficace, que les personnes habilitées ou les services autorisés à en assurer le contrôle puissent vérifier l’identité du porteur du pass, notamment en comparant les noms, prénoms et date de naissance du pass avec ceux sur une pièce d’identité. Or, la vérification de l’identité d’une personne est encadrée par la loi. En l’occurrence, sur le site Services Publics.fr, on peut lire que le contrôle d’identité est limité aux personnes suivantes :

Les forces de l’ordre (police, gendarmerie) habilitées à faire un contrôle d’identité sont les suivantes :

  • Officier de police judiciaire (OPJ)
  • Agents de police judiciaire, sous la responsabilité de l’OPJ
  • Certains agents de police judiciaire adjoints, sous la responsabilité de l’OPJ Un douanier peut aussi faire un contrôle d’identité dans certains cas. A savoir : un agent de police municipale peut relever votre identité lorsqu’il constate une contravention. Par exemple, une contravention de stationnement. Toutefois, il n’est pas autorisé à contrôler votre identité.

Il convient donc de noter que ni les barmen, ni les restaurateurs, ni les agents de sécurité des boîtes de nuit, des centres commerciaux, des hôpitaux, des cinémas et théâtres, ou d’aucun lieu de loisirs ne sont habilités à demander aux citoyens français leurs papiers d’identité pour en faire le contrôle. Alexandre Horn informe également dans ce sens, dans les colonnes de Libération.

Par ailleurs, la Quadrature du Net a saisi le Conseil d’État, le 9 juin, à propos du pass sanitaire, via la procédure de référé-liberté. Bien que le Conseil d’État soit censé rendre un verdict en deux jours, dans ce cadre de procédure, il a fallu attendre près d’un mois pour obtenir un jugement. Il s’agit là d’un délai noté comme anormalement long par de nombreux juristes, même dans les circonstances exceptionnelles de cette pandémie.

Le verdict du Conseil d’État, rendu le 6 juillet a soigneusement évité d’adresser certains points cruciaux de la plainte, a énoncé des banalités sans rapport avec la plainte (avaient-ils perdu le dossier ?), et n’a finalement pas suspendu le pass sanitaire pour les raisons suivantes (liste non exhaustive) :

  • “Il résulte de l’instruction et il n’est d’ailleurs pas contesté que le traitement TousAntiCovid Vérif effectivement mis en oeuvre par le ministre de solidarités et de la santé repose sur un contrôle local des données contenues par les justificatifs (” mode off-line “), et que le Gouvernement a renoncé à tout échange de données avec le serveur central de la société prestataire lors de la vérification des justificatifs présentés sur le téléphone mobile de la personne entendant se prévaloir du passe sanitaire”. On notera que ce “renoncement” du gouvernement coïncide avec les révélations faites par le groupe de citoyens mentionnés dans la section “Aspects techniques” de ce billet.

  • “Son usage a été restreint aux déplacements avec l’étranger, la Corse et l’outre-mer, d’une part, et à l’accès à des lieux de loisirs, d’autre part, sans que soient concernées les activités quotidiennes ou l’exercice des libertés de culte, de réunion ou de manifestation”.

Or, avec l’extension du pass sanitaire annoncée par le Président de la République ce 12 juillet 2021, soit 6 jours après le verdict du Conseil d’État, il apparaît très clairement que le contexte sanitaire n’a pas changé du tout au tout en ces 6 jours, et que le pass concerne désormais les activités quotidiennes.

Sur le plan juridique, il y a également la question de la proportionnalité de l’atteinte à la liberté de circulation, et au principe d’égalité, au vu de l’objectif. Étant donné que la France est l’un des rares pays à avoir choisi de déployer un tel dispositif généralisé, il me semble raisonnable d’en douter. Hélas, comme l’explique Dominique Bompoint dans son article dans Le Figaro, il n’y a rien à attendre du Conseil Constitutionnel.

Le recours déposé par Piotr Chmielnicki auprès de la CNIL, avec en copie le Défenseur des droits, n’a pas abouti. Le Défenseur des droits s’est défaussé en pointant vers son article à ce sujet, publié en mai, à une date antérieure à la plainte, et qui ne répond à aucun des éléments techniques avancés dans la plainte. On peut notamment y lire “Le projet de loi a fait l’objet de modifications par le Sénat, maintenues par la commission mixte paritaire, dont certaines vont dans le sens des recommandations de la Défenseure des droits, en particulier l’intégration dans le texte de garanties complémentaires concernant le « pass sanitaire », en vue de protéger les droits et libertés, notamment les données de santé”. Or, il s’avère que même si la loi contient effectivement ces garanties, l’implémentation du pass sanitaire par le gouvernement français en fait fi. Le Défenseur des droits n’a donc visiblement pas jugé utile de vérifier. La CNIL n’a fait qu’accuser réception, plus d’un mois après le dépôt de plainte. Elle n’a pas statué sur le fond pour le moment, près de deux mois après la réception du recommandé avec accusé de réception.

Aspect éthique

Le pass sanitaire devient moralement un pass vaccinal. En effet, le déremboursement des tests sans prescription médicale revient à ce que les personnes ne souhaitant pas se faire vacciner, ou ne le pouvant pas pour raisons de santé, soient contraintes de se vacciner, ou à débourser plusieurs centaines d’euros par mois, pour vivre normalement. Il s’agit là d’une violence sociale, particulièrement grave, contre les personnes en situation de précarité, ou en situation de santé complexes. Criant est le manque d’humilité des instances dirigeantes sur leur capacité à capturer l’infinie complexité des situations individuelles et à asséner une solution universelle.

Le pass sanitaire va donc créer deux castes de citoyens : les vaccinés et les non-vaccinés. Le Président de la République soulignait d’ailleurs lors d’un entretien : “Vos droits ne peuvent pas être les mêmes parce qu’ils supposent des devoirs”. Dès lors, la notion d’égalité, énoncée par la Constitution française, vole en éclat. Cette division participe, d’ailleurs, à créer des tensions entre citoyens, et détourne l’ire de la foule de la caste des dirigeants vers celle des non-vaccinés. Cette diversion participe activement à dédouaner et déresponsabiliser la caste politique de la situation actuelle, alors qu’ils en sont les premiers fautifs.

Hélas, les pauvres hères de la caste des non-vaccinés (ou devrait-on les appeler “intouchables” ?) ne seront pas tous relégués ainsi par choix. Même en admettant que tous souhaitent se faire vacciner, il n’y a pas assez de doses pour vacciner toute la population âgée de 12 ans et plus. Avec 50 millions d’adultes âgés de 20 ans et plus, il faudrait au minimum 100 millions de doses pour tous les vacciner. C’est faire l’hypothèse qu’aucune dose n’a été perdue, et qu’il faut deux doses pour chaque personne. Or, depuis le début de la pandémie, la France n’a reçu que 71 millions de doses. Bien que nous soyons censés en recevoir 9.6 millions d’ici fin juillet, et 14 millions en août (source : JT de France 2 du 17 juillet), le chiffre de 100 millions ne sera pas atteint. Et c’est sans compter la vaccination des 12 à 20 ans. Le gouvernement a donc choisi délibérément, et en connaissance de ces chiffres publics, une stratégie qui plongera des millions de citoyens dans la difficulté, qu’ils soient pour ou contre le vaccin, et pour ou contre le pass sanitaire. Une stratégie antisociale, déshumanisante, déresponsabilisante, infantilisante.

Finalement, on peut s’interroger sur le caractère éthique d’un très haut taux de vaccination dans les pays développés, imposé par le gouvernement en France avec le pass désormais vaccinal, quand 87% de la population mondiale n’a pas reçu deux doses. Freinerait-on plus efficacement l’épidémie en diminuant la propagation du virus (et donc ses chances de mutation, qui affecteront également les vaccinés du premier monde) dans les pays du tiers monde ? Probablement.

Conclusion

Le pass sanitaire, maintenant devenu pass vaccinal, représente à lui seul la déchéance de tous les principes énoncés par notre devise nationale. Séparation des citoyens en castes ; privation de libertés pour les non-vaccinés volontaires et involontaires ; obligation vaccinale pour certains corps de métiers, sous peine d’être licenciés de plein droit ; tensions accrues entre les citoyens menant à des actes de violences et de vandalismes. La défaite est totale. L’individualisme est la règle, et dès lors que certains ont leur fameux sésame, ils se contrefichent, et pire, jugent, leurs compatriotes, au lieu de se montrer solidaires et de comprendre qu’ils seront peut-être les prochains exclus, au détour d’une nouvelle loi liberticide des gouvernants.

Un passeport n’a jamais été le symbole de la liberté. Un passeport est un passe-droit accordé à des personnes qui peuvent outrepasser une nouvelle règle restrictive, afin que leurs détenteurs puissent continuer de procéder comme avant. N’oublions jamais les laissés pour compte qui ne jouissent pas de ce passe-droit, et souvenons-nous que nous serons peut-être les prochains à être laissés sur le carreau.

Je souhaiterais terminer ce billet avec le cri du Général Kellermann lors de la bataille de Valmy, où les forces prussiennes ont été repoussées par l’armée des citoyens : “Vive la Nation !”. Faisons trembler la terre, et pourquoi pas l’Élysée !

Pass sanitaire et vie privée : quels sont les risques ?

Cet article est sous licence CC-BY-ND.

Auteurs :

Les auteurs de cet article peuvent être contactés :

  • par email : florian.maury-pass-sanitaire VOUS-SAVEZ-QUOI broken-by-design.fr

  • par chat, avec Matrix : #pass-sanitaire:matrix.piotr.paris


Mise à jour importante du 10 juin 2021 : l’application TousAntiCovid Verif, dans sa dernière version à la date d’écriture de cette ligne, ne fait plus appel à un serveur centralisé pour valider les pass sanitaires. Elle n’envoie plus de données à un prestataire américain. Elle ne contient plus de services Google Firebase. Hélas, le reste de l’article et de la vidéo continuent d’être pertinents pour l’heure. La Quadrature du Net effectue une action en justice en ce sens.


Il existe une vidéo compagnon, pour ceux qui préfèrent regarder que lire.

Sur Peertube :

En téléchargement : Haute qualité (1300MB) / Faible qualité (90MB)


Ce document porte sur le pass sanitaire, qui est en train d’être mis en place par le gouvernement français et qui entrera en vigueur le 9 juin 2021. Il vise à mettre au jour de fausses informations diffusées par certains membres du gouvernement, à expliquer et à illustrer pourquoi le pass sanitaire, tel qu’il est conçu, met en danger la vie privée, mais aussi des données médicales des citoyens. En outre, il accroit le risque de vol d’identité.

Le pass sanitaire est présenté sous la forme d’un code barre en deux dimensions, appelé datamatrix. Ce code barre, comme son nom l’indique, encode des informations. Il est en cela similaire aux codes barres des produits que vous achetez en grande surface, et que vous passez à la caisse. Il est juste en deux dimensions et contient plus d’information. Au lieu d’un numéro qui sert à indiquer à la caisse enregistreuse la nature du produit que vous achetez, ce qui lui sert à connaitre le prix à imputer, le code barre du pass sanitaire contient vos informations personnelles et des informations relatives à la vaccination. L’encodage de ces informations ne constitue pas une mesure de protection des données puisque n’importe qui équipé d’un dispositif de lecture de code-barres peut acquérir les données qui ont été encodées. Le pass sanitaire ne fait pas exception.

D’après le site Service Public.fr, le pass sanitaire contient les informations suivantes :

  • nom, prénom ;
  • date de naissance ;
  • type de certificat et résultat éventuel (test PCR ou antigénique ou vaccination première et seconde dose) ;
  • type de vaccin le cas échéant ;
  • date et heure du certificat.

Le site gouvernement.fr indique la même liste.

Nous avons analysé le contenu du pass sanitaire, à l’aide d’outils grands publics, trouvables sur n’importe quel Store d’applications, comme le Google Play Store ou l’Apple Store. Par exemple, Barcode Scanner de ZXing Team sur le Google Play Store.

Nous affirmons que la liste dressée par les sites gouvernmentaux est incomplète.

Le pass est composé de 3 types d’informations :

  • des informations techniques, qui permettent de vérifier l’authenticité du pass sanitaire ; on y retrouve des informations sur l’émetteur du pass sanitaire, ainsi que la date d’émission, et le sceau d’authenticité (une signature numérique) ;
  • des informations personnelles : nom, prénom et date de naissance ;
  • des informations de santé : le type de molécule injectée, le nom du vaccin reçu, le nombre de doses reçues, la date de vaccination et si ce nombre est suffisant pour être protégé de manière optimale pour la personne vaccinée.

Décomposition du pass sanitaire

Au-delà de ces informations de santé, il est également possible d’inférer des informations de santé encore plus privées sur certains citoyens : ont-il déjà été infectés par la COVID-19 (besoin que d’une seule dose) ? Sont-ils immunodéprimés (besoin de trois doses) ? Sont-ils parmis les citoyens prioritaires pour recevoir des injections tôt dans le calendrier vaccinal ?

Ces informations dépassent largement le cadre et la finalité du pass sanitaire.

Les sites gouvernementaux (comme gouvernement.fr et servic public.fr) se veulent cependant rassurants. Ils précisent :

Pour accéder à un lieu, un établissement ou un événement, seuls les ouvreurs engagés par les organisateurs pourront lire :

  • nom et prénom ;
  • date de naissance ;
  • accès autorisé ou accès refusé, en fonction des règles sanitaires imposées pour accéder au lieu (les ouvreurs ne pourront pas connaître le détail du type de certificat sanitaire présenté).

De même, M. Cédric O, secrétaire d’État, chargé de la transition numérique, indique dans son interview exclusive donnée au journal Le Parisien :

Comment les professionnels vérifieront-ils le pass sanitaire numérique ?

D’ici le 9 juin, nous aurons déployé l’application de lecture appelée TousAntiCovid Verif. Pour les compagnies aériennes, il y aura une version spécifique car elles ont obligation d’avoir accès au contenu détaillé, avec la date de vaccination, le type de vaccination etc. Elles pourront la télécharger sur les stores, avec un contrôle d’accès par identifiant. En revanche, les organisateurs d’évènements ou les lieux concernés par le pass sanitaire en France, ne connaîtront pas ces informations. Ils ne sauront que le nom, le prénom et la date de naissance de la personne concernée et ne verront apparaître que « vert » ou « rouge » pour valider ou non l’accès. Pour eux, l’application sera en accès libre sur les stores.

Comme nous l’avons démontré plus tôt dans ce document, il n’existe aucune protection contre l’obtention de l’ensemble des données contenues dans le pass sanitaire. Tout lecteur de code barre grand public est suffisant. Il n’est nul besoin d’être membre d’une compagnie aérienne pour obtenir une application aux pouvoirs supérieurs permettant d’acquérir des informations de santé sensibles sur une personne qui exposerait volontairement ou par mégarde son pass sanitaire, sur Internet, dans une file d’attente, ou à un personnel de sécurité à l’entrée d’un événement.

Il existe également d’autres parties qui pourraient être mises au courant du contenu de votre pass sanitaire. D’après un tweet du compte TousAntiCovid du 20 mai 2021:

#COVID19 | Les autorités compétentes peuvent lire vos certificats de tests avec l’application #TousAntiCovid Verif. Seule la signature du certificat est vérifiée par un serveur dédié d’@IN_Groupe respectant toutes les règles de sécurité des systèmes d’information.

Cette assertion est également corroborée par la demande de l’application TousAntiCovid Verif d’avoir un accès complet au réseau, lors de son installation. De même, on trouve dans les entrailles de l’application TousAntiCovid Verif, une URL (https://portail.tacv.myservices-ingroupe.com), et ainsi qu’un fichier comportant une fonction call2dDoc, qui fait une requête HTTP avec des paramètres 2ddoc, latitude et longitude. Enfin, lorsque l’on scanne un pass sanitaire en mode avion, TousAntiCovid Verif affiche un message d’erreur “Erreur de connexion” et n’affiche pas de résultat.

Il n’est pas aisé de déterminer clairement ce que fait cette fonction, car l’application TousAntiCovid Verif, contrairement à l’application TousAntiCovid, n’est pas en sources ouvertes. Néanmoins, gilbsgilbs a su faire de l’ingénierie inverse et il confirme nos craintes et observations.

Il convient de noter qu’une telle communication réseau génère des meta-données de communication avec le serveur ; il y a notamment l’adresse IP de l’équipement faisant tourner l’application TousAntiCovid Verif. Cette adresse IP permet la géolocalisation de l’équipement faisant tourner TousAntiCovid Verif, par l’entremise des opérateurs de télécommunication, comme Orange.

En croisant ces données, l’État serait donc en mesure de dresser un listing des citoyens et de leurs lieux de fréquentation, grâce au pass sanitaire.

Il convient de noter que l’envoi des données (complètes ou sous la forme d’empreintes cryptographiques) n’est nullement nécessaire pour la vérification de la signature numérique du pass sanitaire. Toutes les informations nécessaires à cette vérification sont publiques. La validation du pass sanitaire peut donc être accomplie sans problème directement par l’application de lecture du code barre. Si un lecteur de code barre est jugé par le gouvernement comme étant suffisamment de confiance pour lire les données médicales et afficher un verdict, il l’est aussi pour la vérification de la signature.

Nous ne sommes pas les seuls à dénoncer le pass sanitaire, et la quantité d’informations qu’il recèle. La CNIL, la Commission Nationale Informatique et Liberté, a été saisie et a rendu un avis le 12 mai 2021 :

  1. La Commission considère qu’un dispositif visant à ne permettre la vérification que sur la base d’un résultat de conformité réduirait considérablement les données accessibles aux personnes habilitées à vérifier le statut des personnes concernées, et notamment de ne pas indiquer si elle a été vaccinée, a fait un test ou s’est rétablie d’une infection antérieure à la COVID-19, conformément au principe de minimisation des données

  2. Un tel dispositif implique le téléchargement, du côté des vérificateurs, d’une application permettant de décoder les signaux, probablement sous forme de code-QR, qui contiendront l’information permettant de faire apparaître un résultat vert ou rouge et d’en vérifier l’authenticité. Dans l’hypothèse où ce code-QR correspondrait aux codes actuellement disponibles dans la fonctionnalité « TousAntiCovid Carnet », la Commission relève que celui-ci contient plus d’informations (nom, prénom, date de 8 naissance, date d’examen, type d’examen, résultat). Il est donc possible, dans ce cas, qu’un tel dispositif soit détourné de façon à ce que le lecteur (téléphone ou lecteur dédié) lisant le code-QR puisse accéder à davantage d’informations qu’un simple résultat de conformité (couleur verte ou rouge). Elle invite le Gouvernement à s’assurer de la mise en œuvre des mesures opérationnelles et à fournir, aux personnes gérant les lieux, événements et établissements toute documentation nécessaire (communication sur les lieux, établissements ou évènements soumis au dispositif, mise en place d’une signalétique visible sur place, etc.) permettant de se prémunir de ce risque.

Hélas, aucune “mesure opérationnelle” significative n’a été mise en place par le gouvernement. Il aurait, par exemple, été possible d’émettre plusieurs pass, contenant plus ou moins d’information, en fonction du type de lieu (e.g. salles de spectacle ou aéroports). Cela aurait été, de surcroit, conforme au principe de minimisation des données en regard de la finalité, comme indiqué par la CNIL ou par le Règlement Général de la Protection des Données (RGPD).

Nous affirmons donc, que la mise en oeuvre du pass sanitaire, en l’état, constitue un risque significatif pour la vie privée, pour les données personnelles (risque de vol d’identité accru) et pour les données médicales des citoyens.

Nous affirmons qu’il contient des informations sensibles sans aucun rapport avec la finalité énoncée.

Nous affirmons qu’il peut être détourné pour pister les citoyens.

Nous demandons le retrait du pass sanitaire dans sa forme actuelle.

Nous invitons les citoyens français à rejoindre cet appel et à déposer une plainte auprès de la CNIL et du défenseur des droits contre le pass sanitaire dans sa forme actuelle.

Nous invitons les citoyens européens et les responsables politiques à s’opposer au pass sanitaire européen qui est peu ou prou calqué sur le pass sanitaire français, avec les mêmes informations, les mêmes dérives et les mêmes risques. 

Si un nouveau pass sanitaire français est créé, nous exigeons le retrait des informations qui sont sans rapport avec la finalité. Si certaines informations sensibles doivent figurer dans le pass sanitaire, plusieurs pass doivent être remis en fonction du besoin d’en connaitre des employés de sécurité filtrant l’accès à un lieu.

Finalement, nous exigeons que la vérification de l’authencité du pass sanitaire s’effectue localement par une application de vérification en source ouverte, sans avoir besoin de la permission d’accès au réseau. 

M. Cédric O s’indigne, dans son interview au Parisien :

Il y a une forme d’aberration dans la crispation sur ces sujets-là. Comme si nous avions si peur de la solidité de notre démocratie et de notre état de droit, qu’on ne puisse pas se doter de ces outils.

Nous affirmons que la confiance ne s’exige pas, mais qu’elle s’acquiert. Nous affirmons que son acquisition passe par la vérité, la transparence, et des actes en accord avec les paroles et les engagements. Sur ce point, le pass sanitaire est un échec.

De surcroit, les risques de détournement ou de mésusage évoquées dans ce document devraient au minimum avoir été considérés avec circonspection par les responsables politiques. S’ils l’avaient été, le pass sanitaire dans sa forme actuelle aurait été rejeté selon le principe de prudence, au nom de la protection des citoyens.


Autres documents :


Remerciements : Aurélien Hugues, Émilie Gill, Stéphane Bortzmeyer


Historique d’édition :

  • 5 juin 2021 à 13h55 : ajout des références aux travaux de gilbsgilbs et de Christian Quest
  • 5 juin 2021 à 14h35 : ajout du fil de tweets de Mathis Hammel
  • 5 juin 2021 à 16h20 : ajout des remerciements
  • 6 juin 2021 à 8h45 : ajout de l’application en preuve de concept
  • 6 juin 2021 à 11h50 : ajout de la version alternative de TousAntiCovid par Olaf
  • 7 juin 2021 à 12h40 : corrections de coquilles, précisions sur les auteurs, rajout d’une réference à NextInpact, reformulation de la contribution d’Olaf
  • 7 juin 2021 à 13h30 : ajout du fil de tweets de Pixel de Tracking
  • 8 juin 2021 à 8h50 : ajout des articles de Numerama, de Developpez, et du code source de sanipasse
  • 8 juin à 19h15 : ajout des articles d’igen, de 01net et de lemondeinformatique.fr
  • 9 juin à 13h35 : ajout des articles de Mediapart, de Contrepoints, de Nextinpact, et la délibération de la CNIL du 7 juin ; remerciements à Stéphane Bortzmeyer sans lequel la diffusion de cet article n’aurait pas été celle qu’elle a connue
  • 10 juin à 8h25 : ajout du bandeau de mise à jour en tête d’article concernant TousAntiCovid Verif

Attestation COVID-19 en ligne : un outil de surveillance globale sur Internet ?

Cet article est sous licence CC-BY-NC-ND.

Les auteurs de cet article peuvent être contactés sur :

Synthèse non-technique

Le Ministère de l’Intérieur, par l’intermédiaire du site permettant la génération d’attestations de déplacement dérogatoire COVID-19, est en mesure d’assurer un pistage nominatif des citoyens, en usant de procédés comparables à ceux qu’emploient les régies publicitaires et d’autres spécifiques aux services de renseignement. Il est impossible de prouver qu’ils ne le font ou ne le feront pas. Les auteurs de cet article ne détiennent pas, à ce jour, de preuve non plus qu’ils le font ou l’on fait. Cet article expose un risque et propose des contremesures. Les observations de cet article restent valables même après le 15 décembre 2020, lorsque les attestations ne seront potentiellement plus obligatoires, à cause de la persistence infinie des données de pistage.

Il n’existe pas de contremesure technique à certaines des méthodes de pistage évoquées dans cet article. Selon le principe de précaution, il est recommandé aux citoyens d’éviter le risque en ne faisant pas usage de la fonctionnalité “Mon téléphone se souvient de moi”, ou en privilégiant les attestations au format papier. Si un citoyen a déjà utilisé la fonctionnalité “Mon téléphone se souvient de moi”, il est recommandé qu’il efface son historique de navigation, y compris les données mémorisées par le site web https://media.interieur.gouv.fr.

Il est recommandé au Ministère de l’Intérieur de modifier le site web de génération des attestations de déplacement COVID-19 afin :

  • de supprimer la fonctionnalité “Mon téléphone se souvient de moi” ; 

  • d’automatiser l’effacement des données mémorisées précedemment ;

  • d’héberger l’application sur une autre adresse que https://media.interieur.gouv.fr ;

  • dans le cas d’un maintien de la fonctionnalité de mémorisation, de supprimer la couche de chiffrement qui ne sert à rien d’autre qu’à induire un faux sentiment de sécurité ;

  • de renforcer la sécurité de son site web (détail technique plus bas).

Une voie alternative pour le Ministère de l’Intérieur serait de fournir une application mobile en sources ouvertes dédiée à la génération d’attestations. TousAntiCovid ne répond pas à ce besoin, car elle effectue de nombreuses autres missions nécessitant des droits supplémentaires sur le téléphone.

Présentation succincte de l’application d’émission d’attestation

Pour le second confinement de 2020, le Ministère de l’Intérieur a publié une application en ligne pour l’émission d’attestation de déplacement dérogatoire COVID-19 à l’adresse : https://media.interieur.gouv.fr/deplacement-covid-19/

Cette application a subi notamment une mise à jour afin de permettre de mémoriser les informations saisies dans le formulaire, afin d’éviter d’avoir à retaper tous les renseignements à chaque nouvelle visite. Ce mécanisme est au coeur des risques évoqués dans cet article.

L’application fonctionne à l’aide d’un formulaire dans lequel les citoyens saississent leurs informations d’état civil, ainsi que le motif de sortie, et la date et heure. Lors du clic sur le bouton de génération, un fichier PDF est téléchargé. Ce fichier est un formulaire vierge. Il est completé par le navigateur (et le code téléchargé depuis le site du Ministère) grâce aux informations fournies dans le formulaire. Si la case “mon téléphone se souvient de moi” est cochée, alors les informations saisies dans le formulaire sont enregistrées dans le navigateur, grâce à la fonctionnalité localStorage. Elles ne sont pas transmises au Ministère lors de cette opération.

Lors du rechargement de la page, le localStorage est consulté afin d’auto-compléter le formulaire.

Les informations sont stockées sous une forme de document JSON chiffré à l’aide secure-ls. Secure-ls est un module Javascript permettant de chiffrer les données dans le localStorage afin d’en éviter le vol. Outre le fait que les algorithmes cryptographiques déployés par secure-ls sont pour la plupart obsolètes (MD5, SHA-1, 3DES, PBKDF2, RC4…), et que l’implémentation contienne des versions Javascript de ces algorithmes alors qu’il existe WebCrypto, le problème de l’implémentation du Ministère de l’Intérieur est le suivant : le secret permettant de chiffrer et de déchiffrer les informations dans le localStorage est hardcodé dans le code source de la page. Le voici :

s3cr3t$#@135^&*246

Autant dire que cette couche de chiffrement ne sert strictement à rien, et n’est là que pour donner une fausse impression de sécurité… ou pour cacher ce que contient le localStorage aux yeux des curieux.

Il se trouve que le localStorage ne contient rien de bien excitant : une entrée _secure__ls__metadata qui contient un document JSON listant les autres entrées “sécurisées” du localStorage et leurs clés de chiffrement :

{"keys":[{"k":"profile","s":"7bebe7af384395d2ec6d383ac5380c4f"}]}

La clé “profile” contient l’état civil et des informations étrangement redondantes :

{
  "firstname": "Camille",
  "lastname": "Dupont",
  "birthday": "01/01/1970",
  "placeofbirth": "Paris",
  "address": "999 avenue de France",
  "city": "Paris",
  "zipcode": "75001",
  "datesortie": "24/11/2020",
  "heuresortie": "18:00",
  "ox-travail": "travail",
  "ox-achats": "achats",
  "ox-sante": "sante",
  "ox-famille": "famille",
  "ox-handicap": "handicap",
  "ox-sport_animaux": "sport_animaux",
  "ox-convocation": "convocation",
  "ox-missions": "missions",
  "ox-enfants": "enfants"
}

À première vue, l’application semble légitime et conforme à sa mission, faire de son mieux pour que les données ne fuitent pas vers le Ministère de l’Intérieur, et même ce qui semble “caché” sous du chiffrement médiocre est en fait sans surprise ni risque.

Quel est donc le problème décrit par cet article ?

Isolation des sites web

Le web est un milieu dangereux ; s’y cotoient de nombreuses applications web (autrefois appelées sites, mais le terme de site web semble bien réducteur, compte tenu de la quantité de code que chaque site fait exécuter à un navigateur ; ce sont bien des applications à part entière), d’origines diverses et d’innocuité variable. Il est possible de consulter simultanément votre situation fiscale et Facebook, et il serait un scandale si Facebook pouvait décortiquer vos sources de revenus, ou si le site des Impôts pouvait analyser votre graph social.

Pour parrer à ce type de porosité, très tôt dans l’histoire du Web, une politique de sécurité appelée Same Origin Policy (SOP) a été introduite. Cette politique est automatiquement appliquée par tous les navigateurs web. Son principe est l’isolation des applications web en fonction du schéma/protocole (http ou https), du nom de domaine et du numéro de port depuis lequel elles ont été téléchargées. Ainsi http://example.com, http://exemple.net, http://broken-by-design.fr, https://broken-by-design.fr, https://www.broken-by-design.fr et https://www.broken-by-design.fr:8080 sont toutes des applications séparées.

Des applications web isolées par la SOP ne peuvent ni consulter ce qui est affiché par une autre application, ni consulter leurs localStorage respectifs.

Il est ainsi impossible pour Facebook de consulter l’état civil stocké par l’application de génération des attestations COVID-19, par exemple.

Techniques de pistage des utilisateurs

Les techniques de pistage des utilisateurs sont très nombreuses. Parmi ces dernières, les cookies sont un outil redoutable. 

Visiter un site A, puis visiter un site B. Les deux sites utilisent les services d’un troisième site, C. Le site B peut alors afficher des publicités en rapport avec la visite du site A. Cela est rendu possible, car C a obtenu des informations sur la navigation de l’utilisateur lors de son passage sur le site A, et a utilisé des cookies pour en prendre note. Lors de la visite sur le site B, les cookies déposés lors de la visite du site A sont automatiquement envoyés à C, et C peut agit en conséquence en proposant de la publicité personnalisée.

Les cookies ne sont qu’un des nombreux moyens à la disposition des régies publicitaires. Ils sont les plus pratiques car les cookies usent d’une politique de sécurité moins forte que la Same Origin Policy discutée précedemment. Mais il est possible de faire virtuellement la même chose avec localStorage, l’outil de stockage également employé par le site de génération des attestations COVID-19 du Ministère de l’Intérieur. Le localStorage est légèrement plus sécurisé (c’est-à-dire moins pratique pour les régies), mais il a le mérite d’avoir une durée de vie potentiellement illimitée, et de passer un peu plus sous le radar juridique.

Pistage des citoyens

Les lecteurs les plus perspicaces auront déjà fait 1 + 1. 

Le citoyen soucieux de ne pas être sanctionné en cas d’absence d’attestation de déplacements dérogatoires COVID-19 voudra générer ses attestations quotidiennes le plus facilement et rapidement possible. Il va donc utiliser l’application web du Ministère de l’Intérieur sur son téléphone portable, et mémoriser ses informations. Ce faisant, il aura stocké son état civil durablement dans le localStorage associé à https://media.interieur.gouv.fr/.

Ce même utilisateur pourra ensuite continuer de naviguer sur ses sites habituels. Tout site contenant une sous-page (iframe) téléchargée depuis https://media.interieur.gouv.fr, qu’elle soit visible ou non, permettra potentiellement au Ministère de l’Intérieur d’associer cette visite à un état civil. Il s’agit d’un pistage nominatif, et non plus d’un pistage sur la base de pseudonymes (comme des identifiants numériques arbitraires ou des adresses IP).

Mettons que l’on veuille préremplir un formulaire sur service-public.fr ; il suffit d’inclure une sous-page téléchargée depuis https://media.interieur.gouv.fr et boom : service-public.fr peut collaborer avec media.interieur.gouv.fr pour obtenir les informations d’état civil ! (Par exemple, avec une technique d’affaiblissement de la SOP nommée message passing, qui permet à des onglets de communiquer entre eux par messages.)

Mettons que l’on veuille identifier les bons citoyens qui se rendent régulièrement sur le site gouvernement.fr : boom, même technique.

Mettons qu’un service de renseignement peu scrupuleux des limites du droit français souhaite identifier les utilisateurs d’un site peu recommandable. Plusieurs options sont à sa disposition.

La première possibilité serait l’exploitation d’une vulnérabilité de XSS (Cross Site Scripting) qui serait présente sur ce site. Cette vulnérabilité permet d’ajouter du code illégitime dans une page d’un site web. Les XSS font partie des vulnérabilités les plus communes du web ; cela ne semble donc pas improbable. Grâce à cette faille, il est possible d’ajouter une sous-page de https://media.interieur.gouv.fr sur le site ciblé et boom : citoyen Camille Dupont a visité un site interdit !

Une seconde solution pour ce service de renseignement, si le site peu recommandable est servi en HTTP : pratiquer l’attaque de l’homme du milieu (MITM). Cette attaque permet également d’injecter du code dans une page du site web.

Finalement, il existe une technique pour associer un citoyen à une visite sur un site ciblé qui contourne toutes les contremesures (connues des auteurs de cet article) qui ont été déployées notamment à l’encontre des régies publicitaires, y compris First Party Isolation de Mozilla, et son équivalent dans le Tor Browser. Cette technique utilise la redirection HTTP et une page web qui pourrait être hébergée sur https://media.interieur.gouv.fr. Cette page web offrirait volontairement une vulnérabilité de type Open Redirect : en clair, dès que le Javascript de cette page est chargé, il enregistrerait les paramètres de la query string ainsi que l’état civil de l’utilisateur, puis effectuerait une redirection du navigateur (top level navigation) vers l’adresse du site web peu recommandable indiquée dans cette query string. 

Délibérée ou accidentelle, cette fonctionnalité est dangereuse pour les libertés des citoyens français.

Pour les plus sceptiques, un ensemble de sites de démonstration ont été mis en place, qui simulent ce que le Ministère de l’Intérieur peut faire.

Comment s’en protéger ?

Une application mobile en sources ouvertes dédiée à la génération d’attestation est une voie intéressante : elle serait immunisée aux attaques web. La recommandation n’est cependant pas d’utiliser TousAntiCovid. Son modèle est voué à l’échec et présente des risques d’atteinte à la vie privée. De plus, TousAntiCovid accomplit de nombreuses autres missions qui nécessitent des privilèges supplémentaires, dont la connexion au réseau.

Pour se protéger des risques de dévoiement du site de génération de l’attestation COVID-19, il n’existe aucune panacée au meilleur de la connaissance des auteurs de cet article. Il est donc recommandé :

  • de ne pas enregistrer ses données en laissant décoché “Mon téléphone se souvient de moi” ou

  • d’éviter le risque en générant ses attestations autrement (sur papier ou avec des applications alternatives ne reposant par sur la sécurité des navigateurs web).

Enfin, si vous avez utilisé la fonction de mémorisation des données personnelles par le passé, il convient d’effacer toutes les données stockées par le site https://media.interieur.gouv.fr. Il est préférable de le faire en utilisant la fonctionnalité de nettoyage de l’historique du navigateur (en cochant bien la case d’effacement des données stockées par le site), plutôt que d’utiliser le bouton prévu à cet effet dans l’application web de génération des attestations (bien que celle-ci agisse correctement à l’heure de l’écriture de cet article).

Recommandations au Ministère de l’Intérieur

Les recommandations principales sont de retirer la fonctionnalité de mémorisation de l’état civil, et d’ajouter un nettoyage automatique de ces données si elles ont été mémorisées par le passé.

L’usage de l’origine https://media.interieur.gouv.fr est un choix médiocre pour plusieurs raisons :

  • de nombreuses ressources sont servies par cette origine ; la compromission d’une seule de ces ressources entraine la fuite des données personnelles (état civil) des citoyens français. L’isoler sur une origine dédié est une tâche prioritaire.
  • media.interieur.gouv.fr peut trop facilement co-héberger une application délibérément utilisée pour traquer les utilisateurs, tout en prétendant avoir un objectif légitime ; si un site web tiers héberge une sous-page servie par https://media.interieur.gouv.fr, il ne fera pas immédiatement le rapport avec le risque de pistage des citoyens. En utilisant une autre origine dédiée (https://attestation-covid.media.interieur.gouv.fr, par exemple), vous faîtes preuve de transparence et vous permettez à vos partenaires et vos citoyens de vérifier/douter d’une sous-page que vous voudriez qu’ils ajoutent à votre site web.

En outre, les entêtes de sécurité HTTP employés pour servir le site web de génération des attestations COVID-19 sont strictement insuffisants. Vous employez à la date d’écriture de cet article X-XSS-Protection qui est obsolète, HSTS (de manière adéquate, bravo), x-content-type-options. Les auteurs de cet article recommandent l’ajout des entêtes suivants :

  • Content-Security-Policy (dont frame-ancestors ’none’, script-src et default-src), afin de prévenir l’inclusion dans une sous-page et de charger du contenu malveillant en cas de XSS qui ne serait pas bloquée par X-XSS-protection qui est obsolète ;
  • X-Frame-Options: deny afin de prévenir l’inclusion dans des sous-pages ;
  • Cross-Origin-Opener-Policy: same-origin afin de prévenir la fuite d’information via l’ouverture de pop-ups par un attaquant (Spectre, etc.) ;
  • Cross-Origin-Resource-Policy: same-site afin de prévenir l’inclusion de ressources de votre site sur un site tiers ; cela évitera que le secret hardcodé dans votre code source soit volable de manière automatisée ;
  • Cross-Origin-Embedder-Policy: require-corp afin d’imposer l’usage de Cross-Origin-Resource-Policy

Enfin, si vous tenez absolument à maintenir la fonctionnalité de mémorisation, il est recommandable de retirer la couche de chiffrement ls-secure qui est parfaitement inutile et non conforme au Référentiel Général de Sécurité (RGS) - Annexe B1.

L’empoisonnement de cache DNS : toujours d’actualité ?

Le DNS est l’un des protocoles réseau centraux au bon fonctionnement de l’Internet moderne. Ce protocole permet la résolution de noms « symboliques » – les noms de domaine – en des ressources, notamment des adresses IP. Malgré son omniprésence dans notre quotidien, sa sécurisation a été incrémentale et laborieuse. Cet article traite d’une attaque aussi vieille que le DNS, l’empoisonnement de cache, contre laquelle les dernières avancées, comme DNS-over-HTTPS, pourraient permettre de se protéger enfin complètement. Ou le pourront-elles ?

1. Rappels sur le fonctionnement nominal du DNS

Le DNS désigne simultanément un protocole de transmission d’informations sur Internet, et une arborescence administrative et technique organisant les données qui sont transmises par ce protocole. Comprendre finement ces deux aspects est nécessaire pour approcher les attaques par empoisonnement de cache, également appelées attaques par pollution de cache.

Les données stockées dans le DNS sont d’ordres multiples : des adresses IP (types A, AAAA…), des informations utiles pour la livraison des courriers électroniques (types MX, TXT…), des politiques de sécurité (types TXT, TLSA…), des clés cryptographiques (types DNSKEY, TLSA…), ou encore des informations techniques nécessaires au bon fonctionnement et à la sécurisation du DNS lui-même (types NS, RRSIG, DS…). Ces données sont rangées sous la forme d’un arbre, dont chaque nœud, chaque intersection, forme un domaine, comme le montre la figure 1.

Illustration de l’arborescence DNS
Fig. 1 : Illustration de l’arborescence DNS. Chaque intersection constitue un domaine, qui couvre l’ensemble des domaines situés en dessous de lui, et qui sont donc appelés sous-domaines.

Entre chaque domaine de cette arborescence peut se trouver une séparation, une frontière administrative ou technique, que l’on nomme délégation, représentée par un trait plein dans la figure 1. Cette frontière se manifeste techniquement par des données, stockées sous la forme d’enregistrements DNS de type NS, qui indiquent où trouver les serveurs qui seront responsables du domaine délégué.

L’extrait de console suivant fournit un exemple d’une réponse DNS comportant de tels enregistrements formant une délégation. Dans cet exemple, le domaine john.domaine-fictif.fr est délégué, et deux serveurs font autorité sur ce dernier : srv.autre-domaine.fr, et truc.john.domaine-fictif.fr. Ces informations de délégations sont fournies dans la section Authority de la réponse DNS. Nous verrons ultérieurement le rôle des sections dans les empoisonnements de cache. Comme le nom de domaine truc.john.domaine-fictif.fr est situé à l’intérieur du domaine délégué john.domaine-fictif.fr, une adresse doit être fournie pour ce dernier, dans la section Additional de la réponse DNS de délégation.

$ dig -t NS john.domaine-fictif.fr @ns1.domaine-fictif.fr
<snip>
;; QUESTION SECTION:
john.domaine-fictif.fr. IN NS
 
;; AUTHORITY SECTION:
john.domaine-fictif.fr. 172800 IN NS srv.autre-domaine.fr.
john.domaine-fictif.fr. 172800 IN NS truc.john.domaine-fictif.fr.
 
;; ADDITIONAL SECTION:
truc.john.domaine-fictif.fr. 172800 IN A 198.51.100.53

Pour comprendre le rapport entre ces sections et les attaques par empoisonnement de cache, il est également nécessaire d’étudier le fonctionnement d’une interrogation DNS. Une interrogation DNS fait intervenir au minimum trois types d’acteurs : le demandeur, le serveur récursif, et les serveurs faisant autorité sur des domaines.

Le demandeur est une application qui a besoin d’une donnée stockée dans le DNS. Ce peut être, par exemple, un navigateur ou un serveur de courriers électroniques, ou tout simplement la commande ping. Ces applications peuvent contenir du code servant à interroger le DNS, ou simplement utiliser les dispositifs mis à disposition par le système d’exploitation : un résolveur primitif (en anglais, stub resolver).

Le serveur récursif, quant à lui, reçoit la requête DNS du demandeur, et interroge, de manière itérative, les serveurs faisant autorité pour obtenir la réponse adéquate. Pour cela, le serveur récursif suit les délégations, comme celles de l’extrait de console précédent. Son fonctionnement est illustré dans la figure 2, où l’on observe avec les étapes 2, 3, et 4, le processus itératif. Comme l’interrogation itérative est relativement coûteuse, en temps, mémoire, et CPU, les serveurs récursifs sont dotés d’une mémoire persistante, dénommée cache, dans laquelle ils stockent les réponses temporairement, afin d’économiser des ressources en cas de réception d’une nouvelle requête DNS identique (étape 6).

Résolution DNS standard
Fig. 2 : Résolution DNS standard. Une requête est envoyée par un résolveur primitif à un serveur récursif ; celui-ci entreprend le processus de récursion, puis répond au résolveur primitif. Un second résolveur primitif interroge ensuite le même serveur DNS récursif.

Finalement, les serveurs faisant autorité contiennent les données recherchées. Ils répondent aux requêtes DNS ayant trait à des domaines sur lesquels ils ont reçu l’autorité par d’autres serveurs ayant eux-mêmes autorité sur des domaines « parents ». Seule la racine du DNS n’a pas de domaine parent, et la localisation de ses serveurs doit être spécifiée dans la configuration des serveurs DNS récursifs.

Souvent, l’interrogation du DNS n’est pas aussi triviale que le cas présenté dans la figure 2. En effet, toujours à des fins d’optimisations, parfois également pour des raisons de sécurité, un autre type d’acteurs du DNS peut être employé : les relais. Les relais sont des serveurs qui n’ont pour objectif que de faire suivre les requêtes et les réponses entre plusieurs autres acteurs du DNS (par exemple, entre des résolveurs primitifs et des serveurs récursifs). Généralement, ces serveurs ont également une mémoire persistante (cache), afin de décharger les serveurs récursifs ou d’économiser le transit sur le réseau des requêtes et réponses. Ces relais sont souvent utilisés par le système d’exploitation pour mettre en commun les réponses pour plusieurs applications, ou par les box Internet et autres routeurs SOHO pour mettre en commun les réponses pour plusieurs équipements d’un même réseau. La figure 3 illustre un exemple d’interrogation DNS employant des relais.

Résolution DNS avec un relais
Fig. 3 : Résolution DNS avec un relais. Plusieurs applications sollicitent un relais installé directement sur le poste de travail. Ce dernier relaie les requêtes au serveur DNS récursif, qui procède comme dans la figure 2.

2. L’empoisonnement de cache

L’attaque par empoisonnement de cache vise à insérer dans une mémoire persistante (cache) une valeur frauduleuse, qui sera ensuite servie à de multiples demandeurs.

Les conséquences d’une réponse DNS frauduleuse peuvent être très variables : le détournement de connexions vers une adresse IP sous le contrôle de l’attaquant, le contournement de politiques de sécurité, ou encore la fuite d’informations sensibles, comme détaillée dans l’article « SMTP : la killer-app de DNSSEC », publié dans MISC n°97 1.

Il est intéressant de noter qu’un attaquant peut utiliser les mêmes techniques détaillées ultérieurement dans cet article pour empoisonner juste une réponse pour un demandeur spécifique. Cela est cependant rarement fait, puisqu’étant à la fois potentiellement plus difficile à effectuer, et ayant un impact moins grand, puisqu’une seule application en est victime.

L’empoisonnement de cache peut généralement être exécuté par quatre vecteurs, chacun objet d’une des sections suivantes.

2.1. Le cas d’école : l’attaque de l’homme du milieu

Le mode opératoire de l’empoisonnement de cache par l’homme du milieu est simple : l’attaquant se situe en coupure sur le réseau entre le serveur DNS victime et le serveur interrogé. Ce cas peut survenir lorsqu’un routeur est compromis, par exemple. Une variante de cette attaque consiste à manipuler le réseau ou le DNS pour détourner le trafic vers les serveurs de l’attaquant.

Dans ces deux cas, l’homme du milieu peut intercepter toutes les requêtes et réponses DNS. Ainsi, il peut observer les requêtes en transit sur le réseau et fournir des réponses DNS correspondantes contenant les informations frauduleuses de son choix, à la place du serveur interrogé.

Cette attaque est de loin la plus triviale à comprendre, mais sa complexité d’exécution est très variable en fonction du réseau sur lequel elle est mise en œuvre. En effet, sur un réseau local, il est souvent possible de faire des attaques de type ARP poisoning, afin de détourner le trafic local en se faisant passer pour la passerelle du réseau. Sur Internet, en revanche, les attaques ARP ne sont pas possibles. Détourner du trafic reste, bien entendu, possible, notamment grâce à des attaques sur les protocoles de routage dynamiques comme BGP. Ces attaques ont cependant le mauvais goût d’être peu discrètes. Cela n’empêche pas des attaquants de la pratiquer, comme en 2018, où le trafic vers les serveurs DNS d’Amazon a été détourné avec une attaque BGP afin de dérober des cryptomonnaies 2. La NSA a également monté le programme QUANTUMDNS pour effectuer ce genre d’empoisonnement de cache 3.

Si l’on omet les autres attaques nécessaires pour se placer en homme du milieu, effectuer un empoisonnement de cache en étant l’homme du milieu est l’affaire d’une dizaine de lignes de Python : intercepter le trafic, inverser le bit de l’en-tête DNS indiquant que ce message DNS est une question ou une réponse, ajouter la réponse frauduleuse au message DNS, et renvoyer le paquet dans « l’autre sens ».

2.2. La compromission des serveurs faisant autorité ou de la chaîne d’approvisionnement

L’empoisonnement de cache consiste à faire persister une donnée frauduleuse qui sera redistribuée à des demandeurs qui seront les victimes réelles ; l’empoisonnement n’est pas une fin en soi, mais bien un moyen. En conséquence, un serveur DNS disposant d’une mémoire persistante peut parfaitement recevoir une donnée frauduleuse d’un serveur désigné comme légitime par l’arborescence DNS. Cela peut se produire si ce serveur légitime a été compromis, ou bien lorsque les attaquants mènent une attaque sur la chaîne d’approvisionnement du DNS.

Les attaques sur la chaîne d’approvisionnement du DNS sont très fréquentes. La chaîne d’approvisionnement du DNS est formée, au minimum, par le bureau d’enregistrement auprès duquel est acheté un domaine, et le registre. Les registres sont les organismes qui possèdent les domaines situés juste en dessous de la racine du DNS et qui accréditent les bureaux d’enregistrement pour vendre des noms de domaine. Par exemple, on peut citer l’AFNIC, registre en charge des noms de domaine français, dont le .fr, et OVH ou Gandi pour les bureaux d’enregistrement.

Parmi les attaques sur la chaîne d’approvisionnement, il peut notamment être cité le cas de la compromission des authentifiants permettant de se connecter auprès du bureau d’enregistrement. Une fois authentifié, l’attaquant peut modifier les informations de délégation d’un domaine, et désigner ses propres serveurs comme faisant autorité sur ce domaine. Ces serveurs peuvent alors servir des données frauduleuses qui resteront potentiellement dans la mémoire persistante des serveurs DNS qui les auront interrogés bien après que le propriétaire légitime de ce domaine ait repris le contrôle de son domaine. Un exemple d’une telle attaque sur la chaîne d’approvisionnement peut être le détournement de PayPal et d’eBay, en 2014, par l’intermédiaire d’une attaque du bureau d’enregistrement Mark Monitor 4.

En outre, la nature arborescente du DNS signifie qu’il est possible de servir des données frauduleuses pour un domaine en compromettant n’importe lequel de ses domaines parents. Ainsi, en 2017, Matthew Bryant, un chercheur en sécurité, a détourné une fraction des requêtes pour les domaines se terminant en .io, en identifiant une faiblesse dans la délégation de la racine du DNS vers les serveurs en charge du domaine io 5.

2.3. L’exploitation de bugs de logique logicielle

Il est bien entendu que si le serveur ou le logiciel rendant le service DNS sont compromis par un attaquant, ce dernier peut envoyer des réponses de son choix. Cette section de l’article ne s’intéresse cependant pas à ce cas de figure.

Il est ici question du niveau de confiance qu’un serveur DNS récursif a dans les informations reçues dans une réponse DNS. Par exemple, est-ce que le serveur responsable de example.com a le droit de fournir l’adresse IP de www.example.net, dans le cadre d’un « complément de réponse » à une requête qui lui serait envoyée ? Et quid de la réponse illustrée dans l’extrait ci-dessous ? Est-elle acceptable ? Doit-elle être ajoutée à la mémoire persistante (cache) ? Peut-elle remplacer une donnée contraire déjà en mémoire ?

$ dig -t A any1.abc.com
<snip>
;; QUESTION SECTION:
any1.abc.com.         IN    A
;; ANSWER SECTION:
any1.abc.com.        IN    A    1.2.3.4
;; AUTHORITY SECTION:
abc.com.    172800    IN    NS    www.abc.com.
;; ADDITIONAL SECTION:
www.abc.com.        172800    IN    A    6.6.6.6

La réponse n’est pas simple, car il y a de nombreux facteurs à considérer :

  • sur quel(s) domaines(s) le serveur produisant la réponse fait-il autorité ;
  • dans quelle section de la réponse DNS l’information a-t-elle été fournie : section réponse (Answer), autorité (Authority) ou complément d’information (Additional) ;
  • l’information reçue est-elle signée cryptographiquement, avec les extensions de sécurité du DNS : DNSSEC.

Pendant près de dix ans après la conception du DNS, aucune norme n’a documenté l’arbre de décision permettant de choisir si une donnée est suffisamment digne de confiance pour être stockée en mémoire persistante. C’est seulement avec la RFC 2181, en 1997, que des conseils ont enfin été donnés, après un processus itératif ayant compris essais et erreurs. À ce jour, le serveur DNS BIND implémente sept niveaux de confiance différents pour qualifier une donnée et décider si celle-ci peut être mémorisée, utilisée ou retournée dans le cadre d’une réponse. Les autres serveurs DNS ont implémenté leurs propres variantes. Les réponses DNS n’ont donc pas les mêmes effets en fonction du serveur récursif recevant la réponse.

Cela a notamment été documenté dans l’étude « The Hitchhiker’s Guide to DNS Cache Poisoning » 6, qui compare les implémentations de trois serveurs DNS récursifs (BIND9, Unbound, et MaraDNS), modélise leurs comportements, et utilise un modèle formel pour découvrir des réponses DNS provoquant des empoisonnements de cache. Par exemple, la réponse montrée dans l’extrait de console ci-dessus peut inciter BIND9 et Unbound à enregistrer un serveur DNS faisant autorité additionnel, à une adresse du choix de l’attaquant. Cette réponse ne permettra cependant pas d’écraser l’adresse IP de www.abc.com si celle-ci a déjà été mémorisée dans le cadre d’une réponse où elle figurait dans la section Answer.

Le processus de décision est désormais bien établi dans les implémentations principales. Il reste cependant parfois des bugs, comme la CVE-2009-4022, qui affectait BIND. En outre, les nouvelles implémentations peuvent se faire piéger comme des débutants, comme ce fut le cas pour systemd-resolved, en 2014 7.

2.4. L’attaque à l’aveugle

L’attaque à l’aveugle est la plus terrifiante des attaques par empoisonnement de cache ; et pour cause, l’attaquant peut la mener depuis virtuellement n’importe où sur le réseau, y compris parfois Internet dans sa globalité ! Pour cette attaque, il n’est pas nécessaire d’intercepter le trafic DNS de la victime, d’où son nom d’attaque à l’aveugle. L’attaquant se « contente » d’envoyer une réponse (probablement plutôt des millions) à une requête dont il ignore tout, et joue les probabilités afin que sa réponse (l’une d’entre-elles, en tout cas) soit acceptée par le serveur DNS récursif victime comme étant la réponse légitime. Ce dernier met alors à jour sa mémoire persistante avec les informations frauduleuses.

Cette notion de probabilité de succès tient au fait que pour qu’une réponse soit acceptée par un serveur DNS récursif, plusieurs critères doivent être réunis :

  • l’identifiant de transaction DNS (QXID), un champ aléatoire présent dans l’en-tête des réponses DNS doit être identique à celui envoyé dans la requête ;
  • la réponse doit être reçue (c’est-à-dire qu’elle doit être envoyée à la bonne adresse IP et au bon port) ;
  • la réponse doit (sembler) provenir du serveur interrogé (c’est-à-dire que la réponse a été envoyée à partir de l’adresse IP et du numéro de port auxquels la requête a été envoyée).

À cela, il faut également ajouter les éventuelles informations spécifiques au protocole de transport employé : UDP, TCP, D-TLS 8, TLS 9 ou HTTP/2 10. Le DNS peut les utiliser tous, même si UDP est actuellement généralement privilégié, pour des raisons de performance. En UDP, aucune information supplémentaire ne doit être devinée par un attaquant tentant de créer une réponse DNS frauduleuse. HTTP/2 repose (dans les faits) sur TLS, qui lui-même transite sur TCP. Chacun de ces protocoles ajoute des informations inconnues de l’attaquant, à commencer par le numéro de séquence TCP (32 bits pseudo-aléatoires). L’attaquant doit devenir ce dernier, car il usurpe l’adresse IP du serveur DNS interrogé et il ne reçoit donc pas le segment TCP SYN/ACK contenant le numéro de séquence du serveur.

D-TLS, quant à lui, introduit, entre autres, des éléments cryptographiques très difficiles à deviner par un attaquant.

En somme, si l’on considère le protocole de transport par défaut, UDP, le nombre de bits inconnus d’un attaquant essayant de fabriquer une réponse frauduleuse est :

  • QXID au maximum 16 bits ;
  • l’adresse IP du résolveur DNS : certaines infrastructures DNS utilisent plusieurs adresses IP émettrices de requêtes vers les serveurs faisant autorité, ce qui ajoute une incertitude de l’ordre de 0 à 3 ou 4 bits dans les cas extrêmes ;
  • l’adresse IP du serveur DNS interrogé : la plupart des domaines disposent d’au moins deux serveurs DNS faisant autorité, soit au moins 1 bit d’incertitude ;
  • le port sur lequel la réponse doit être envoyée : si ce dernier est choisi aléatoirement, selon les recommandations 11 12, au maximum 16 bits.

Au total, l’attaquant qui tente de fabriquer une réponse DNS frauduleuse doit donc deviner, dans le cas le plus défavorable pour lui, $16 + 16 + 4 + 1 = 37$ bits. Une autre manière de considérer ce résultat est de dire qu’une réponse DNS frauduleuse d’un attaquant à l’aveugle a une probabilité d’au mieux $2^-37$ (environ une chance sur 137 milliards) d’être acceptée par un serveur DNS récursif.

L’attaquant n’est cependant pas contraint d’envoyer une unique réponse frauduleuse. En effet, le serveur DNS récursif est en attente d’une réponse valide. Il rejettera généralement silencieusement les tentatives infructueuses de l’attaquant, et attendra patiemment une réponse correcte. Cette attente dure le temps que le serveur réellement interrogé réponde. Pendant ce laps de temps, l’attaquant peut donc envoyer autant de tentatives de réponses frauduleuses que la victime est capable de recevoir et de traiter. Une réponse DNS de taille moyenne pouvant faire dans les 100 octets, l’attaquant peut envoyer 125000 réponses frauduleuses par seconde vers une victime capable de traiter 100 Mb/s. En admettant un délai raisonnable de réponse du serveur légitime autour des 100 millisecondes, l’attaquant a donc le temps d’envoyer 12500 réponses frauduleuses. En conséquence, une tentative d’empoisonnement de cache d’une victime capable de gérer 100 Mb/s de trafic, avec un serveur légitime mettant 100 millisecondes à répondre, a une probabilité de succès d’autour de $log(12500)/log(2) * 2^-37$, soit environ $2^-23$ ou approximativement une chance sur huit millions. Il existe, en outre, des techniques obscures pouvant permettre d’améliorer encore cette probabilité 13 14 (note : le calcul ci-dessus est faux, mais constitue une approximation compréhensible acceptable).

Une chance sur 137 milliards peut paraître être un risque négligeable. C’est en particulier le cas si l’on considère qu’en cas d’échec, l’attaquant doit attendre que l’information envoyée par le serveur DNS légitime expire de la mémoire persistante du serveur récursif ciblé. Pendant cette période d’expiration, toutes les requêtes sont, en effet, répondues avec l’information mémorisée ; l’attaquant ne peut donc plus tenter sa chance, car le serveur DNS récursif n’émet plus de requête.

Le risque n’a cependant pas toujours été aussi faible. En 2008, le chercheur en sécurité Dan Kaminsky a publié une attaque permettant un empoisonnement de cache à l’aveugle pouvant s’effectuer en quelques minutes, voire quelques secondes suivant les « optimisations » appliquées. À l’époque, les serveurs DNS récursifs n’utilisaient pas systématiquement un port source aléatoire. La probabilité qu’une réponse frauduleuse puisse être acceptée pouvait donc être aussi basse que $2^-16$, soit une chance sur 65536. Le seul élément inconnu était l’identifiant de transaction (QXID) ! En outre, Kaminsky a abusé de la mécanique permettant aux serveurs DNS de juger de la confiance qu’ils peuvent porter dans les informations contenues dans une réponse DNS. Ainsi, son attaque consistait à faire des tentatives d’empoisonnement de cache, non pas sur des domaines existants, mais sur des domaines inexistants aux noms aléatoires. Son but n’était pas de compromettre ces domaines inexistants, mais de fournir des informations complémentaires écrasant d’autres données déjà présentes dans la mémoire persistante du serveur DNS récursif victime. De surcroît, le génie de cette attaque était d’utiliser des domaines inexistants, qui sont quasiment innombrables. Grâce à ces noms aléatoires, en cas de tentative infructueuse, au lieu d’attendre que le serveur DNS récursif vide sa mémoire persistante ou invalide la réponse légitime après un certain délai, une nouvelle tentative pouvait être immédiatement effectuée par l’attaquant, avec un nouveau nom aléatoire.

3. Défenses

Le DNS a été conçu à la fin des années 80. Ce vénérable protocole a connu de nombreux changements, et moult augmentations. Pendant longtemps, les seules améliorations de sa sécurité ont été des rustines visant à rendre de plus en plus difficiles les attaques à l’aveugle et compenser l’absence de lignes directrices pour les niveaux de confiance à porter dans les données reçues.

C’est ainsi que la RFC 5452, publiée en 2009, documente, après la débâcle causée par l’attaque de Dan Kaminksy, que le port source devrait être aléatoire pour plus de sécurité.

La technique connue sous le nom de 0x20 a également vu le jour. 0x20 est la distance, dans la table ASCII, entre une lettre majuscule et la lettre minuscule correspondant : A (65) et a (97) donnent $97 - 65 = 32 = 0x20$ en hexadécimal. Son principe est de changer aléatoirement la casse des lettres d’un nom de domaine dans une requête DNS, et d’escompter voir les mêmes variations de casse dans la réponse DNS. Si la réponse ne contient pas les bonnes majuscules, alors la réponse est rejetée, même si tous les autres paramètres sont bons. Un attaquant à l’aveugle ne peut connaître les lettres qui ont été mises en majuscule ; il doit donc les deviner, en plus de tout le reste.

Ces astuces ne protègent cependant pas contre les autres attaques par empoisonnement de cache évoquées dans la section précédente de cet article. Ainsi, au milieu des années 90, l’IETF, l’organisme qui conçoit les standards de fait de l’Internet, a donc commencé à concevoir des extensions DNS pour la sécurité : DNSSEC. Il a fallu à la communauté plus de dix ans pour arriver à une mouture convenable. Finalement, en 2010, son déploiement global fut rendu possible.

Le principe de DNSSEC a déjà été détaillé de nombreuses fois dans MISC, ainsi que dans un document publié par l’Afnic 15. Néanmoins, il convient ici d’en présenter les grandes lignes, étant donné qu’il s’agit de l’unique contre-mesure efficace contre l’empoisonnement de cache, à ce jour. DNSSEC permet de protéger l’intégrité des informations contenues dans le DNS, à l’aide de signatures cryptographiques. Ces signatures sont créées avec des clés asymétriques : une clé privée est utilisée pour créer les signatures, et la clé publique associée à la clé privée permet de vérifier ces signatures.

La personne ou le serveur en charge d’un domaine signe donc, avec une clé privée, les informations contenues dans ce domaine (plus spécifiquement, dans sa zone… mais la différence subtile de terminologie peut être ignorée ici). La « magie » mathématique de la cryptographie asymétrique permet à tout acteur DNS de valider l’intégrité cryptographique des données ayant trait à ce domaine. Pour cela, la clé publique est employée. Les signatures et les clés publiques nécessaires à leur vérification sont publiées dans l’arborescence DNS elle-même. À chaque délégation d’un sous-domaine, le domaine parent signe une information permettant de vérifier l’authenticité de la clé qui signe le sous-domaine. Il se crée ainsi une chaîne de clés-signatures, permettant de vérifier toutes les informations du DNS… pour peu que les domaines soient signés.

Les validateurs des signatures DNS sont généralement les acteurs de l’infrastructure DNS qui maintiennent une mémoire persistante : les serveurs DNS récursifs et les relais. Une fois les données vérifiées cryptographiquement, ces serveurs peuvent les stocker, en toute sécurité.

Lorsqu’un résolveur primitif interroge un serveur DNS récursif validant DNSSEC, ce dernier répondra en fournissant les informations depuis sa mémoire, et en mettant un bit à 1 (AD : Authentic Data) pour signaler qu’en ce qui le concerne, ces informations ont été déterminées comme authentiques.

Paradoxalement, et de façon parfaitement incompréhensible, les concepteurs de DNSSEC n’ont pas jugé utile de protéger en intégrité le bit AD… En conséquence, si un relais maintenant une mémoire persistante ne fait pas lui-même la validation DNSSEC, son cache peut être empoisonné par un attaquant, quand bien même le domaine est signé avec DNSSEC ! Il peut être jugé que sur un réseau local maîtrisé, comme dans un réseau d’entreprise, la probabilité d’une telle attaque soit faible. Cependant, il est difficile de tenir le même argument lorsque le serveur DNS récursif validant DNSSEC est celui de résolveurs publics, comme ceux de Google, Cloudflare ou OpenDNS ; en effet, les réponses de ces serveurs transitent sur l’Internet sans protection !

Plusieurs propositions ont été avancées pour combler cette absence.

Le protocole DNSCrypt 16 figure parmi les premières propositions viables. Hélas, malgré ses nombreux mérites et son support par OpenDNS dès 2011, son déploiement reste faible à ce jour.

De son côté, la communauté DNS a, des années après la publication de DNSCrypt, mis au monde DNS-over-TLS (DoT) en 2018. Ses atouts sur son prédécesseur sont au mieux douteux, et son adoption est également anecdotique à l’aube de la nouvelle décennie.

Finalement, toujours en 2018, ce qui aurait pu sembler être un trait d’humour il y a dix ans est devenu réalité : DNS-over-HTTPS a été spécifié. Encombré par HTTP/2, sans en tirer le moindre avantage, ce protocole plaque les messages DNS dans la pile protocolaire « DNS sur HTTP/1.1 sur HTTP/2 sur TLS sur TCP ». Ironiquement, contre toute attente et contrairement à la raison la plus primaire, c’est ce protocole, digne de l’œuvre du docteur Frankenstein, qui semble être destiné à être largement adopté. Ce dernier est, en effet, largement plébiscité par les navigateurs, déjà habitués à traiter avec cette pile protocolaire absurde, et dont les intérêts sont tout autre que la protection de l’intégrité du DNS et de la vie privée. Néanmoins, force est de constater que grâce aux navigateurs, le bit AD aura peut-être enfin une chance d’être protégé lors de son transit sur le réseau, grâce à TLS, et les attaques par empoisonnement de cache deviendront réellement impossibles grâce à DNSSEC.

4. Conclusion

Dans cet article, nous avons étudié les différents types d’attaques par empoisonnement de cache, au sens large. Nous avons ainsi pu observer, au travers d’exemples, que ces attaques sont toujours d’actualité, à l’aube de la nouvelle décennie, et plus de 30 ans après la conception du protocole DNS. Enfin, nous avons fait un point sur les techniques de défense disponibles, et celles en cours de déploiement.

Disposer d’une boîte à outils complète pour contrer ces attaques est un luxe dont nous pouvons/allons pouvoir enfin jouir. Hélas, le taux d’adoption de DNSSEC est encore très faible, notamment pour les noms de domaine en .fr. En 2017, l’ANSSI relevait que 10% des noms en .fr étaient signés, et que l’adoption volontaire était anecdotique (1% des domaines qui existaient déjà l’année précédente) 17.

En conséquence, étudier les empoisonnements de cache est encore à ce jour pertinent, et cela devrait, hélas, continuer de l’être pour encore de nombreuses années.

5. Remerciements

Je tiens à remercier Benjamin Cohen et Piotr Chmielnicki pour leurs suggestions d’amélioration de cet article. Les opinions exprimées dans cet article ne sauraient les engager.

6. Références

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


  1. SMTP la killer-app de DNSSEC : https://connect.ed-diamond.com/MISC/MISC-097/SMTP-la-killer-app-de-DNSSEC ↩︎

  2. Article sur l’attaque BGP pour détourner les serveurs DNS d’Amazon : https://dyn.com/blog/bgp-hijack-of-amazon-dns-to-steal-crypto-currency/ ↩︎

  3. Quantum DNS : https://arstechnica.com/information-technology/2015/01/nsa-secretly-hijacked-existing-malware-to-spy-on-n-korea-others/ ↩︎

  4. Article sur l’attaque via Mark Monitor : https://mashable.com/2014/02/01/syrian-electronic-army-ebay/ ↩︎

  5. Blog de Matthew Bryant : https://thehackerblog.com/the-io-error-taking-control-of-all-io-domains-with-a-targeted-registration/ ↩︎

  6. The Hitchhiker’s Guide to DNS Cache Poisoning : https://www.cs.cornell.edu/~shmat/shmat_securecomm10.pdf ↩︎

  7. Systemd-resolved DNS cache poisoning https://seclists.org/oss-sec/2014/q4/592 ↩︎

  8. DNS over Datagram Transport Layer Security (DTLS) : https://www.rfc-editor.org/rfc/rfc8094.txt ↩︎

  9. Specification for DNS over Transport Layer Security (TLS) : https://www.rfc-editor.org/rfc/rfc7858.txt ↩︎

  10. DNS Queries over HTTPS (DoH) : https://www.rfc-editor.org/rfc/rfc8484.txt ↩︎

  11. DNS forgery : http://cr.yp.to/djbdns/forgery.html ↩︎

  12. Measures for Making DNS More Resilient against Forged Answers : https://www.rfc-editor.org/rfc/rfc5452.txt ↩︎

  13. Blocking DNS messages is Dangerous : https://www.ssi.gouv.fr/uploads/IMG/pdf/DNS-OARC-2013-Blocking_DNS_Messages_Is_Dangerous.pdf ↩︎

  14. Fragments Considered Poisonous : https://u.cs.biu.ac.il/~herzbea/security/13-03-frag.pdf ↩︎

  15. Dossier DNSSEC de l’Afnic : https://www.afnic.fr/data/divers/public/afnic-dossier-dnssec-2010-09.pdf ↩︎

  16. Site du projet DNSCrypt : https://dnscrypt.info/ ↩︎

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

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/ ↩︎