<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>Broken by Design</title>
		<link>https://broken-by-design.fr/</link>
		<description>Recent content on Broken by Design</description>
		<generator>Hugo 0.147.3</generator>
		<language>fr</language>
		<copyright>Florian Maury - All content is licensed CC-BY-NC except if stated otherwise</copyright>
		<lastBuildDate>Sun, 03 May 2026 11:40:00 +0200</lastBuildDate>
		<atom:link href="https://broken-by-design.fr/index.xml" rel="self" type="application/rss+xml"/>
		<item>
			<title>Debunkage de la vidéo sur les mots de passe de Fabien Olicard : mémorabilité, densité et entropie irréconciliables ?</title>
			<link>https://broken-by-design.fr/posts/mots-de-passe/</link>
			<pubDate>Sun, 03 May 2026 11:40:00 +0200</pubDate>
			<guid isPermaLink="true">https://broken-by-design.fr/posts/mots-de-passe/</guid>
			<description>&lt;p&gt;Alors que les mots de passe deviennent toujours plus longs et complexes à retenir d&amp;rsquo;une part, et que les attaques informatiques augmentent en intensité d&amp;rsquo;autre part, nous voyons encore en 2026 des débats autour des méthodes sur la composition d&amp;rsquo;un mot de passe.&lt;/p&gt;
&lt;p&gt;En avril 2026, Fabien Olicard, lancé dans le défi de publier une vidéo courte par jour pendant un an, a publié une vidéo intitulée &lt;a href=&#34;https://www.youtube.com/shorts/wofSA-4sHsY&#34;&gt;&amp;ldquo;Votre Mot de Passe est Nul (mais j&amp;rsquo;ai la solution)&amp;rdquo;&lt;/a&gt;. Dans sa vidéo, il donne des conseils sur la composition d&amp;rsquo;un mot de passe, dont l&amp;rsquo;impact en sécurité informatique est très dommageable. Nous détaillerons pourquoi dans cet article (et qui sait, cela lui donnera peut-être un sujet pour une prochaine vidéo 😅).&lt;/p&gt;
&lt;p&gt;Plus inquiétant/intéressant encore, dans la section commentaires, de nombreuses personnes mentionnaient des techniques de composition de mots de passe de leur cru. Une qui est ressortie particulièrement est d&amp;rsquo;utiliser une phrase complète telle que &amp;ldquo;J&amp;rsquo;ai mangé 3 croissants le jour de mon mariage&amp;rdquo;. L&amp;rsquo;argumentaire des personnes proférant ce conseil est qu&amp;rsquo;une longue phrase en toutes lettres rend les attaques par recherche exhaustive (c&amp;rsquo;est-à-dire d&amp;rsquo;essayer toutes les combinaisons de mots/caractères possibles) extrêmement longue.&lt;/p&gt;
&lt;p&gt;Florilège :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Je suis désolé d&amp;rsquo;invalider ton propos mais je pense que, partant de ta phrase perso, le mieux est de la prendre telle quelle, donc &amp;ldquo;J ai mangé 3 croissant le jour de mon mariage&amp;rdquo;, avec ou sans les espaces, en y ajoutant un caractère spécial, afin de respecter cette exigence de la plupart des sites nécessitant un mot de passe.&lt;/p&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Perso, je mets des phrases random généralement et en entier XD&lt;/p&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;oui, lune phrase longue est un meilleur mot de passe qu&amp;rsquo;un mdp court avec caractère spéciaux&amp;hellip; le problème, c&amp;rsquo;est que tout les sites ne permettent pas de le faire&lt;/p&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;On peut aussi choisir une phrase d&amp;rsquo;un livre que l&amp;rsquo;on aime particulièrement, dans un chapitre précis , dans un passage de ce livre, passage que l&amp;rsquo;on aime particulièrement&amp;hellip;&lt;/p&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Tu m&amp;rsquo;es simple la phrase t&amp;rsquo;elle qu&amp;rsquo;elle sans les espaces.Tu à tout la majuscule le chiffre et c&amp;rsquo;est incracable&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;S&amp;rsquo;en est suivi un débat auquel j&amp;rsquo;ai participé et que je souhaiterais reprendre ici, loin de la censure de Youtube qui supprime assez arbitrairement des commentaires. Ma position est que &lt;strong&gt;toute structure dans un mot de passe nuit à sa qualité&lt;/strong&gt;. Nous définirons et détaillerons cette affirmation dans le corps de l&amp;rsquo;article.&lt;/p&gt;
&lt;h2 id=&#34;recommandations-institutionnelles&#34;&gt;Recommandations institutionnelles&lt;/h2&gt;
&lt;p&gt;Les institutions françaises publient des recommandations concernant les mots de passe.&lt;/p&gt;
&lt;p&gt;Ainsi, la CNIL publie des &lt;a href=&#34;https://www.cnil.fr/fr/mots-de-passe-recommandations-pour-maitriser-sa-securite&#34;&gt;recommandations&lt;/a&gt; et un &lt;a href=&#34;https://www.cnil.fr/fr/verifier-sa-politique-de-mots-de-passe&#34;&gt;évaluateur de la sécurité des mots de passe&lt;/a&gt;. De manière intéressante, les recommandations de la CNIL ont évolué vers le mieux en 2022, celles publiées en 2017 présentant de vrais problèmes pour la sécurité des usagers.&lt;/p&gt;
&lt;p&gt;De son côté, l&amp;rsquo;ANSSI publie un &lt;a href=&#34;https://messervices.cyber.gouv.fr/guides/recommandations-relatives-lauthentification-multifacteur-et-aux-mots-de-passe&#34;&gt;guide de recommandations relatives à l&amp;rsquo;authentification multifacteur et aux mots de passe&lt;/a&gt;. Par transparence, précisons que l&amp;rsquo;auteur du présent article a participé à son élaboration.&lt;/p&gt;
&lt;h2 id=&#34;la-recommandation-de-fabien-olicard&#34;&gt;La recommandation de Fabien Olicard&lt;/h2&gt;
&lt;h3 id=&#34;synthèse-de-la-vidéo&#34;&gt;Synthèse de la vidéo&lt;/h3&gt;
&lt;p&gt;Dans sa vidéo courte, Fabien nous propose d&amp;rsquo;utiliser les lettres initiales de chaque mot d&amp;rsquo;une phrase personnelle, avec quelques modifications additionnelles. Ainsi, la phrase &amp;ldquo;J&amp;rsquo;ai mangé 3 croissants le jour de mon mariage&amp;rdquo; est transformée en &amp;ldquo;Jam3cljdmm&amp;rdquo;. Ensuite, il propose de rajouter un caractère spécial à intervalle régulier, par exemple tous les 6 caractères. Il suggère ici le tiret, ce qui donne &amp;ldquo;Jam3cl-jdmm&amp;rdquo;. Enfin, il suffixe au mot de passe un &amp;ldquo;abrégé&amp;rdquo; du site pour lequel ce mot de passe est destiné. En guise d&amp;rsquo;exemple, il propose &amp;ldquo;Nfx&amp;rdquo; pour Netflix. Le suffixe ne contient jamais de caractères spéciaux rajoutés ; il est donc préfixé du caractère spécial. Ainsi, le mot de passe Netflix serait &amp;ldquo;Jam3cl-jdmm-Nfx&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;En points positifs, Fabien indique bien de préférer une phrase personnelle à une phrase bien connue, comme une citation. En effet, une citation connue, ou un extrait de livre auraient une forte probabilité d&amp;rsquo;être la source d&amp;rsquo;inspiration de nombreuses personnes, qui se retrouveraient alors avec un mot de passe quasi identique et &amp;ldquo;public&amp;rdquo;. Fabien suggère également qu&amp;rsquo;il est nécessaire d&amp;rsquo;utiliser des mots de passe distincts par site, ce qui est une bonne pratique de sécurité.&lt;/p&gt;
&lt;p&gt;Analysons maintenant pourquoi la recommandation de Fabien est problématique.&lt;/p&gt;
&lt;h3 id=&#34;analyse-critique&#34;&gt;Analyse critique&lt;/h3&gt;
&lt;p&gt;Pour comprendre les problèmes de la recommandation de Fabien, il faut d&amp;rsquo;abord comprendre comment sont généralement stockés les mots de passe par les sites web, et comment ils sont attaqués.&lt;/p&gt;
&lt;p&gt;Pour s&amp;rsquo;authentifier, on envoie &lt;em&gt;généralement&lt;/em&gt; son mot de passe au site web (&lt;a href=&#34;https://git.broken-by-design.fr/fmaury/Broken-by-Design/src/branch/main/posts/cours-id-authn.md#la-preuve-par-calculs-r%C3%A9partis&#34;&gt;il existe des manières de s&amp;rsquo;authentifier où ce n&amp;rsquo;est pas le cas&lt;/a&gt;).&lt;/p&gt;
&lt;pre class=&#34;mermaid&#34;&gt;sequenceDiagram
actor you as Vous
actor website as Site Web

you -&gt;&gt; website: Envoie du mot de passe
website -&gt;&gt; website: Dérive le mot de passe
website -&gt;&gt; website: Vérifie le dérivé avec celui stocké en base de données
alt Les dérivés correspondent
    website -&gt;&gt; you: Vous donne accès
else
    website -&gt;&gt; you: Rejette la connexion
end
&lt;/pre&gt;

&lt;p&gt;Ce mot de passe n&amp;rsquo;est pas comparé directement avec le mot de passe que nous avons envoyé lors de notre inscription sur le site web. En effet, pour limiter les risques en cas de compromission du site web, ce dernier stocke les mots de passe fournis à l&amp;rsquo;inscription sous une forme &lt;em&gt;dérivée&lt;/em&gt;. Cette dérivation se produit en utilisant des algorithmes spécialement conçus pour le stockage de mots de passe.&lt;/p&gt;
&lt;p&gt;Pour vérifier le mot de passe qu&amp;rsquo;on envoie lorsqu&amp;rsquo;on veut se connecter à un site web, ce dernier va appliquer un algorithme de dérivation sur le mot de passe envoyé. Le résultat de cet algorithme, appelé &lt;em&gt;dérivé&lt;/em&gt;, est ensuite comparé avec le dérivé stocké dans sa base de données, lors de l&amp;rsquo;inscription.&lt;/p&gt;
&lt;p&gt;Si les deux dérivés sont identiques, alors bingo ! Nous avons prouvé notre connaissance du mot de passe, et donc notre identité au site web !&lt;/p&gt;
&lt;p&gt;Si le site web venait à être compromis, l&amp;rsquo;attaquant·e n&amp;rsquo;obtiendrait que les dérivés des mots de passe stockés en base de données. Les algorithmes de dérivation de mots de passe sont conçus spécifiquement pour qu&amp;rsquo;il soit très difficile pour un·e attaquant·e de retrouver le mot de passe à partir du dérivé. L&amp;rsquo;attaquant·e ne peut qu&amp;rsquo;essayer de retrouver le mot de passe à partir du dérivé en générant des mots de passe, en les dérivant, et en comparant ces dérivés avec les dérivés récupérés lors du piratage. On appelle cela l&amp;rsquo;attaque par force brute, &lt;em&gt;bruteforce&lt;/em&gt;, ou par recherche exhaustive.&lt;/p&gt;
&lt;p&gt;Nous en savons maintenant assez pour comprendre quelques-uns des problèmes de la recommandation de Fabien.&lt;/p&gt;
&lt;p&gt;Fabien propose d&amp;rsquo;utiliser un mot de passe &amp;ldquo;Jam3cl-jdmm&amp;rdquo; suffixé d&amp;rsquo;un abrégé désignant le site web sur lequel ce mot de passe est utilisé. Dans l&amp;rsquo;exemple &amp;ldquo;-Nfx&amp;rdquo;. Si l&amp;rsquo;utilisateur·rice utilise aussi Amazon Prime, le suffixe sera, par exemple, &amp;ldquo;-AmzP&amp;rdquo; et son mot de passe sera &amp;ldquo;Jam3cl-jdmm-AmzP&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Ainsi, les suffixes &amp;ldquo;-Nfx&amp;rdquo; et &amp;ldquo;-AmzP&amp;rdquo; jouent le rôle de diversificateurs. &lt;strong&gt;L&amp;rsquo;essentiel du mot de passe reste cependant identique !&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Imaginons maintenant que le site d&amp;rsquo;Amazon Prime contienne un bug, et qu&amp;rsquo;il n&amp;rsquo;utilise &lt;strong&gt;pas d&amp;rsquo;algorithmes de dérivation de mots de passe&lt;/strong&gt;. À la place, il stocke &lt;em&gt;directement&lt;/em&gt; le mot de passe de l&amp;rsquo;utilisateur·rice dans la base de données. Si celle-ci est piratée, ou qu&amp;rsquo;Amazon est malveillant, l&amp;rsquo;attaquant·e pourra voir que le mot de passe de Fabien sur Amazon Prime est &amp;ldquo;Jam3cl-jdmm-AmzP&amp;rdquo; ! L&amp;rsquo;effort mental pour imaginer que pour Netflix, le suffixe est &amp;ldquo;-Nfx&amp;rdquo; est minimal. L&amp;rsquo;attaquant·e ou Amazon pourront alors facilement deviner que le mot de passe pour Netflix est &amp;ldquo;Jam3cl-jdmm-Nfx&amp;rdquo; et pirater le compte Netflix de Fabien ! 😱&lt;/p&gt;
&lt;p&gt;Ce constat est déjà très problématique en soi. Il revient à utiliser quasiment le même mot de passe partout, ce qui est décrié depuis des années par toutes les personnes vaguement compétentes pour parler du sujet.&lt;br&gt;
Certaines personnes l&amp;rsquo;ont d&amp;rsquo;ailleurs présenti dans les commentaires :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Excellente l&amp;rsquo;idée de rajouter le sigle du site à la fin. Cela permet de réutiliser la phrase.&lt;br&gt;
Mais en cas de soucis ou doute, il faudra changer touts les mots de passe&amp;hellip;🙄&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Les problèmes de la recommandation de Fabien vont cependant plus loin. Les mots de passe ainsi construits ont une &lt;strong&gt;structure&lt;/strong&gt;. Le sujet de la structure est complexe, et nombre des commentateur·rices ne l&amp;rsquo;ont pas saisi ; c&amp;rsquo;est ce qui a motivé l&amp;rsquo;écriture du présent article.&lt;/p&gt;
&lt;h2 id=&#34;le-problème-de-la-structure-des-mots-de-passe&#34;&gt;Le problème de la structure des mots de passe&lt;/h2&gt;
&lt;p&gt;Commençons par acquérir une intuition du problème que représente la structure. Nous pourrons ensuite généraliser et formaliser le propos.&lt;/p&gt;
&lt;h3 id=&#34;biais-statistique-de-la-lettre-initiale&#34;&gt;Biais statistique de la lettre initiale&lt;/h3&gt;
&lt;p&gt;En vulgarisant, on pourrait dire qu&amp;rsquo;en français, plus de mots commencent par un &lt;strong&gt;D&lt;/strong&gt; que par un &lt;strong&gt;Z&lt;/strong&gt;. Plus formellement, on dirait que les mots français ne sont pas uniformément distribués en 26 catégories correspondant à la lettre initiale de chaque mot.&lt;br&gt;
En prenant le dictionnaire libre aspell, on peut calculer le graphique suivant, avec la commande :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; i in &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;a..z&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; aspell -d /usr/lib64/aspell-0.60/francais-lrg.alias dump master &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep -c &lt;span class=&#34;s2&#34;&gt;&amp;#34;^&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$i&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre class=&#34;mermaid&#34;&gt;xychart
    title &#34;Répartition des mots dans le dictionnaire par leur lettre initiale&#34;
    x-axis &#34;Lettres initiales&#34; [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z]
    y-axis &#34;Nombre de mots&#34; 0 --&gt; 70000
    bar [ 25187, 15642, 35126, 65442, 21728, 12855, 10470, 6147, 12059, 11801, 537, 69161, 53765, 59390, 5441, 27644, 55430, 37415, 36184, 53545, 1038, 7307, 190, 63, 94, 800 ]
&lt;/pre&gt;

&lt;p&gt;Le mot de passe de Fabien &amp;ldquo;Jam3cl-jdmm&amp;rdquo; est composé des lettres initiales des mots présents dans la phrase personnelle &amp;ldquo;J&amp;rsquo;ai mangé 3 croissants le jour de mon mariage.&amp;rdquo; &lt;strong&gt;Certaines lettres ont donc statistiquement beaucoup plus de chances d&amp;rsquo;apparaitre que d&amp;rsquo;autres&lt;/strong&gt; dans un mot de passe fabriqué en suivant la technique de Fabien.&lt;br&gt;
Lorsque l&amp;rsquo;attaquant·e essaie de trouver le mot de passe d&amp;rsquo;une personne, il pourra donc mener sa recherche en essayant d&amp;rsquo;abord avec les &lt;strong&gt;lettres les plus fréquentes&lt;/strong&gt;, afin d&amp;rsquo;&lt;strong&gt;accélérer sa recherche&lt;/strong&gt; et trouver plus vite le mot de passe !&lt;/p&gt;
&lt;p&gt;Il convient de noter que ce problème existe également si l&amp;rsquo;on compose ses mots de passe avec la méthode dite syllabique, où le mot de passe est élaboré à partir d&amp;rsquo;une phrase décomposée en phonèmes (par exemple, &amp;ldquo;J&amp;rsquo;ai&amp;rdquo; devient la lettre &amp;ldquo;G&amp;rdquo; par proximité phonologique). La méthode syllabique était conseillée, à tort, par la CNIL en 2017.&lt;/p&gt;
&lt;h3 id=&#34;biais-statistiques-liés-à-la-structure-de-la-phrase&#34;&gt;Biais statistiques liés à la structure de la phrase&lt;/h3&gt;
&lt;p&gt;La fréquence des initiales n&amp;rsquo;est pas le seul biais de ce type lié à la structure du mot de passe. En français, la plupart des phrases sont construites sous la forme SVO : sujet, verbe, objet. En généralisant, la plupart des langues possèdent une syntaxe propre ne permettant pas d&amp;rsquo;ordonner les mots de manière arbitraire.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;💡 En contre-exemple, l&amp;rsquo;Esperanto utilise le suffixe -n pour marquer l&amp;rsquo;accusatif. Ainsi, &amp;ldquo;amikoj&amp;rdquo; désigne le sujet de la phrase et &amp;ldquo;amikoj&lt;em&gt;n&lt;/em&gt;&amp;rdquo; porte la marque de l&amp;rsquo;accusatif et est donc l&amp;rsquo;actant ou le complément d&amp;rsquo;objet direct, quelle que soit sa position dans la phrase. Ces trois phrases (&amp;ldquo;J&amp;rsquo;ai des amis.&amp;rdquo;) sont syntaxiquement identiques : &amp;ldquo;Mi havas amikojn. Amikojn mi havas. Mi amikojn havas.&amp;rdquo; Pour être complet, l&amp;rsquo;ordre des composants de la phrase pourra traduire une intention d&amp;rsquo;attirer spécifiquement l&amp;rsquo;attention sur l&amp;rsquo;une des informations de la phrase.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;La syntaxe d&amp;rsquo;une langue permet de concevoir des chaines de Markov. Il s&amp;rsquo;agit d&amp;rsquo;un outil mathématique permettant, par exemple, de déterminer quels sont les mots les plus probables suivant un autre mot. Si cela vous évoque les grands modèles de langage (LLM), ce n&amp;rsquo;est pas un hasard.&lt;/p&gt;
&lt;p&gt;Mais pour en revenir à nos moutons, intuitivement, on peut se dire qu&amp;rsquo;après l&amp;rsquo;article &amp;ldquo;la&amp;rdquo;, nous ne trouverons pas en français correct de mots commençant par une voyelle.&lt;/p&gt;
&lt;p&gt;Lorsqu&amp;rsquo;un·e attaquant·e tentera de retrouver un mot de passe consistant en une phrase en langage naturel (comme le français), il pourra donc intégrer ces informations pour tester en premier les combinaisons probables, et donc accélérer sa recherche. En effet, les attaquant·es ne limitent pas leur recherche des mots de passe à la seule technique par recherche exhaustive bête et méchante : a, b, &amp;hellip;, aa, bb, &amp;hellip;, aaa, bbb, &amp;hellip; Les outils modernes de &amp;ldquo;cassage de mots de passe&amp;rdquo; sont parfaitement capables d&amp;rsquo;utiliser des techniques variées, incluant la recherche de mots dans les &lt;a href=&#34;https://hashcat.net/wiki/#core_attack_modes&#34;&gt;dictionnaires&lt;/a&gt;, &lt;a href=&#34;https://github.com/RUB-SysSec/NEMO&#34;&gt;les chaines de Markov&lt;/a&gt;, &lt;a href=&#34;https://hashcat.net/wiki/doku.php?id=maskprocessor#maskprocessor&#34;&gt;des masques&lt;/a&gt;, et bien d&amp;rsquo;autres.&lt;/p&gt;
&lt;p&gt;Ce biais affecte directement la méthode de Fabien pour fabriquer un mot de passe, puisque les lettres sont des initiales de mots. Pour chaque lettre du mot de passe, même sans connaitre le mot qui lui est associé, on peut prendre la liste des mots commençant par cette lettre. Ensuite, on peut calculer quels mots sont les plus probables après chacun de ces mots. Enfin, on calcule la lettre initiale la plus commune parmi ces derniers. Cela permet à l&amp;rsquo;attaquant·e d&amp;rsquo;optimiser sa recherche exhaustive !&lt;/p&gt;
&lt;p&gt;Mais on peut généraliser ce biais et faire la déclaration que certain·es trouvent excessive : &lt;strong&gt;toute structure induit un biais réduisant l&amp;rsquo;entropie ou la densité&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&#34;structure-entropie-et-densité&#34;&gt;Structure, entropie et densité&lt;/h2&gt;
&lt;h3 id=&#34;définition-de-lentropie-et-de-la-densité&#34;&gt;Définition de l&amp;rsquo;entropie et de la densité&lt;/h3&gt;
&lt;p&gt;L&amp;rsquo;entropie est un terme du technolecte informatique lié à la théorie de l&amp;rsquo;information de Shannon. Ce terme est souvent mécompris. Nous commencerons par en apporter une définition afin de faciliter la lecture du reste de l&amp;rsquo;article.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;entropie désigne la &lt;em&gt;quantité d&amp;rsquo;information dans une donnée&lt;/em&gt;. La quantité d&amp;rsquo;information désigne l&amp;rsquo;incertitude de ce que sera une information compte tenu des informations précédemment connues.&lt;/p&gt;
&lt;p&gt;Intuitivement, la donnée représentant le mot de passe &lt;code&gt;aaaaaa&lt;/code&gt; contient relativement peu d&amp;rsquo;informations, si ce mot de passe est construit exclusivement en répétant six fois la lettre &lt;code&gt;a&lt;/code&gt;. Au mieux, on peut avoir deux informations : le nombre de lettres et la lettre répétée. Les mêmes deux informations auraient pu être communiquées de manière plus &lt;strong&gt;dense&lt;/strong&gt; en écrivant &lt;code&gt;6a&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Il convient également de tordre le cou à une croyance bien ancrée, et qui se trouve être également très populaire chez les personnes œuvrant en informatique. &lt;a href=&#34;https://ia801605.us.archive.org/view_archive.php?archive=/23/items/dilbert-1989-2023-complete.-7z_202303/Dilbert_1989-2023_complete.7z&amp;amp;file=2001%2F2001-10-25_tour%20of%20accounting_random%20number%20geneartor_randomness.gif&#34;&gt;Il n&amp;rsquo;est pas possible de déterminer l&amp;rsquo;entropie en observant une donnée !&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Ainsi, &lt;code&gt;999999&lt;/code&gt; pourrait tout à fait contenir plus d&amp;rsquo;entropie que &lt;code&gt;hjf3U&amp;amp;àSD/r-&lt;/code&gt;. Pour comprendre cela, il faut comprendre comment est calculée l&amp;rsquo;entropie. Une &lt;a href=&#34;https://fr.wikipedia.org/wiki/Entropie_de_Shannon#D%C3%A9finition_formelle&#34;&gt;définition formelle&lt;/a&gt; est disponible sur Wikipedia. Intuitivement, il faut comprendre que ce qui compte n&amp;rsquo;est pas tant l&amp;rsquo;aspect de la donnée que le degré d&amp;rsquo;incertitude de chaque élément composant la donnée.&lt;/p&gt;
&lt;p&gt;Le mot de passe &lt;code&gt;hjf3U&amp;amp;àSD/r-&lt;/code&gt; &lt;strong&gt;semble&lt;/strong&gt; complexe, et il a probablement été généré en tirant 12 caractères aléatoirement, avec des minuscules, des majuscules, des chiffres et des caractères spéciaux. L&amp;rsquo;ensemble des minuscules (26 éléments), majuscules (26 éléments), chiffres (10 éléments) et caractères spéciaux (disons une quarantaine) signifie que chaque caractère a une chance sur 92 (26 + 26 + 10 + 40) d&amp;rsquo;être sélectionné comme le prochain caractère du mot de passe. Répété 12 fois, on obtient 92&lt;sup&gt;12&lt;/sup&gt;
 combinaisons possibles (367666387654882241806336 ou environ 3,68 * 10&lt;sup&gt;23&lt;/sup&gt;
). Cela correspond à log2(92&lt;sup&gt;12&lt;/sup&gt;
) ≈ 78 bits d&amp;rsquo;entropie.&lt;/p&gt;
&lt;p&gt;Comparativement, le mot de passe &lt;code&gt;999999&lt;/code&gt; &lt;strong&gt;semble&lt;/strong&gt; être un chiffre répété six fois. Cependant, il se pourrait aussi qu&amp;rsquo;il s&amp;rsquo;agisse du nombre tiré aléatoirement entre zéro et 2&lt;sup&gt;128&lt;/sup&gt;
. Ou même de 6 nombres concaténés et constitués de un chiffre chacun, tirés entre 0 et 2&lt;sup&gt;128&lt;/sup&gt;
 ! Dans le premier cas, l&amp;rsquo;entropie serait de moins de 20 bits. Dans le second, l&amp;rsquo;entropie serait de 128 bits, soit nettement supérieure aux 78 bits de &lt;code&gt;hjf3U&amp;amp;àSD/r-&lt;/code&gt;. Dans le dernier cas, l&amp;rsquo;entropie serait même de 768 bits ! 🤯&lt;/p&gt;
&lt;p&gt;Il résulte de cet argumentaire que tout &amp;ldquo;calculateur d&amp;rsquo;entropie&amp;rdquo; où l&amp;rsquo;on saisit son mot de passe pour qu&amp;rsquo;il en fasse une analyse statistique d&amp;rsquo;uniformité est irrémédiablement &lt;strong&gt;incorrect&lt;/strong&gt;, puisqu&amp;rsquo;il repose sur ce qui est observable dans le mot de passe et non sur l&amp;rsquo;analyse de sa méthode de fabrication ! Cette erreur est également présente sur des gestionnaires/générateurs de mots de passe, comme KeePassXC qui calcule l&amp;rsquo;entropie d&amp;rsquo;un mot de passe en fonction des caractères le composant plutôt qu&amp;rsquo;en fonction du nombre de caractères le composant ET de la taille de l&amp;rsquo;ensemble des caractères possibles pour chacun d&amp;rsquo;entre eux ! 😭&lt;/p&gt;
&lt;h3 id=&#34;les-mots-de-passe-fonction-de-laléa&#34;&gt;Les mots de passe fonction de l&amp;rsquo;aléa&lt;/h3&gt;
&lt;p&gt;Dans la section précédente de cet article, l&amp;rsquo;entropie a été mesurée en bits. Ce n&amp;rsquo;est pas un hasard ; cette unité est liée à la génération de secrets en cryptographie.&lt;/p&gt;
&lt;p&gt;En cryptographie, un nombre aléatoire doit disposer de deux propriétés : dans sa représentation binaire, chaque bit (c&amp;rsquo;est-à-dire chaque 0 ou 1 qui le compose) doit être &lt;strong&gt;indépendant&lt;/strong&gt; et la distribution doit être &lt;strong&gt;uniforme&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;uniformité d&amp;rsquo;une représentation binaire signifie que chaque bit composant un nombre aléatoire avait autant de chance d&amp;rsquo;être un 0 qu&amp;rsquo;un 1. Intuitivement, c&amp;rsquo;est comme de faire un pile ou face avec une pièce non truquée.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;indépendance signifie qu&amp;rsquo;aucun des bits ne doit être en mesure d&amp;rsquo;influencer la probabilité qu&amp;rsquo;un ou plusieurs bits suivants soient un 0 ou un 1. Intuitivement, c&amp;rsquo;est comme de dire que chaque lancer de pile ou face ne peut pas influencer le résultat des futurs lancers. Par exemple, 01010101 est parfaitement uniforme (il y a autant de zéros et de uns), mais il semblerait bien que ce soit une alternance de zéros et de uns. Si cette séquence est le pur fruit du hasard, alors parfait ! Si, par contre, lors de la génération, cette séquence alternée de zéros et de uns était délibérée, alors les bits ne sont pas indépendants ! On touche à nouveau du doigt les biais et l&amp;rsquo;intentionnalité dans l&amp;rsquo;algorithme de fabrication du mot de passe.&lt;/p&gt;
&lt;p&gt;Pour éviter les biais, une méthode est de demander à une machine de nous générer un mot de passe. Pour cela, cette dernière utilise un générateur de bits aléatoires, afin de générer N bits d&amp;rsquo;entropie.&lt;/p&gt;
&lt;p&gt;Une fois ces bits générés, ils sont consommés par une fonction, que nous appellerons T, afin de transformer cet aléa en mot de passe. La fonction T peut être tout et n&amp;rsquo;importe quoi, mais le principe général est de consommer une partie des bits encore non consommés pour choisir aléatoirement le prochain &amp;ldquo;composant&amp;rdquo; d&amp;rsquo;un mot de passe.&lt;/p&gt;
&lt;p&gt;Par exemple, admettons que les bits aléatoires générés par la machine soient les suivants (regroupés en groupes de six bits pour des raisons qui deviendront évidentes dans quelques lignes) :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;mi&#34;&gt;101010&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;101000&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;111000&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;101101&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Admettons ensuite que le mot de passe que l&amp;rsquo;on cherche à générer est un mot de passe composé de caractères alphanumériques et de quelques caractères spéciaux. L&amp;rsquo;ensemble des caractères pouvant constituer un mot de passe sont au nombre de 64 et sont les suivants :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;b&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;c&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;d&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;e&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;f&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;g&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;h&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;j&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;k&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;l&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;m&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;o&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;q&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;r&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;t&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;u&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;v&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;w&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;y&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;z&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;A&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;B&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;C&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;D&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;E&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;F&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;G&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;H&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;I&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;J&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;K&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;L&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;M&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;N&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;O&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;P&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Q&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;R&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;S&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;T&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;U&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;V&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;W&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;X&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Y&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Z&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;9&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Chaque groupe de 6 bits représente un nombre entre 0 et 63 en base 2 (c&amp;rsquo;est-à-dire en binaire). Ainsi, &lt;code&gt;101010&lt;/code&gt; représente le nombre 42. On prend donc le 43e caractère (42 + 1, le +1 étant parce qu&amp;rsquo;on commence à compter à partir de 0) parmi la liste de caractères précédemment listés.&lt;/p&gt;
&lt;p&gt;En répétant cet algorithme, on obtient ainsi :&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Bits aléatoires&lt;/th&gt;
          &lt;th&gt;Caractère du mot de passe&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;101010&lt;/td&gt;
          &lt;td&gt;Q&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;101000&lt;/td&gt;
          &lt;td&gt;O&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;111000&lt;/td&gt;
          &lt;td&gt;4&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;101101&lt;/td&gt;
          &lt;td&gt;T&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Le mot de passe généré est donc &lt;code&gt;QO4T&lt;/code&gt; et contient autant d&amp;rsquo;entropie que le nombre de bits générés précédemment : 4 groupes de 6 bits, soit 24 bits.&lt;/p&gt;
&lt;p&gt;Dans cet exemple, la fonction T est donc de consommer les bits, six par six, pour tirer un caractère aléatoire dans une liste de 64 caractères distincts. On aurait pu imaginer une fonction T&lt;sub&gt;bis&lt;/sub&gt;
 où l&amp;rsquo;on consomme les bits quatre par quatre et où l&amp;rsquo;on répète alternativement la lettre A ou la lettre B un nombre de fois égal au nombre formé en base 2 par ces groupes de 4 bits ! Cela donnerait :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;mi&#34;&gt;1010&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1010&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1000&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1110&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0010&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1101&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Bits aléatoires&lt;/th&gt;
          &lt;th&gt;Séries de A ou de B&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;1010&lt;/td&gt;
          &lt;td&gt;AAAAAAAAAA&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;1010&lt;/td&gt;
          &lt;td&gt;BBBBBBBBBB&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;1000&lt;/td&gt;
          &lt;td&gt;AAAAAAAA&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;1110&lt;/td&gt;
          &lt;td&gt;BBBBBBBBBBBBBB&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;0010&lt;/td&gt;
          &lt;td&gt;AA&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;1101&lt;/td&gt;
          &lt;td&gt;BBBBBBBBBBBBB&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Le mot de passe serait alors &lt;code&gt;AAAAAAAAAABBBBBBBBBBAAAAAAAABBBBBBBBBBBBBBAABBBBBBBBBBBBB&lt;/code&gt;. Bien qu&amp;rsquo;il soit nettement plus long (c&amp;rsquo;est-à-dire moins &lt;strong&gt;dense&lt;/strong&gt;) que &lt;code&gt;QO4T&lt;/code&gt;, il contient la même quantité d&amp;rsquo;entropie : 24 bits.&lt;/p&gt;
&lt;p&gt;Un attaquant qui voudrait casser ce mot de passe aurait à deviner 25 bits d&amp;rsquo;entropie : 24 bits aléatoires et si c&amp;rsquo;est la fonction T ou la fonction T&lt;sub&gt;bis&lt;/sub&gt;
 qui a été utilisée. Il a une chance sur deux de tenter la fonction T et une chance sur deux de tenter la fonction T&lt;sub&gt;bis&lt;/sub&gt;
, ce qui représente donc une incertitude de 1 bit.&lt;/p&gt;
&lt;p&gt;On peut imaginer encore d&amp;rsquo;autres fonctions T :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;choisir un mot aléatoirement dans un dictionnaire (si le dictionnaire contient 8192 mots, alors on consomme les bits treize par treize) comme le fait Bitwarden ;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;choisir un smiley aléatoire dans une liste de smileys ;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;choisir aléatoirement un phonème dans une langue (s&amp;rsquo;il y a 36 phonèmes dans une langue, alors on consomme les bits 6 par 6, car 2&lt;sup&gt;5&lt;/sup&gt;
 &amp;lt; 36 &amp;lt; 2&lt;sup&gt;6&lt;/sup&gt;
 ) comme le fait Apple ;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;choisir aléatoire un livre dans sa bibliothèque, choisir aléatoirement une page, choisir aléatoirement un paragraphe dans la page, choisir aléatoirement un mot dans le paragraphe et recommencer jusqu&amp;rsquo;à avoir consommé tous les bits d&amp;rsquo;entropie ;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;choisir un chemin de neurones pseudo-aléatoire déterministe pour fabriquer une phrase dans un langage naturel, comme peuvent le faire les LLM&amp;hellip;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Contrairement à ce que l&amp;rsquo;on pourrait croire intuitivement, l&amp;rsquo;existence de nombreuses fonctions T n&amp;rsquo;est pas un frein majeur pour un attaquant. Si nous pouvons imaginer 1024 fonctions T distinctes, cela n&amp;rsquo;augmente l&amp;rsquo;entropie que de 10 bits (car log2(1024) = 10).&lt;/p&gt;
&lt;p&gt;Et pire : il existe un nouveau biais dans ces 10 bits si la fonction T est choisie par un humain en fonction de ses préférences et sa capacité à se souvenir du résultat de la fonction T ! Gageons que &lt;code&gt;AAAAAAAAAABBBBBBBBBBAAAAAAAABBBBBBBBBBBBBBAABBBBBBBBBBBBB&lt;/code&gt; est moins facilement mémorisable que &lt;code&gt;QO4T&lt;/code&gt; et que peu de personnes préfèreront la fonction T&lt;sub&gt;bis&lt;/sub&gt;
.&lt;/p&gt;
&lt;p&gt;Pour maintenant généraliser et formaliser ces conclusions, les fonctions T sont des bijections entre :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;un domaine de départ composé de nombres ou bits aléatoires ;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;un domaine d&amp;rsquo;arrivée composé de symboles (caractères, mots, phonèmes, etc.) ayant pour but d&amp;rsquo;être plus aisément mémorisables par un humain.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;S&amp;rsquo;agissant de bijections, la fonction T est inversible (T&lt;sup&gt;-1&lt;/sup&gt;
), ce qui signifie qu&amp;rsquo;en connaissant le fonctionnement de la fonction T et en observant le résultat d&amp;rsquo;une fonction T, on peut retrouver les bits aléatoires ayant servis à fabriquer ce résultat.&lt;/p&gt;
&lt;p&gt;On peut donc formaliser que l&amp;rsquo;objectif d&amp;rsquo;un·e attaquant·e est de retrouver les bits aléatoires ayant servis à fabriquer le mot de passe, quelle que soit sa représentation humainement mémorisable et quelle que soit la fonction T appliquée. Avec un mot de passe de 24 bits d&amp;rsquo;entropie et une fonction T connue, il faudra 2&lt;sup&gt;24&lt;/sup&gt;
 (≈ 16 millions) tentatives à l&amp;rsquo;attaquant pour le trouver avec une probabilité de 1 (100%).&lt;/p&gt;
&lt;h2 id=&#34;le-compromis-entre-entropie-densité-et-mémorabilité&#34;&gt;Le compromis entre entropie, densité et mémorabilité&lt;/h2&gt;
&lt;p&gt;Dans sa recommandation de 2022, la CNIL définit un seuil minimal d&amp;rsquo;entropie de 80 bits pour un mot de passe utilisé comme seul moyen d&amp;rsquo;identification. Cette recommandation est adressée sans spécifier de méthode de fabrication du mot de passe spécifique. Le choix de la fonction T est donc libre.&lt;/p&gt;
&lt;p&gt;En reprenant les exemples précédents, on peut calculer la longueur des mots de passe comme suit dans ce tableau.&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Taille de l&amp;rsquo;ensemble dans lequel sélectionner aléatoirement des éléments&lt;/th&gt;
          &lt;th&gt;Complexité du mot de passe&lt;/th&gt;
          &lt;th&gt;Entropie&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;un ensemble de 64 caractères (alphanumériques + caractères spéciaux )&lt;/td&gt;
          &lt;td&gt;14 caractères&lt;/td&gt;
          &lt;td&gt;≈ 84 bits&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://raw.githubusercontent.com/bitwarden/jslib/refs/heads/master/common/src/misc/wordlist.ts&#34;&gt;un dictionnaire de 7776&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;7 mots&lt;/td&gt;
          &lt;td&gt;≈ 83 bits&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;un ensemble de 36 phonèmes&lt;/td&gt;
          &lt;td&gt;16 phonèmes&lt;/td&gt;
          &lt;td&gt;≈ 83 bits&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;On peut observer que la densité est très variable, pour une même entropie.&lt;/p&gt;
&lt;p&gt;Alors qu&amp;rsquo;utiliser des caractères aléatoires représente 14 caractères à taper au clavier lors de l&amp;rsquo;authentification, taper des mots du dictionnaire représente 55 caractères, les mots faisant en moyenne 7 caractères, avec un caractère séparant les 7 mots (7 * 7 + 6). Sachant que la frappe de ces 55 caractères se fait généralement à l&amp;rsquo;aveugle, la moindre faute de frappe coute un temps considérable ! D&amp;rsquo;un autre côté, se souvenir de 14 caractères aléatoires sans aucun sens peut représenter un défi insurmontable pour la plupart des utilisateur·rices !&lt;/p&gt;
&lt;p&gt;Certain·es pourraient être alors tenté·es, comme suggéré par Fabien, d&amp;rsquo;utiliser des mots ou des phrases ayant un sens personnel particulier. Mais est-ce que 7 mots choisis par un humain contiennent bien 80 bits d&amp;rsquo;entropie ?!&lt;/p&gt;
&lt;p&gt;La question n&amp;rsquo;est pas simple, car il n&amp;rsquo;est pas possible de connaitre la fonction T qui a été utilisée ; il faudrait faire une imagerie du cerveau de la personne pour comprendre, au moment de la création du mot de passe, par quel procédé elle a inventé ce mot de passe ! 🧑‍⚕️&lt;/p&gt;
&lt;p&gt;Quand bien même, il est déjà possible de répondre à propos des phrases en langage naturel. En français, &lt;a href=&#34;https://www.tract-linguistes.org/combien-de-mots-utilise-t-on-comment-savoir-si-un-chiffre-est-farfelu-on-vous-explique-tout/&#34;&gt;il existe presque 300 mots-outils, et leur occurrence dans un texte serait de l&amp;rsquo;ordre d&amp;rsquo;un tiers du texte&lt;/a&gt; ! Cela veut dire qu&amp;rsquo;un mot sur trois porte en lui au maximum 8 bits (log2(300) ≈ 8,23) contre presque 13 bits quand on choisit un mot dans le dictionnaire de 7776 mots évoqué plus haut (log2(7776) ≈ 12,92). Cela réduit donc drastiquement la densité : l&amp;rsquo;entropie de 2 mots du dictionnaire est supérieure à celle de 3 mots-outils. Il en résulte donc la nécessité de mots de passe plus longs que 55 caractères pour maintenir une même quantité d&amp;rsquo;entropie.&lt;/p&gt;
&lt;p&gt;Outre les mots-outils, le français, comme toutes les langues, est structuré, comme expliqué plus haut dans cet article. Cela signifie que, dans une phrase syntaxiquement valide, le contexte détermine la nature des mots pouvant suivre ceux déjà sélectionnés, ce qui diminue encore la densité. Intuitivement &amp;ldquo;Je mange une pomme&amp;rdquo; est syntaxiquement correct et plus probable que &amp;ldquo;Mange je pomme une&amp;rdquo; qui est encore plus probable que &amp;ldquo;Rouge voiture conduit anticatastase&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Ensuite, concernant la taille du vocabulaire actif d&amp;rsquo;un français adulte, les chiffres ne sont pas clairs, et &lt;a href=&#34;https://www.tract-linguistes.org/combien-de-mots-utilise-t-on-comment-savoir-si-un-chiffre-est-farfelu-on-vous-explique-tout/&#34;&gt;beaucoup de faux chiffres semblent circuler&lt;/a&gt;. D&amp;rsquo;après &lt;a href=&#34;https://www.frontiersin.org/journals/psychology/articles/10.3389/fpsyg.2016.01116/full&#34;&gt;une étude du département de psychologie expérimentale de Ghent&lt;/a&gt;, en Belgique, l&amp;rsquo;adulte moyen de 20 ans, natif des États-Unis d&amp;rsquo;Amérique, connait 42000 lemmes. Chaque lemme serait alors porteur d&amp;rsquo;environ 15 bits d&amp;rsquo;entropie (log2(42000) ≈ 15.36), en admettant qu&amp;rsquo;ils soient choisis de manière aléatoire. L&amp;rsquo;amélioration est marginale: 6 lemmes sont nécessaires pour atteindre 80 bits d&amp;rsquo;entropie, contre 7 avec le dictionnaire !&lt;/p&gt;
&lt;p&gt;Reste à déterminer si un humain est capable de faire un choix réellement aléatoire (uniforme et indépendant) parmi ces 42000 lemmes. Comme le démontre très bien Fabien dans ses vidéos, l&amp;rsquo;humain est abominablement mauvais pour choisir quoi que ce soit aléatoirement. Les biais dans le choix &amp;ldquo;aléatoire&amp;rdquo; effectué par un humain viennent à nouveau réduire l&amp;rsquo;entropie, et incidemment réduire la densité si l&amp;rsquo;on veut garder le même niveau de sécurité. Il en résulte des mots de passe toujours plus longs 😱.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;L&amp;rsquo;objectif d&amp;rsquo;un mot de passe est de fournir un moyen d&amp;rsquo;identification mémorisable par un humain. Dès lors que ce dernier ne peut plus être mémorisé, il doit être stocké dans un gestionnaire de secrets. Et dès qu&amp;rsquo;on utilise un gestionnaire de secrets, alors la longueur du mot de passe ou sa mémorabilité cessent d&amp;rsquo;être un sujet : la machine peut mémoriser des téraoctets de données sans broncher.&lt;/p&gt;
&lt;p&gt;Simultanément, plus le mot de passe est facilement mémorisable, plus il est porteur de sémantique. Or, la structure du mot de passe et sa sémantique résultent en une sélection biaisée des constituants du mot de passe, et une diminution de la densité ou de l&amp;rsquo;entropie.&lt;/p&gt;
&lt;p&gt;Il en résulte une tension insoluble :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;un mot de passe à forte entropie peut être dense, mais il sera aussi peu mémorisable ;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;un mot de passe mémorisable est soit peu dense, et donc peu utilisable en pratique, soit il n&amp;rsquo;est pas de bonne qualité, car ne comportant pas une entropie d&amp;rsquo;au moins 80 bits.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;La méthode qui semble la plus propice à réduire cette tension est d&amp;rsquo;utiliser une série de mots indépendants et sélectionnés par la machine, et d&amp;rsquo;ensuite y donner du sens ou de les mémoriser tels quels par des méthodes comme celles promues par Fabien Olicard sur ses chaines Youtube (palais mental, etc.).&lt;/p&gt;
&lt;p&gt;Le mot de passe est cependant appelé à disparaitre tôt ou tard, à mesure que la puissance de calcul des machines grandit et avec elle la capacité des attaquant·es à retrouver toujours plus vite les mots de passe. Des solutions existent (comme les passkeys) mais leur adoption par le grand public reste encore à améliorer.&lt;/p&gt;
</description>
		</item>
		<item>
			<title>Managing files over WebDAV with Terraform</title>
			<link>https://broken-by-design.fr/posts/remotefs/</link>
			<pubDate>Mon, 08 Dec 2025 00:00:00 +0000</pubDate>
			<guid isPermaLink="true">https://broken-by-design.fr/posts/remotefs/</guid>
			<description>&lt;p&gt;A few weeks ago, I participated in a conversation on social media about the use of simple technologies like WebDAV instead of relying on modern and unreliable stuff like &lt;a href=&#34;https://github.com/minio/minio/commit/27742d469462e1561c776f88ca7a1f26816d69e2&#34;&gt;minio&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;WebDAV is boring and it is not gonna change its license or become obsolete because some shareholders decided they want more, so everybody else is gonna have less. WebDAV is an &lt;a href=&#34;https://www.rfc-editor.org/rfc/rfc4918&#34;&gt;Internet Standard&lt;/a&gt; implemented by Apache, nginx, Caddy and many others.&lt;/p&gt;
&lt;p&gt;Unfortunately, modern DevOps tools prefer to play with modern tech. It is easy to publish a blob on a S3-like platform with infrastructure as code tools like Terraform, but you are out of luck if you want to push that same blob on a WebDAV server. Or at least, you WERE out of luck because I decided to &lt;a href=&#34;https://infosec.exchange/@x_cli/115448668477171787&#34;&gt;follow through&lt;/a&gt; and develop a &lt;a href=&#34;https://registry.terraform.io/providers/X-Cli/remotefs/latest&#34;&gt;WebDAV Terraform provider&lt;/a&gt; on my free time! Hooray!&lt;/p&gt;
&lt;p&gt;OpenTofu is not supported at the moment because I used features that are not yet in an OpenTofu stable version. As soon as v1.11 is out, I&amp;rsquo;ll seek compatibility.&lt;/p&gt;
&lt;p&gt;Some of you may be wondering about these missing features. In short, OpenTofu &amp;lt; 1.11 misses ephemeral resources and write-only attributes. Those are very important features that enable secure-ish&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; secret handling in Terraform/OpenTofu. And because developing a Terraform provider with write-only attributes is a challenge, I decided to document the journey in this blog post.&lt;/p&gt;
&lt;p&gt;But first, let&amp;rsquo;s talk about my use cases.&lt;/p&gt;
&lt;h2 id=&#34;what-documents-could-i-possibly-publish-over-webdav-&#34;&gt;What Documents Could I Possibly Publish over WebDAV ?&lt;/h2&gt;
&lt;p&gt;WebDAV main current use case is CalDAV. Most people using an online calendar are probably synchronizing their events over WebDAV without ever knowing it.&lt;/p&gt;
&lt;p&gt;In the infrastructure that I have developed, I like to use WebDAV because it relies on mTLS for authentication. Transferring files over SSH/SFTP is fine as long as you are able to authenticate the SSH server. Unfortunately, this is rarely done. Most Terraform providers I audited are silently skipping the host key verification, allowing free meddle-in-the-middle (MITM) attacks and making the connection as secure as using Telnet&amp;hellip; This is why I developed the &lt;a href=&#34;https://registry.terraform.io/providers/X-Cli/ssh2vsock/latest&#34;&gt;SSH2VSOCK Terraform provider&lt;/a&gt;, which leverages the implicit trust you have in the hypervisor to access a guest VM over SSH without needing to verify the SSH host key. Unfortunately, this provider only works when using a (compatible) hypervisor. When using a bare metal server or an incompatible hypervisor, SSH host key verification remains a challenge.&lt;/p&gt;
&lt;p&gt;Meanwhile, secure TLS certificate deployment to authenticate servers (and clients) is trivial thanks to the &lt;a href=&#34;https://www.rfc-editor.org/rfc/rfc8555&#34;&gt;ACME protocol&lt;/a&gt;. Once the certificates are provisioned, tools like Terraform can safely connect to a WebDAV server over HTTPS, authenticate using their client certificate, and manage file over a secure channel.&lt;/p&gt;
&lt;p&gt;Using this secure channel, I can push configuration files like ignition configuration that are later served over HTTPS to Fedora CoreOS booting instances. I can also push shared secrets to several instances and avoid using centralized online secret managers, which carry their &lt;a href=&#34;https://app.opencve.io/cve/?product=vault&amp;amp;vendor=hashicorp&#34;&gt;own risks&lt;/a&gt;. This is a topic I discussed at length in a &lt;a href=&#34;https://pod.broken-by-design.fr/@yakafokon/episodes/comment-ne-pas-etre-dans-le-secret-des-dieux&#34;&gt;podcast episode&lt;/a&gt; (in French, but the transcript is available if you want to use a translator on it).&lt;/p&gt;
&lt;h2 id=&#34;secret-handling-in-terraform&#34;&gt;Secret Handling in Terraform&lt;/h2&gt;
&lt;p&gt;Handling secret in Terraform used to be a very bad practice. Terraform is a state machine, and a state machine is based on&amp;hellip; you guessed it: a state. And that state is stored in clear text&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;. OpenTofu implemented client-side encryption, using a passphrase, but the idea is cursed because it means anybody knowing the password can learn &lt;strong&gt;all&lt;/strong&gt; secrets stored in the state. If you want to fragment the knowledge, you have to fragment the workspace as well.&lt;/p&gt;
&lt;p&gt;Hashicorp (employees and community members) came up with a really smart solution to this issue: &lt;a href=&#34;https://developer.hashicorp.com/terraform/language/manage-sensitive-data/ephemeral&#34;&gt;the ephemeral resources and the write-only attributes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ephemeral resources have a different lifecycle from standard resources. They are created (opened) with every execution (plan or apply) and destroyed (closed) immediately after the execution. Thus, they are not persisted in the state. Write-only attributes can be assigned ephemeral values generated by the ephemeral resources. These attributes are NOT stored in state. Putting all of this together means you can &lt;a href=&#34;https://registry.terraform.io/providers/hashicorp/random/latest/docs/ephemeral-resources/password&#34;&gt;generate a password with an ephemeral resource&lt;/a&gt; and assign it to &lt;a href=&#34;https://registry.terraform.io/providers/Infisical/infisical/latest/docs/resources/secret#value_wo-1&#34;&gt;a write-only attribute&lt;/a&gt;, without it ever getting stored in the state.&lt;/p&gt;
&lt;p&gt;As such, Terraform can become a secret generator and distribution center without ever becoming a single point of failure.&lt;/p&gt;
&lt;h2 id=&#34;developing-a-terraform-resource-with-some-write-only-attributes&#34;&gt;Developing a Terraform resource with some write-only attributes&lt;/h2&gt;
&lt;p&gt;Write-only attributes are weird.&lt;/p&gt;
&lt;p&gt;When developing a resource, one implements the usual CRUD operations: Create, Read, Update and Destroy. Which of these functions is called depends on the plan. The called function receives the planned values as arguments. It then proceeds in making the intended changes. It is pretty straight forward.&lt;/p&gt;
&lt;p&gt;With write-only attributes, things change: the plan only contains null values for the write-only attributes. This is due to the fact that write-only attributes can receive ephemeral values. These values can be different with every invocation of Terraform. Building a plan containing values for these attributes would &lt;strong&gt;not&lt;/strong&gt; make sense, since these values might be different during the apply phase.&lt;/p&gt;
&lt;p&gt;To implement CRUD operations on resources containing write-only resources, you will need to get values both from the plan and from the configuration.&lt;/p&gt;
&lt;p&gt;Now the problem is that your resources won&amp;rsquo;t have any changes during the planning phase if the only thing that changes is a value assigned to a write-only attribute. The reason for this is that your plan is computed by comparing the state and the planned changes. Except your planned changes will contain a null value for your write-only attributes, and so will the state these write-only attributes&amp;hellip;. So since nothing has changed, there is nothing to do. Thank you very much.&lt;/p&gt;
&lt;p&gt;Don&amp;rsquo;t even think about adding a standard plan modifier like &lt;a href=&#34;https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier#RequiresReplace&#34;&gt;&lt;code&gt;RequireReplace()&lt;/code&gt;&lt;/a&gt;: the value did not change! It is still null, so there is nothing to replace!&lt;/p&gt;
&lt;p&gt;Terraform documentation contains some &amp;ldquo;&lt;a href=&#34;https://developer.hashicorp.com/terraform/plugin/framework/resources/write-only-arguments#best-practices&#34;&gt;best practices&lt;/a&gt;&amp;rdquo; to implement write-only attributes. The main advice is to pair up your write-only attributes with some standard read-write attributes (like a version number or a &lt;a href=&#34;https://registry.terraform.io/providers/hashicorp/random/latest/docs#resource-keepers&#34;&gt;keeper&lt;/a&gt;), or use some resource &lt;a href=&#34;https://developer.hashicorp.com/terraform/plugin/framework/resources/private-state&#34;&gt;private state&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Keepers and version numbers are exposed to the practitioners, which effectively means that we transfer on them the burden of deciding when to replace the resource.&lt;/p&gt;
&lt;p&gt;So I first attempted to rely exclusively on a private state and it somewhat worked until it did not.&lt;/p&gt;
&lt;h3 id=&#34;using-a-private-state&#34;&gt;Using a private state&lt;/h3&gt;
&lt;p&gt;First off, let&amp;rsquo;s clarify that the private state is not private in the sense that it is confidential. The private state is still part of the state that is sent in clear text to the &lt;a href=&#34;https://developer.hashicorp.com/terraform/language/backend&#34;&gt;state storage backend&lt;/a&gt;. Private only means that the content is not spilled in front of the practitioners&amp;rsquo; eyes and they cannot modify it directly. As such, storing the content of a write-only attribute configuration value in the private state effectively negates the very thing that makes write-only attributes usable as a security feature. If you are a security auditor, you should check that the developers did not do that&amp;hellip;&lt;/p&gt;
&lt;p&gt;The private state can be used to store a value derived from the write-only value. For instance, a cryptographic digest of the value assigned to the write-only attribute. When a new value is assigned, you can implement a &lt;a href=&#34;https://developer.hashicorp.com/terraform/plugin/framework/resources/plan-modification#resource-plan-modification&#34;&gt;custom plan modification function&lt;/a&gt; that will hash the new value and compare it with the digest stored in the private state. If the digest changes, it means the resource was updated and the resource needs to be updated/replaced.&lt;/p&gt;
&lt;p&gt;This may be acceptable, considering a cryptographic hash function is a one-way operation and learning the content of the private state is not supposed to yield information on the hashed data.&lt;/p&gt;
&lt;p&gt;And if you thought I was making any sense: gotcha. Yes, a cryptographic hash function is a one-way operation, but it is a deterministic one. As such, if a value is assigned to two resource instances, one won&amp;rsquo;t be able to know the assigned value just by looking at the state, &lt;strong&gt;but&lt;/strong&gt; one will be able to learn that it was the same value that was assigned to those two resource instances. That may be an undesired property. Also, if the assigned value is a low-to-medium entropy password, one could try and brute force the password value from the digest.&lt;/p&gt;
&lt;p&gt;As a consequence there is no universal answer here: depending on the content that may be assigned to the write-only attribute, you may want to hash the value with a &amp;ldquo;simple&amp;rdquo; cryptographic hash function, like SHA-512, or with a function that was built to derive passwords, like &lt;a href=&#34;https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html&#34;&gt;Argon2ID&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the case of the WebDAV provider I developed, I chose to expose to the practitioners a write-only attribute for the content of the managed files. Doing so helps prevent the state from being bloated with large file contents. It also helps prevent the storage of sensitive values in the state if the file contains stuff like passwords.&lt;/p&gt;
&lt;p&gt;To detect changes, I stored a digest in the private state and implemented a custom plan modification function. The practitioners can inform the provider if the content of the file contains sensitive values by specifying a hash salt. If no salt is not specified, the stored digest is computed with SHA-512. If a salt is specified, a SHA-512 digest is computed over the file content; it is then hex-encoded and used as input for the Argon2ID hash function with the salt value. Using this &amp;ldquo;weird&amp;rdquo; combination of SHA-512 + Argon2ID is just a way to avoid having to pass the whole file content to the Argon2ID function. This should not affect security, even if you believe &lt;a href=&#34;https://neilmadden.blog/2023/04/27/i-still-dont-really-get-hash-shucking/&#34;&gt;hash shucking&lt;/a&gt; gives you any advantage.&lt;/p&gt;
&lt;p&gt;As such, practitioners using my WebDAV provider can write stuff like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-terraform&#34; data-lang=&#34;terraform&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;terraform&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;required_providers&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;random&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;nx&#34;&gt;source&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;hashicorp/random&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;remotefs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;source&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;X-Cli/remotefs&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;variable&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;mysecret&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;ephemeral&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;provider&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;remotefs&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;webdav&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;base_url&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;YOUR_WEBDAV_SERVER_URL&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;random_pet&amp;#34;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;my-id&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;length&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Creates a /my-id file containing the random petname that was generated above
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;remotefs_file&amp;#34;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;davsecret&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;path&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/my-id&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;inline_content&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;random_pet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;my&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;id&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;random_bytes&amp;#34;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;salt&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;length&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;16&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Creates a /secret.txt file containing the secret specified as an ephemeral variable
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;remotefs_file&amp;#34;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;davsecret&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;path&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/secret.txt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;inline_content&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;mysecret&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;hash_salt&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;random_bytes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;salt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;hex&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This ought to work&amp;hellip; as long as you provide the same ephemeral value during the plan and the apply phases.&lt;/p&gt;
&lt;p&gt;But as soon as you try to do the following, the provider will explode in flight:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-terraform&#34; data-lang=&#34;terraform&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;terraform&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;required_providers&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;random&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;nx&#34;&gt;source&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;hashicorp/random&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;remotefs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;source&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;X-Cli/remotefs&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;provider&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;remotefs&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;webdav&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;base_url&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;YOUR_WEBDAV_SERVER_URL&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;ephemeral&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;random_password&amp;#34;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;mysecret&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;length&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;16&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;remotefs_file&amp;#34;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;mysecret&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;path&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/mysecret&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;inline_content&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ephemeral&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;random_password&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;mysecret&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;result&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is because the ephemeral random_password resource will generate a different value during the plan phase, the apply phase and the post-apply non-refresh plan phase that ensure that the apply phase went as expected. So the solution exposed in this section of the blog post only works for values that are not generated using an ephemeral resource. That may be OK for you but I would love to be able to generate random passwords like in the previous example. So we need another mechanism!&lt;/p&gt;
&lt;h3 id=&#34;using-keepers&#34;&gt;Using keepers&lt;/h3&gt;
&lt;p&gt;Keepers are a notion introduced by the &lt;a href=&#34;https://registry.terraform.io/providers/hashicorp/random/latest/docs#resource-keepers&#34;&gt;hashicorp/random&lt;/a&gt; provider. They consist of a map of values that have no ties with the business logic of the managed resource. Instead, the keepers are in control of the lifecycle of the managed resource: if the keeper map values change, the resource must be replaced.&lt;/p&gt;
&lt;p&gt;Using keeper values, one can ignore the digest difference between the private state and the assigned value and instead rely entirely on the keeper value changes.&lt;/p&gt;
&lt;p&gt;To support both workflows, I modified my custom plan modification function to skip the digest computation and comparison operations if the keeper attribute is not null, and I added a keeper attribute that has a plan modifier requiring resource replacement if it is updated. During the resource replacement, whatever the value that will be yielded by the ephemeral random_password resource during the apply phase will be used.&lt;/p&gt;
&lt;p&gt;Here is a working example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-terraform&#34; data-lang=&#34;terraform&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;terraform&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;required_providers&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;random&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;nx&#34;&gt;source&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;hashicorp/random&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;remotefs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;source&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;X-Cli/remotefs&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;variable&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;secret_version&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;description&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Increase this value when the secrets need to be renewed&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;number&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;provider&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;remotefs&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;webdav&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;base_url&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;YOUR_WEBDAV_SERVER_URL&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;ephemeral&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;random_password&amp;#34;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;mysecret&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;length&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;16&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;remotefs_file&amp;#34;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;mysecret&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;keepers&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;secret_version&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;secret_version&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;path&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/mysecret&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;inline_content&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ephemeral&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;random_password&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;mysecret&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;result&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Write-only attributes are weird to implement because they require extra logic and stuff you probably never used before in the Terraform plugin framework. Nevertheless they are an essential part of the ongoing revolution that is secret management as part of the Terraform configuration.&lt;/p&gt;
&lt;p&gt;Old farts like me, who enjoy publishing content thanks to reliable Internet standard protocols, can now do so with Terraform.&lt;/p&gt;
&lt;p&gt;In the following weeks, I expect to publish an update for that provider to support the SFTP protocol in case you already have the material to check the SSH host key (known_hosts file or SSHFP DNS records).&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;Go has no efficient and universal way of zeroizing freed memory. So you need to rely on the kernel to do it for you.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;Server-side state encryption is just sending your state in clear text to a service provider and hoping that they will encrypt the state as they said they would. Also, let&amp;rsquo;s hope there are no early TLS channel terminations, like &lt;a href=&#34;https://blog.cloudflare.com/password-reuse-rampant-half-user-logins-compromised/&#34;&gt;Cloudflare does&lt;/a&gt;.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description>
		</item>
		<item>
			<title>Expérimentation de Fedora CoreOS sur Proxmox : création de la machine virtuelle d&#39;installation</title>
			<link>https://broken-by-design.fr/posts/proxmox-fcos2/</link>
			<pubDate>Mon, 03 Jun 2024 00:00:00 +0200</pubDate>
			<guid isPermaLink="true">https://broken-by-design.fr/posts/proxmox-fcos2/</guid>
			<description>&lt;p&gt;Ce billet est le deuxième d&amp;rsquo;une série traitant de la création d&amp;rsquo;une
infrastructure virtualisée à l&amp;rsquo;aide de Proxmox&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; pour la partie
hyperviseur et de Fedora CoreOS&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; pour le système d&amp;rsquo;exploitation des
machines virtuelles invitées (&lt;em&gt;guests&lt;/em&gt;). L&amp;rsquo;infrastructure codifiée
(&lt;em&gt;Infrastructure as Code&lt;/em&gt;) est réalisée avec OpenTofu&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; (Hashicorp
Terraform ayant rejoint le côté obscur de la Force).&lt;/p&gt;
&lt;p&gt;Dans le premier billet&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;, nous avons évoqué les raisons qui ont mené
au choix de créer une machine virtuelle d&amp;rsquo;installation. Dans ce billet, nous
allons voir une solution technique preuve de concept satisfaisant ce besoin. Le
code source est publié en licence ouverte, afin que la communauté puisse en
bénéficier &lt;sup id=&#34;fnref:5&#34;&gt;&lt;a href=&#34;#fn:5&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;objectif est ici d&amp;rsquo;installer une machine virtuelle (sur Proxmox) qui permettra
d&amp;rsquo;en installer d&amp;rsquo;autres. La distribution Fedora CoreOS est utilisée pour ses
atouts de stabilité et de sécurité intrinsèques (et détaillés dans le premier
billet).&lt;/p&gt;
&lt;p&gt;Sur cette distribution, nous allons déployer un serveur DHCP qui permettra le
démarrage par le réseau des futures machines de l&amp;rsquo;infrastructure. Ce serveur
DHCP fournira un script iPXE&lt;sup id=&#34;fnref:6&#34;&gt;&lt;a href=&#34;#fn:6&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;6&lt;/a&gt;&lt;/sup&gt;, une version moderne et en source ouverte de
PXE (Preboot eXecution Environment), ainsi que des options DHCP distinctes en
fonction de la machine à installer. Ces options permettront notamment de fournir
une adresse réticulaire (URL) de type HTTP, afin de récupérer un fichier de
configuration Ignition spécifique à chaque machine à installer. Ce fichier
Ignition permettra la personnalisation de cette machine à partir de l&amp;rsquo;image
Fedora Core OS générique.&lt;/p&gt;
&lt;p&gt;Le serveur HTTP est le second service de cette machine virtuelle d&amp;rsquo;installation.
Il permet la publication des configurations Ignition, mais aussi du script iPXE
à exécuter, et de l&amp;rsquo;image de Fedora CoreOS à utiliser pour l&amp;rsquo;installation.&lt;/p&gt;
&lt;p&gt;Le dernier service de cette machine d&amp;rsquo;installation est un serveur de fichiers
sur lequel Opentofu (ou Terraform si vous y tenez vraiment) pourra déposer des
extensions de configuration DHCP et des fichiers Ignition : un pour chaque
machine virtuelle de l&amp;rsquo;infrastructure à installer. Dans cette preuve de concept,
le serveur de fichiers est un serveur SFTP. Nous verrons dans la suite de cet
article que c&amp;rsquo;est un choix par défaut, et qui n&amp;rsquo;est pas entièrement
satisfaisant.&lt;/p&gt;
&lt;h2 id=&#34;déploiement-de-services-sur-fedora-coreos&#34;&gt;Déploiement de services sur Fedora CoreOS&lt;/h2&gt;
&lt;h3 id=&#34;extensions-par-conteneurs&#34;&gt;Extensions par conteneurs&lt;/h3&gt;
&lt;p&gt;Fedora CoreOS est une distribution optimisée pour l&amp;rsquo;hébergement de conteneurs.
Son socle (constitué par les namespaces&lt;sup id=&#34;fnref:7&#34;&gt;&lt;a href=&#34;#fn:7&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;7&lt;/a&gt;&lt;/sup&gt; par défaut) ne contient que très
peu de programmes, et les interactions entre les différents logiciels le
composant ainsi qu&amp;rsquo;avec les conteneurs sont fortement limitées par le
durcissement mis en place, notamment avec SELinux.&lt;/p&gt;
&lt;p&gt;Cette distribution permet bien d&amp;rsquo;installer des logiciels additionnels sur le
socle, grâce à un système de surcouches (&lt;em&gt;layering&lt;/em&gt;) de rpm-ostree&lt;sup id=&#34;fnref:8&#34;&gt;&lt;a href=&#34;#fn:8&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;8&lt;/a&gt;&lt;/sup&gt;.
Cette éventualité doit cependant être écartées dans le cas de cette machine
virtuelle d&amp;rsquo;installation ; en effet, celle-ci démarre sur un LiveCD ISO et la
propriété d&amp;rsquo;immuabilité de Fedora CoreOS &amp;ldquo;interdit&amp;rdquo; l&amp;rsquo;ajout de nouveaux
programmes sur le système en cours d&amp;rsquo;exécution.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;ensemble des services déployés doivent donc l&amp;rsquo;être grâce à des conteneurs. Ce
n&amp;rsquo;est pas si différent de ce qui doit être fait dans un cluster Kubernetes, et
il n&amp;rsquo;est pas étonnant que Red Hat CoreOS soit utilisée comme socle pour la
plateforme OpenShift&lt;sup id=&#34;fnref:9&#34;&gt;&lt;a href=&#34;#fn:9&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;9&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;De même, les volumes des conteneurs ne sont qu&amp;rsquo;assez rarement des
bind-mount&lt;sup id=&#34;fnref:10&#34;&gt;&lt;a href=&#34;#fn:10&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;10&lt;/a&gt;&lt;/sup&gt; de répertoires arbitraires du socle, et plus
généralement des volumes (anonymes ou nommés) du moteur de conteneurs. Cela est
dû aux politiques SELinux&lt;sup id=&#34;fnref:11&#34;&gt;&lt;a href=&#34;#fn:11&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;11&lt;/a&gt;&lt;/sup&gt; qui restreignent les interactions
avec les fichiers dans les volumes, qui doivent avoir (principalement) les types
&lt;code&gt;container_file_t&lt;/code&gt; ou &lt;code&gt;container_ro_file_t&lt;/code&gt;&lt;sup id=&#34;fnref:12&#34;&gt;&lt;a href=&#34;#fn:12&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;12&lt;/a&gt;&lt;/sup&gt;, ce qu&amp;rsquo;ont rarement
les fichiers du socle.&lt;/p&gt;
&lt;p&gt;Ainsi, le service DHCP et le service HTTP sont déployés sous la forme de
conteneurs, et en conséquence, le serveur de fichiers doit l&amp;rsquo;être également,
puisqu&amp;rsquo;il sert à ajouter du contenu aux volumes exposés aux deux premiers
services.&lt;/p&gt;
&lt;p&gt;Une autre conséquence est que si un conteneur doit disposer de fichiers
pré-existants dans des volumes, il faut trouver un moyen de les y placer. La
méthode la plus propre et la plus simple est d&amp;rsquo;utiliser des conteneurs
d&amp;rsquo;initialisation&lt;sup id=&#34;fnref:13&#34;&gt;&lt;a href=&#34;#fn:13&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;13&lt;/a&gt;&lt;/sup&gt;, à l&amp;rsquo;instar de ce qui est fait dans les
déploiements Kubernetes. Podman dispose également de la commande &lt;code&gt;podman kube&lt;/code&gt;
qui permet d&amp;rsquo;émuler en partie les déploiements Kubernetes et notamment les
objets ConfigMap&lt;sup id=&#34;fnref:14&#34;&gt;&lt;a href=&#34;#fn:14&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;14&lt;/a&gt;&lt;/sup&gt;. Les ConfigMaps étant plus &amp;ldquo;limitées&amp;rdquo; que le
dépôts de fichiers arbitraires, il a été choisi pour cette preuve de concept
d&amp;rsquo;utiliser exclusivement des conteneurs d&amp;rsquo;initialisation.&lt;/p&gt;
&lt;h3 id=&#34;les-podman-quadlets&#34;&gt;Les Podman Quadlets&lt;/h3&gt;
&lt;p&gt;Fedora CoreOS dispose par défaut des moteurs Moby (Docker) et Podman.&lt;/p&gt;
&lt;p&gt;S&amp;rsquo;il est bien sûr possible d&amp;rsquo;utiliser &lt;code&gt;compose&lt;/code&gt; pour définir les conteneurs, les
orchestrer et les lancer, il est également possible d&amp;rsquo;utiliser les Podman
Quadlets&lt;sup id=&#34;fnref:15&#34;&gt;&lt;a href=&#34;#fn:15&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;15&lt;/a&gt;&lt;/sup&gt;. Les Quadlets sont des fichiers de configuration ressemblant
à des unités systemd (&lt;em&gt;systemd units&lt;/em&gt;), avec des sections en plus. Il en existe
de plusieurs types : conteneurs, pods, images, volumes, réseaux, et même une
couche de compatibilité avec la syntaxe Kubernetes.&lt;/p&gt;
&lt;p&gt;Voici par exemple le quadlet pour le volume stockant les baux DHCP de notre
preuve de concept, stocké dans le fichier /etc/containers/systemd/dhcp_data.volume :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[Unit]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Description = DHCP Data Volume
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[Volume]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;VolumeName = dhcp_data
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Device=/dev/disk/by-label/dhcp_data
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Options=nodev,noexec,nosuid,rootcontext=system_u:object_r:container_file_t:s0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Type=ext4
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Le quadlet du conteneur d&amp;rsquo;initialisation téléchargeant la dernière image de Fedora CoreOS est :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Unit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Description&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Download&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Latest&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FCOS&lt;/span&gt; &lt;span class=&#34;ne&#34;&gt;Image&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ne&#34;&gt;Container&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;ContainerName&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fcos_downloader&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;ne&#34;&gt;Image&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;image_downloader&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Exec&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;download&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;stable&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pxe&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Volume&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fcos_images&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;volume&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;z&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;WorkingDir&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Install&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;WantedBy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;multi&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;user&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Ils sont consommés par un générateur de services systemd qui transforme ces
quadlets, situés dans &lt;code&gt;/etc/containers/systemd&lt;/code&gt;, en services, situés dans
&lt;code&gt;/run/systemd/generator&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;un des intérêts des quadlets est leur intégration au sein de systemd, avec la
possibilité de contrôler de manière assez fine les dépendances avec d&amp;rsquo;autres
services.&lt;/p&gt;
&lt;p&gt;En outre, leur syntaxe permet également de monter automatiquement des systèmes
de fichiers sur des volumes. Couplé à la facilité de créer des partitions avec
Ignition, il est ainsi trivial de créer une partition par volume. Il s&amp;rsquo;agit
d&amp;rsquo;une bonne pratique de sécurité qui permet de limiter les risques de dénis de
service ou de corruption entre conteneurs par saturation d&amp;rsquo;un système de
fichiers commun à plusieurs volumes.&lt;/p&gt;
&lt;h2 id=&#34;difficultés-rencontrées&#34;&gt;Difficultés rencontrées&lt;/h2&gt;
&lt;p&gt;Un projet ne serait pas une aventure, sans son lot d&amp;rsquo;ornières et d&amp;rsquo;imprévus.
Quelle aventure se fut !&lt;/p&gt;
&lt;h3 id=&#34;problèmes-avec-le-fournisseur-ignition-dopentofu&#34;&gt;Problèmes avec le fournisseur Ignition d&amp;rsquo;Opentofu&lt;/h3&gt;
&lt;p&gt;Les fichiers de configuration Ignition sont des documents JSON.&lt;/p&gt;
&lt;p&gt;Chaque document JSON décrit une machine complète : partitions, systèmes de
fichiers, fichiers de configuration systemd, fichiers arbitaires, répertoires,
utilisateurs et groupes, etc. Le contenu des fichiers à créer est sérialisé
dans ce document JSON, soit verbatim, soit sous la forme d&amp;rsquo;une adresse de type
&lt;code&gt;data:&lt;/code&gt;&lt;sup id=&#34;fnref:16&#34;&gt;&lt;a href=&#34;#fn:16&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;16&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Il est possible qu&amp;rsquo;un fichier de configuration Ignition contienne des
directives d&amp;rsquo;inclusion/fusion d&amp;rsquo;autres fichiers Ignition pouvant être récupérés
notamment par le réseau. Il faut dans ce cas s&amp;rsquo;assurer de l&amp;rsquo;intégrité de ces
fichiers distants, afin de prévenir la compromission totale du serveur.&lt;/p&gt;
&lt;p&gt;Fedora CoreOS étant un système d&amp;rsquo;exploitation immuable, reposant sur des images
systèmes administrées par &lt;code&gt;rpm-ostree&lt;/code&gt;, l&amp;rsquo;image de base est la même pour toutes
les machines d&amp;rsquo;une infrastructure virtualisée ; les machines se diversifient et
se spécialisent via leur configuration Ignition. Cette approche est donc opposée
à celles impliquant la pré-personnalisation des images avec des outils comme
Packer&lt;sup id=&#34;fnref:17&#34;&gt;&lt;a href=&#34;#fn:17&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;17&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Le moment et la manière de générer la configuration Ignition peut varier en
fonction des préférences individuelles. Le plus gros de la configuration peut
être statique : tous les serveurs HTTP ont besoin des mêmes images de
conteneurs, des mêmes scripts de démarrage, des mêmes partitions et volumes pour
stocker certaines informations de manière persistante. Tout cela peut être
stocké dans un fichier Ignition commun à toutes les instances et ultérieurement
inclus, ou être mis dans le fichier Ignition de chaque instance. C&amp;rsquo;est au choix.
Avec une approche cloud-init, ces fichiers feraient parties de l&amp;rsquo;image générée
avec Packer.&lt;/p&gt;
&lt;p&gt;En revanche, le contenu servi par ces serveurs HTTP ou l&amp;rsquo;adresse IP d&amp;rsquo;écoute
sont des informations spécifiques à chaque instance. Avec l&amp;rsquo;approche cloud-init,
ces informations seraient communiquées au système d&amp;rsquo;exploitation par le service
de métadonnées interrogé par l&amp;rsquo;utilitaire cloud-init.&lt;/p&gt;
&lt;p&gt;Dans le cas d&amp;rsquo;espèce, puisque nous n&amp;rsquo;avons pas encore d&amp;rsquo;infrastructure
virtualisée, pas de serveur HTTP de confiance où stocker et distribuer la
configuration commune à toutes les machines virtuelles d&amp;rsquo;installation, et que le
fichier Ignition va être stocké dans un ISO personnalisé de Fedora CoreOS, nous
n&amp;rsquo;allons générer qu&amp;rsquo;un seul fichier Ignition, contenant les informations
communes à plusieurs instances éventuelles et les informations spécifiques à une
instance spécifique.&lt;/p&gt;
&lt;p&gt;Concernant la conception du document JSON au format Ignition, nous pourrions
écrire cette configuration Ignition avec n&amp;rsquo;importe quel outil, y compris
&amp;ldquo;manuellement&amp;rdquo;, mais ultérieurement, nous le ferons avec Opentofu, au moins pour
les informations spécifiques. Par cohérence, Opentofu a donc également été
utilisé pour cette machine.&lt;/p&gt;
&lt;p&gt;Étant donné que les fichiers Ignition sont exprimés en JSON, il est possible de
structurer ses données en HCL (HashiCorp Configuration Language), puis de faire
appel à la fonction &lt;code&gt;jsonencode&lt;/code&gt;. Pour autant, Hashicorp a initialement
développé un fournisseur Terraform pour Ignition&lt;sup id=&#34;fnref:18&#34;&gt;&lt;a href=&#34;#fn:18&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;18&lt;/a&gt;&lt;/sup&gt;, qui a
ensuite été abandonné, puis repris par la communauté&lt;sup id=&#34;fnref:19&#34;&gt;&lt;a href=&#34;#fn:19&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;19&lt;/a&gt;&lt;/sup&gt;. Ce
fournisseur propose des sources de données (&lt;em&gt;data sources&lt;/em&gt;) afin de structurer
la configuration Terraform et la typer.&lt;/p&gt;
&lt;p&gt;Ce fournisseur est assez basique puisqu&amp;rsquo;il se contente de codifier sous la forme
d&amp;rsquo;un schéma de source de données les champs des différentes structures définies
dans la spécification d&amp;rsquo;Ignition&lt;sup id=&#34;fnref:20&#34;&gt;&lt;a href=&#34;#fn:20&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;20&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Avec le fournisseur, on écrit donc :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-hcl&#34; data-lang=&#34;hcl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;data&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;ignition_file&amp;#34; &amp;#34;dnsmasq_container&amp;#34;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    path&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/etc/containers/systemd/dnsmasq.container&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    mode&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;420&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;content&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;        content&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;${path.module}/files/dnsmasq.container&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;data&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;ignition_config&amp;#34; &amp;#34;example&amp;#34;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    files&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;ignition_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;dnsmasq_container&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;rendered&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;locals&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    serialized_config&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;ignition_config&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;example&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;rendered&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;En HCL &amp;ldquo;pur&amp;rdquo;, pour comparaison, on écrit :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-hcl&#34; data-lang=&#34;hcl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;locals&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    dnsmasq_container_file&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;        path&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/etc/containers/systemd/dnsmasq.container&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;        mode&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;420&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;        contents&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;            source&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;s2&#34;&gt;&amp;#34;data:text/plain;base64,%s&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;k&#34;&gt;base64encode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;${path.module}/files/dnsmasq.container&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    serialized_config&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;jsonencode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;        ignition&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;            version&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;3.4.0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;        storage&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;            files&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;k&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;dnsmasq_container_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    }&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La différence de verbosité entre les deux versions n&amp;rsquo;est pas flagrante ; mais
surtout, le fournisseur comporte plusieurs problèmes : le document JSON généré
n&amp;rsquo;est pas minimal, certaines générations sont incorrectes, et il manque des
options pourtant spécifiées dans la version 3.4.0 du format Ignition.&lt;/p&gt;
&lt;p&gt;La génération non-minimaliste est dû à l&amp;rsquo;usage par le fournisseur des types
définis dans le code source de l&amp;rsquo;outil Ignition lui-même&lt;sup id=&#34;fnref:21&#34;&gt;&lt;a href=&#34;#fn:21&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;21&lt;/a&gt;&lt;/sup&gt;. Par
exemple la structure racine d&amp;rsquo;une configuration Ignition est définie ainsi :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;type Ignition struct {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	Config   IgnitionConfig `json:&amp;#34;config,omitempty&amp;#34;`
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	Proxy    Proxy          `json:&amp;#34;proxy,omitempty&amp;#34;`
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	Security Security       `json:&amp;#34;security,omitempty&amp;#34;`
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	Timeouts Timeouts       `json:&amp;#34;timeouts,omitempty&amp;#34;`
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	Version  string         `json:&amp;#34;version&amp;#34;`
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La plupart des champs sont définis avec l&amp;rsquo;annotation de sérialisation JSON
&lt;code&gt;omitempty&lt;/code&gt;. Quand cette annotation est utilisée de manière correcte, le champ
n&amp;rsquo;apparait pas dans le document JSON généré avec la fonction &lt;code&gt;json.Marshal&lt;/code&gt; si
sa valeur est &amp;ldquo;fausse&amp;rdquo; ou &amp;ldquo;vide&amp;rdquo; selon le système de typage du langage Go. Or,
les sous-structures ne sont pas définies comme des pointeurs. Ainsi, elles ne
peuvent jamais être &amp;ldquo;vides&amp;rdquo;, et les champs sont toujours ajoutés au document
JSON, même si elles ne contiennent aucune valeur.&lt;/p&gt;
&lt;p&gt;Voici la configuration générée par le code ci-dessus utilisant le fournisseur :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;ignition&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;config&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &amp;#34;replace&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &amp;#34;verification&amp;#34;: {}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;proxy&amp;#34;: {},
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;security&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &amp;#34;tls&amp;#34;: {}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;timeouts&amp;#34;: {},
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;version&amp;#34;: &amp;#34;3.4.0&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;kernelArguments&amp;#34;: {},
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;passwd&amp;#34;: {},
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;storage&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;files&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &amp;#34;group&amp;#34;: {},
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &amp;#34;overwrite&amp;#34;: false,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &amp;#34;path&amp;#34;: &amp;#34;/etc/containers/systemd/dnsmasq.container&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &amp;#34;user&amp;#34;: {},
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &amp;#34;contents&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &amp;#34;source&amp;#34;: &amp;#34;data:text/plain;charset=utf-8;base64,W1VuaXRdCkRlc2NyaXB0aW9uID0gREhDUCBDb250YWluZXIKCldhbnRzPWltYWdlX2Rvd25sb2FkZXIuc2VydmljZQpBZnRlcj1pbWFnZV9kb3dubG9hZGVyLnNlcnZpY2UKV2FudHM9bmV0d29yay1vbmxpbmUudGFyZ2V0CkFmdGVyPW5ldHdvcmstb25saW5lLnRhcmdldApXYW50cz1kaGNwX2NvbmZpZ19pbml0LnNlcnZpY2UKQWZ0ZXI9ZGhjcF9jb25maWdfaW5pdC5zZXJ2aWNlCgpbQ29udGFpbmVyXQpDb250YWluZXJOYW1lID0gZG5zbWFzcV9jb250YWluZXIKSW1hZ2UgPSBsb2NhbGhvc3QvZG5zbWFzcTpsYXRlc3QKVm9sdW1lID0gZGhjcF9jb25maWcudm9sdW1lOi9ldGMvZG5zbWFzcS5kOnoKVm9sdW1lID0gZGhjcF9kYXRhLnZvbHVtZTovZGF0YTpaClZvbHVtZSA9IC9kZXYvbG9nOi9kZXYvbG9nCk5ldHdvcmsgPSBob3N0CkFkZENhcGFiaWxpdHkgPSBDQVBfTkVUX0FETUlOLENBUF9ORVRfUkFXCgpbU2VydmljZV0KV29ya2luZ0RpcmVjdG9yeT0vdmFyL3Jvb3Rob21lL2RoY3AKRXhlY1N0YXJ0UHJlPS9iaW4vYmFzaCAvdmFyL3Jvb3Rob21lL2dlbmVyYXRlX2RoY3Bfb3B0aW9ucy5zaApFeGVjU3RhcnRQcmU9L3Vzci9iaW4vcG9kbWFuIGJ1aWxkIC10IGRuc21hc3E6bGF0ZXN0IC4KUmVzdGFydD1vbi1mYWlsdXJlCgpbSW5zdGFsbF0KV2FudGVkQnk9bXVsdGktdXNlci50YXJnZXQKCg==&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &amp;#34;verification&amp;#34;: {}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        },
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &amp;#34;mode&amp;#34;: 420
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;systemd&amp;#34;: {}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;En comparaison, voici le document JSON généré en écrivant soi-même en HCL la configuration Ignition :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;ignition&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;version&amp;#34;: &amp;#34;3.4.0&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;storage&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;files&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &amp;#34;contents&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &amp;#34;source&amp;#34;: &amp;#34;data:text/plain;base64,W1VuaXRdCkRlc2NyaXB0aW9uID0gREhDUCBDb250YWluZXIKCldhbnRzPWltYWdlX2Rvd25sb2FkZXIuc2VydmljZQpBZnRlcj1pbWFnZV9kb3dubG9hZGVyLnNlcnZpY2UKV2FudHM9bmV0d29yay1vbmxpbmUudGFyZ2V0CkFmdGVyPW5ldHdvcmstb25saW5lLnRhcmdldApXYW50cz1kaGNwX2NvbmZpZ19pbml0LnNlcnZpY2UKQWZ0ZXI9ZGhjcF9jb25maWdfaW5pdC5zZXJ2aWNlCgpbQ29udGFpbmVyXQpDb250YWluZXJOYW1lID0gZG5zbWFzcV9jb250YWluZXIKSW1hZ2UgPSBsb2NhbGhvc3QvZG5zbWFzcTpsYXRlc3QKVm9sdW1lID0gZGhjcF9jb25maWcudm9sdW1lOi9ldGMvZG5zbWFzcS5kOnoKVm9sdW1lID0gZGhjcF9kYXRhLnZvbHVtZTovZGF0YTpaClZvbHVtZSA9IC9kZXYvbG9nOi9kZXYvbG9nCk5ldHdvcmsgPSBob3N0CkFkZENhcGFiaWxpdHkgPSBDQVBfTkVUX0FETUlOLENBUF9ORVRfUkFXCgpbU2VydmljZV0KV29ya2luZ0RpcmVjdG9yeT0vdmFyL3Jvb3Rob21lL2RoY3AKRXhlY1N0YXJ0UHJlPS9iaW4vYmFzaCAvdmFyL3Jvb3Rob21lL2dlbmVyYXRlX2RoY3Bfb3B0aW9ucy5zaApFeGVjU3RhcnRQcmU9L3Vzci9iaW4vcG9kbWFuIGJ1aWxkIC10IGRuc21hc3E6bGF0ZXN0IC4KUmVzdGFydD1vbi1mYWlsdXJlCgpbSW5zdGFsbF0KV2FudGVkQnk9bXVsdGktdXNlci50YXJnZXQKCg==&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        },
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &amp;#34;mode&amp;#34;: 420,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &amp;#34;path&amp;#34;: &amp;#34;/etc/containers/systemd/dnsmasq.container&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Cette définition incorrecte des types dans le code source d&amp;rsquo;Ignition n&amp;rsquo;est pas
trivial à corriger car ces types sont générés par un outil appelé
&lt;code&gt;schematyper&lt;/code&gt;&lt;sup id=&#34;fnref:22&#34;&gt;&lt;a href=&#34;#fn:22&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;22&lt;/a&gt;&lt;/sup&gt;. Cet outil prend en entrée une description de
données au format JSON Schema&lt;sup id=&#34;fnref:23&#34;&gt;&lt;a href=&#34;#fn:23&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;23&lt;/a&gt;&lt;/sup&gt;, et écrit en sortie des définitions de structures
en Go.&lt;/p&gt;
&lt;p&gt;Dans le cas d&amp;rsquo;espèce, cette verbosité excessive n&amp;rsquo;est pas forcément gênante car
nous n&amp;rsquo;avons pas de contrainte de taille de fichiers. Certains services de
metadonnées cloud en ont cependant une (généralement autour de 16ko) ; dans
ces cas, la taille compte.&lt;/p&gt;
&lt;p&gt;Également, bien que les champs soient bien définis par le code source
d&amp;rsquo;Ignition, le fournisseur Terraform est incomplet et plusieurs définitions
manquent, rendant impossible l&amp;rsquo;utilisation de certaines options. Ce n&amp;rsquo;est pas
que c&amp;rsquo;est difficile à ajouter&amp;hellip; mais leur absence cumulée au fait qu&amp;rsquo;exprimer en
HCL une configuration Ignition fait qu&amp;rsquo;il devient immédiatement préférable de
s&amp;rsquo;en passer.&lt;/p&gt;
&lt;h3 id=&#34;problèmes-avec-la-prise-en-charge-de-sftp-par-opentofu&#34;&gt;Problèmes avec la prise en charge de SFTP par Opentofu&lt;/h3&gt;
&lt;p&gt;La solution proposée utilise SFTP afin de permettre l&amp;rsquo;extension de la
configuration du serveur DHCP et la publication de fichiers Ignition pour les
futures machines virtuelles qui composeront l&amp;rsquo;infrastructure.&lt;/p&gt;
&lt;p&gt;SFTP est un service natif d&amp;rsquo;OpenSSH, un des démons les plus exposés et les plus
sensibles puisque sa présence est quasi universelle et qu&amp;rsquo;il transporte
notamment les flux d&amp;rsquo;administration. Son emploi est particulièrement intéressant
pour le type de transfert de fichiers utilisé dans cette preuve de concept,
grâce à son chiffrement de flux par défaut, son identification native par clé
publique, et ses capacités d&amp;rsquo;isolation à l&amp;rsquo;aide de chroot&lt;sup id=&#34;fnref:24&#34;&gt;&lt;a href=&#34;#fn:24&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;24&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;De surcroit, la configuration est triviale :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Subsystem sftp internal-sftp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Match User terraform_ignition
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ForceCommand internal-sftp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ChrootDirectory /my/chroot/path
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Compte tenu des politiques de sécurité SELinux en place par défaut sur Fedora
CoreOS, il n&amp;rsquo;est pas possible d&amp;rsquo;utiliser le processus OpenSSH Server du socle.
En effet, lors de la réception des fichiers, ces derniers sont marqués avec le
type SELinux &lt;code&gt;user_home_t&lt;/code&gt; avec lequel les conteneurs ne peuvent interagir.&lt;/p&gt;
&lt;p&gt;Pour cette raison, la preuve de concept dispose de deux serveurs SSH : un pour
se connecter au socle et un autre, accessible uniquement en SFTP, permettant le
téléversement de fichiers. Ainsi, les fichiers déposés en SFTP sont marqués avec
le type &lt;code&gt;container_file_t&lt;/code&gt; qui peut être lu par d&amp;rsquo;autres conteneurs.&lt;/p&gt;
&lt;p&gt;Hélas, ce superbe service SFTP ne peut être utilisé nativement par Opentofu&amp;hellip;
En effet, l&amp;rsquo;espoir était que les configurations DHCP soient générées par
Opentofu, écrites sur disque à l&amp;rsquo;aide d&amp;rsquo;une ressource
&lt;code&gt;local_file&lt;/code&gt;&lt;sup id=&#34;fnref:25&#34;&gt;&lt;a href=&#34;#fn:25&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;25&lt;/a&gt;&lt;/sup&gt; ou même une &lt;code&gt;null_resource&lt;/code&gt;&lt;sup id=&#34;fnref:26&#34;&gt;&lt;a href=&#34;#fn:26&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;26&lt;/a&gt;&lt;/sup&gt;, puis
téléversées grâce au mécanisme d&amp;rsquo;approvisionnement (&lt;em&gt;provisioner&lt;/em&gt;)
&amp;ldquo;file&amp;rdquo;&lt;sup id=&#34;fnref:27&#34;&gt;&lt;a href=&#34;#fn:27&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;27&lt;/a&gt;&lt;/sup&gt;. Le code aurait ressemblé à :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-hcl&#34; data-lang=&#34;hcl&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;null_resource&amp;#34; &amp;#34;ignition_configuration&amp;#34;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;provisioner&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;file&amp;#34;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    content&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;encoded_config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;    destination&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;writable/${vm_id}.ign&amp;#34;&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;connection&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;      type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;ssh&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;      host&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;netboot_server_ip&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;      port&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;2222&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;      user&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;terraform_ignition&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;      agent&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;      bastion_host&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;pve_host&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;      bastion_user&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;pve_pam_user&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;      bastion_port&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;22&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Il s&amp;rsquo;avère néanmoins que cela n&amp;rsquo;est pas possible, et une tentative renvoie le
message d&amp;rsquo;erreur :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Upload&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;failed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;his&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;service&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;allows&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sftp&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;connections&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;only&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La documentation explique que :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Provisioners which execute commands on a remote system via a protocol such as
SSH typically achieve that by uploading a script file to the remote system and
then asking the default shell to execute it.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Ce mécanisme d&amp;rsquo;approvisionnement ayant pour but la copie de fichiers notamment
par SSH n&amp;rsquo;est pas compatible avec le mécanisme standard de transfert de fichiers
de SSH&lt;sup id=&#34;fnref:28&#34;&gt;&lt;a href=&#34;#fn:28&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;28&lt;/a&gt;&lt;/sup&gt;&amp;hellip;&lt;/p&gt;
&lt;p&gt;La preuve de concept actuelle repose donc sur plusieurs mécanismes
d&amp;rsquo;approvisionnement, dont &lt;code&gt;local-exec&lt;/code&gt;&lt;sup id=&#34;fnref:29&#34;&gt;&lt;a href=&#34;#fn:29&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;29&lt;/a&gt;&lt;/sup&gt; afin d&amp;rsquo;exécuter la commande
&lt;code&gt;sftp&lt;/code&gt; via le shell. Comme cette solution est un bricolage peu satisfaisant,
l&amp;rsquo;auteur de cet article envisage de développer, dans un futur plus ou moins
proche, un fournisseur Opentofu pour la gestion de ressources de type fichiers
au travers du protocole WebDav&lt;sup id=&#34;fnref:30&#34;&gt;&lt;a href=&#34;#fn:30&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;30&lt;/a&gt;&lt;/sup&gt;, afin de palier cette situation.&lt;/p&gt;
&lt;h3 id=&#34;problèmes-avec-le-fournisseur-opentofu-pour-proxmox&#34;&gt;Problèmes avec le fournisseur Opentofu pour Proxmox&lt;/h3&gt;
&lt;p&gt;Le fournisseur Opentofu pour Proxmox &lt;code&gt;bpg/proxmox&lt;/code&gt;&lt;sup id=&#34;fnref:31&#34;&gt;&lt;a href=&#34;#fn:31&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;31&lt;/a&gt;&lt;/sup&gt; est le fournisseur le
plus avancé disponible sur les registres de Terraform.&lt;/p&gt;
&lt;p&gt;Hélas, ce dernier ne dispose pas d&amp;rsquo;une ressource pour le téléversement de
fichiers ISO. La ressource &lt;code&gt;proxmox_virtual_environement_file&lt;/code&gt; permet certes le
téléversement de fichiers arbitraires, mais comme l&amp;rsquo;indique la documentation, un
transfert par SSH vers l&amp;rsquo;hyperviseur est impliqué, au lieu d&amp;rsquo;utiliser l&amp;rsquo;API de
Proxmox. La surface d&amp;rsquo;attaque de cette ressource est donc bien plus importante
que si l&amp;rsquo;API avait été utilisée. C&amp;rsquo;est d&amp;rsquo;autant plus regrettable que l&amp;rsquo;API
fournit bien un moyen de téléverser des fichiers ISO.&lt;/p&gt;
&lt;p&gt;En conséquence, dans cette preuve de concept, le mécanisme d&amp;rsquo;approvisionnement
&lt;code&gt;local-exec&lt;/code&gt; d&amp;rsquo;Opentofu a été utilisé afin de téléverser le fichier avec
l&amp;rsquo;utilitaire &lt;code&gt;curl&lt;/code&gt; par l&amp;rsquo;API de Proxmox :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;provisioner&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;local-exec&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;command&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EOT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;curl&lt;/span&gt; \
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;F&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;content=iso&amp;#34;&lt;/span&gt; \
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;F&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;filename=@customized-${random_pet.config_name.id}.iso;type=application/vnd.efi.iso;filename=fcos-netboot-server-${random_pet.config_name.id}.iso&amp;#34;&lt;/span&gt; \
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;H&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;@${local_file.api_token.filename}&amp;#34;&lt;/span&gt; \
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;s2&#34;&gt;&amp;#34;${var.pve_api_base_url}nodes/${var.pve_node_name}/storage/${var.pve_storage_id}/upload&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;EOT&lt;/span&gt;      
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Une ressource de type &lt;code&gt;local_file&lt;/code&gt; a également été utilisée pour stocker le
jeton d&amp;rsquo;API, de manière à éviter d&amp;rsquo;exposer le jeton directement sur la ligne de
commandes&lt;sup id=&#34;fnref:32&#34;&gt;&lt;a href=&#34;#fn:32&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;32&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h3 id=&#34;problèmes-avec-systemdpath-et-la-détection-de-changements-de-fichiers-dans-un-répertoire&#34;&gt;Problèmes avec systemd.path et la détection de changements de fichiers dans un répertoire&lt;/h3&gt;
&lt;p&gt;Le serveur DHCP utilisé par cette preuve de concept repose sur &lt;code&gt;dnsmasq&lt;/code&gt;.
Celui-ci contient certainement moins de fonctionnalités que le serveur de l&amp;rsquo;ISC,
mais il convient parfaitement pour le démarrage par le réseau.&lt;/p&gt;
&lt;p&gt;Une fonctionnalité manquante sur ces deux logiciels est la capacité de recharger
automatiquement la configuration lors de son changement ou de son extension. Or,
cette preuve de concept repose sur l&amp;rsquo;extensibilité de la configuration par
Opentofu : lorsqu&amp;rsquo;une nouvelle machine est ajoutée à l&amp;rsquo;infrastructure, des
options DHCP sont définies dynamiquement pour permettre son installation. En
particulier, une option DHCP indique où trouver le fichier de configuration
Ignition spécifique à cette machine à installer et une autre indique le chemin
du disque dur sur lequel effectuer l&amp;rsquo;installation.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dhcp-host=${mac_address},set:${hostname}tag,${host_ip},${hostname}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dhcp-option=tag:${hostname}tag,encap:128,2,&amp;#34;${vm_id}.ign&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dhcp-option=tag:${hostname}tag,encap:128,3,&amp;#34;/dev/disk/by-path/pci-0000:00:0a.0&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Le redémarrage du service pourrait être fait avec un mécanisme
d&amp;rsquo;approvisionnement de type remote-exec&lt;sup id=&#34;fnref:33&#34;&gt;&lt;a href=&#34;#fn:33&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;33&lt;/a&gt;&lt;/sup&gt;, mais cette solution
nécessite la capacité d&amp;rsquo;exécuter des commandes sur le socle depuis Opentofu.&lt;/p&gt;
&lt;p&gt;Opentofu dispose déjà de la capacité d&amp;rsquo;exécuter des commandes arbitraires sur
toutes les machines de l&amp;rsquo;infrastructure par injection de commandes et de
fichiers dans les configurations Ignition. Cela demande néanmoins le redémarrage
de la machine virtuelle pour appliquer la nouvelle configuration, ce qui n&amp;rsquo;est
pas forcément très discret pour un attaquant qui souhaiterait ainsi compromettre
des machines.&lt;/p&gt;
&lt;p&gt;Une solution plus propre et ne nécessitant pas d&amp;rsquo;accès shell est de surveiller
les fichiers de configuration avec &lt;code&gt;inotify&lt;/code&gt;&lt;sup id=&#34;fnref:34&#34;&gt;&lt;a href=&#34;#fn:34&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;34&lt;/a&gt;&lt;/sup&gt;. Inotify est une
fonctionnalité du noyau Linux qui permet d&amp;rsquo;émettre des événements lors
d&amp;rsquo;opérations sur le système de fichiers. Les programmes intéréssés peuvent
s&amp;rsquo;abonner à ces événements en vue d&amp;rsquo;y réagir.&lt;/p&gt;
&lt;p&gt;Systemd peut être configuré pour surveiller le système de fichiers avec &lt;code&gt;inotify&lt;/code&gt;,
grâce aux unités de type &lt;code&gt;path&lt;/code&gt;&lt;sup id=&#34;fnref:35&#34;&gt;&lt;a href=&#34;#fn:35&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;35&lt;/a&gt;&lt;/sup&gt;. La configuration ressemble à ceci :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[Unit]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Description = Path Monitor for DHCP Config
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[Path]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PathChanged=/path/to/monitored/path
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;TriggerLimitIntervalSec=0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[Install]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;WantedBy=multi-user.target
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Cette unité d&amp;rsquo;exemple active un service du même nom que celui de l&amp;rsquo;unité de type
&lt;code&gt;path&lt;/code&gt; lorsque le chemin indiqué subit une modification. Ce chemin peut être un
fichier ou un répertoire. Dans le cas d&amp;rsquo;un répertoire, les changements
n&amp;rsquo;interviennent que lors de la suppression ou de l&amp;rsquo;ajout d&amp;rsquo;un fichier ; les
opérations de modification des fichiers contenus dans un répertoire n&amp;rsquo;entrainent
pas de modification du répertoire lui-même.&lt;/p&gt;
&lt;p&gt;Hélas, bien qu&amp;rsquo;il existe une directive &lt;code&gt;PathExistsGlob&lt;/code&gt; permettant l&amp;rsquo;usage de
chaines de substitution (e.g. &lt;code&gt;*.conf&lt;/code&gt;), il n&amp;rsquo;existe aucune directive de type
&lt;code&gt;PathChangedGlob&lt;/code&gt; qui permettrait la surveillance de tous les fichiers au sein
d&amp;rsquo;un répertoire. Un ticket à ce sujet est ouvert depuis plusieurs
années&lt;sup id=&#34;fnref:36&#34;&gt;&lt;a href=&#34;#fn:36&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;36&lt;/a&gt;&lt;/sup&gt;. Un bricolage pour s&amp;rsquo;accomoder de la situation est de
supprimer les fichiers de configuration existants avant d&amp;rsquo;ajouter les nouveaux,
de façon à provoquer un ou deux redémarrages du service&lt;sup id=&#34;fnref:37&#34;&gt;&lt;a href=&#34;#fn:37&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;37&lt;/a&gt;&lt;/sup&gt; et la prise
en compte de la nouvelle configuration.&lt;/p&gt;
&lt;p&gt;Un autre défaut de cette solution est qu&amp;rsquo;elle exige que systemd &amp;ldquo;espionne&amp;rdquo; les
fichiers déposés par SFTP dans un volume géré par Podman. Cela implique de faire
une hypothèse sur les chemins utilisés par Podman ou de monter une deuxième fois
le système de fichiers associé à ce volume à un chemin connu du socle. Si le
montage peut sembler plus propre, il faut considérer que lorsqu&amp;rsquo;on monte un même
système de fichiers à de multiples endroits, il faut que les options de montage
soient identiques, y compris les informations relatives à SELinux (e.g.
l&amp;rsquo;option &lt;code&gt;rootcontext&lt;/code&gt;). Il faut alors à nouveau faire des hypothèses : les
options utilisées par les Quadlets Podman lors du montage du système de fichiers
sur le volume.&lt;/p&gt;
&lt;p&gt;Dans le ticket précédemment évoqué, un moyen de contournement est évoqué :
utiliser l&amp;rsquo;utilitaire &lt;code&gt;inotifywatch&lt;/code&gt;&lt;sup id=&#34;fnref:38&#34;&gt;&lt;a href=&#34;#fn:38&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;38&lt;/a&gt;&lt;/sup&gt;. Ce programme permet la
surveillance de plusieurs fichiers dans un répertoire, nommés suivant un motif
spécifié. Hélas, ce dernier n&amp;rsquo;est pas disponible sur le socle de Fedora CoreOS,
et comme expliqué précédemment, il n&amp;rsquo;est pas possible d&amp;rsquo;installer des logiciels
additionnels dans notre cas d&amp;rsquo;usage. Il est cependant possible de l&amp;rsquo;utiliser
dans un conteneur qui aurait également accès au volume des extensions de
configuration DHCP. Une pierre, deux coups : on contournerait la limitation de
systemd et on ne ferait plus d&amp;rsquo;hypothèse sur le chemin d&amp;rsquo;accès ! Hélas, il reste
ensuite à trouver un moyen de redémarrer le service dnsmasq depuis le conteneur
ayant détecté le changement&amp;hellip;&lt;/p&gt;
&lt;p&gt;Donner un accès SSH sur le socle depuis le conteneur de surveillance semble la
voie royale. Hélas, cet accès est compliqué à donner, du fait des politiques
SELinux, encore une fois, ou du plan d&amp;rsquo;adressage dynamique de la couche réseau
de Podman.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;hypothèse à faire sur le plan d&amp;rsquo;adressage de Podman est de connaitre l&amp;rsquo;adresse
IP associée au socle. Elle doit être faite si on tente de se connecter en SSH au
socle par le réseau. Une solution pour éviter de faire des hypothèses sur la
couche réseau est d&amp;rsquo;établir la connexion SSH à travers une socket Unix
bind-montée dans le conteneur de surveillance. Exposer un service SSH sur socket
Unix à d&amp;rsquo;autres conteneurs ou utilisateurs est une astuce assez élégante
notamment discutée par Timothée Ravier, développeur de CoreOS, sur son blog dans
le cadre d&amp;rsquo;un remplacement de &lt;code&gt;sudo&lt;/code&gt; par une connexion SSH locale&lt;sup id=&#34;fnref:39&#34;&gt;&lt;a href=&#34;#fn:39&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;39&lt;/a&gt;&lt;/sup&gt;.
Hélas, dans le cas d&amp;rsquo;espèce, les politiques SELinux empêchent la connexion de
&lt;code&gt;socat&lt;/code&gt;, utilisé par le client SSH du conteneur, à la socket Unix exposée par le
serveur SSHD du socle.&lt;/p&gt;
&lt;p&gt;En conséquence, sur cette problématique, aucune solution satisfaisante n&amp;rsquo;a été
trouvée. La solution retenue est, en attendant de trouver mieux, d&amp;rsquo;utiliser une
unité systemd de type &lt;code&gt;path&lt;/code&gt; en faisant l&amp;rsquo;hypothèse sur le chemin du volume
Podman, et en supprimant puis en rajoutant le fichier de configuration, afin de
déclencher le redémarrage du service.&lt;/p&gt;
&lt;h1 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;Cet article a couvert une partie des problèmes rencontrés et des solutions
proposées pour la création d&amp;rsquo;une preuve de concept d&amp;rsquo;un serveur d&amp;rsquo;installation
pour une infrastructure basée sur Fedora CoreOS sur Proxmox. Le code est
ouvert&lt;sup id=&#34;fnref1:5&#34;&gt;&lt;a href=&#34;#fn:5&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt; et les commentaires sont les bienvenues, afin d&amp;rsquo;améliorer
cette dernière et permettre à la communauté d&amp;rsquo;en bénéficier.&lt;/p&gt;
&lt;p&gt;Grâce à cette machine d&amp;rsquo;installation, il devient trivial de déployer de
nouvelles machines faisant tourner Fedora CoreOS. Il suffit pour cela de
téléverser le fichier Ignition de la machine à installer et un fichier
d&amp;rsquo;extension de la configuration de dnsmasq, puis de configurer la nouvelle
machine virtuelle pour démarrer par le réseau.&lt;/p&gt;
&lt;p&gt;Ces téléversements peuvent s&amp;rsquo;effectuer lors de la déclaration de la nouvelle
machine virtuelle dans la configuration d&amp;rsquo;Opentofu.&lt;/p&gt;
&lt;p&gt;Dans le prochain billet de cette série, nous verrons comment déployer, grâce à
cette machine d&amp;rsquo;installation, un serveur DNS&lt;sup id=&#34;fnref:40&#34;&gt;&lt;a href=&#34;#fn:40&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;40&lt;/a&gt;&lt;/sup&gt;, un serveur
ACME&lt;sup id=&#34;fnref:41&#34;&gt;&lt;a href=&#34;#fn:41&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;41&lt;/a&gt;&lt;/sup&gt;, et un cluster etcd&lt;sup id=&#34;fnref:42&#34;&gt;&lt;a href=&#34;#fn:42&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;42&lt;/a&gt;&lt;/sup&gt;, en vue d&amp;rsquo;installer une instance
d&amp;rsquo;Openbao&lt;sup id=&#34;fnref:43&#34;&gt;&lt;a href=&#34;#fn:43&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;43&lt;/a&gt;&lt;/sup&gt;, et ainsi pouvoir enfin créer des instances de Fedora CoreOS
sans placer de secrets dans les fichiers Ignition.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.proxmox.com/en/&#34;&gt;https://www.proxmox.com/en/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://fedoraproject.org/coreos/&#34;&gt;https://fedoraproject.org/coreos/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://opentofu.org/&#34;&gt;https://opentofu.org/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.broken-by-design.fr/posts/proxmox-fcos1/&#34;&gt;https://www.broken-by-design.fr/posts/proxmox-fcos1/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:5&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://git.broken-by-design.fr/fmaury/iac&#34;&gt;https://git.broken-by-design.fr/fmaury/iac&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:5&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref1:5&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:6&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://ipxe.org/&#34;&gt;https://ipxe.org/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:6&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:7&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.man7.org/linux/man-pages/man7/namespaces.7.html&#34;&gt;https://www.man7.org/linux/man-pages/man7/namespaces.7.html&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:7&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:8&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://coreos.github.io/rpm-ostree/&#34;&gt;https://coreos.github.io/rpm-ostree/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:8&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:9&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.redhat.com/fr/technologies/cloud-computing/openshift&#34;&gt;https://www.redhat.com/fr/technologies/cloud-computing/openshift&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:9&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:10&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://docs.docker.com/storage/bind-mounts/&#34;&gt;https://docs.docker.com/storage/bind-mounts/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:10&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:11&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/containers/container-selinux/blob/main/container_selinux.8&#34;&gt;https://github.com/containers/container-selinux/blob/main/container_selinux.8&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:11&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:12&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/containers/container-selinux/blob/main/container.te&#34;&gt;https://github.com/containers/container-selinux/blob/main/container.te&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:12&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:13&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://kubernetes.io/docs/concepts/workloads/pods/init-containers/&#34;&gt;https://kubernetes.io/docs/concepts/workloads/pods/init-containers/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:13&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:14&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://kubernetes.io/docs/concepts/configuration/configmap/&#34;&gt;https://kubernetes.io/docs/concepts/configuration/configmap/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:14&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:15&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html&#34;&gt;https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:15&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:16&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.rfc-editor.org/rfc/rfc2397&#34;&gt;https://www.rfc-editor.org/rfc/rfc2397&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:16&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:17&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.packer.io/&#34;&gt;https://www.packer.io/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:17&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:18&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/hashicorp/terraform-provider-ignition&#34;&gt;https://github.com/hashicorp/terraform-provider-ignition&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:18&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:19&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/community-terraform-providers/terraform-provider-ignition&#34;&gt;https://github.com/community-terraform-providers/terraform-provider-ignition&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:19&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:20&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://coreos.github.io/ignition/configuration-v3_4/&#34;&gt;https://coreos.github.io/ignition/configuration-v3_4/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:20&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:21&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/coreos/ignition/blob/v2.18.0/config/v3_4/types/schema.go&#34;&gt;https://github.com/coreos/ignition/blob/v2.18.0/config/v3_4/types/schema.go&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:21&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:22&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/idubinskiy/schematyper&#34;&gt;https://github.com/idubinskiy/schematyper&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:22&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:23&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://json-schema.org/&#34;&gt;https://json-schema.org/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:23&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:24&#34;&gt;
&lt;p&gt;&lt;code&gt;chroot(2)&lt;/code&gt; est un appel système qui permet de restreindre la
capacité d&amp;rsquo;un processus à changer de répertoires ; bien utilisé, il permet
de restreindre les accès à un sous-ensemble de la hiérarchie des fichiers
d&amp;rsquo;un système de fichiers sous Linux.&amp;#160;&lt;a href=&#34;#fnref:24&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:25&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file&#34;&gt;https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:25&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:26&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource&#34;&gt;https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:26&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:27&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://developer.hashicorp.com/terraform/language/resources/provisioners/file&#34;&gt;https://developer.hashicorp.com/terraform/language/resources/provisioners/file&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:27&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:28&#34;&gt;
&lt;p&gt;Le protocole SCP est devenu obsolète à la suite d&amp;rsquo;une vulnérabilité
protocolaire irréparable : &lt;a href=&#34;https://lwn.net/Articles/835962/&#34;&gt;https://lwn.net/Articles/835962/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:28&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:29&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://developer.hashicorp.com/terraform/language/resources/provisioners/local-exec&#34;&gt;https://developer.hashicorp.com/terraform/language/resources/provisioners/local-exec&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:29&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:30&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.rfc-editor.org/rfc/rfc4918&#34;&gt;https://www.rfc-editor.org/rfc/rfc4918&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:30&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:31&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://registry.terraform.io/providers/bpg/proxmox/latest/docs&#34;&gt;https://registry.terraform.io/providers/bpg/proxmox/latest/docs&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:31&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:32&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://cwe.mitre.org/data/definitions/214&#34;&gt;https://cwe.mitre.org/data/definitions/214&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:32&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:33&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://developer.hashicorp.com/terraform/language/resources/provisioners/remote-exec&#34;&gt;https://developer.hashicorp.com/terraform/language/resources/provisioners/remote-exec&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:33&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:34&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.man7.org/linux/man-pages/man7/inotify.7.html&#34;&gt;https://www.man7.org/linux/man-pages/man7/inotify.7.html&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:34&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:35&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.freedesktop.org/software/systemd/man/latest/systemd.path.html&#34;&gt;https://www.freedesktop.org/software/systemd/man/latest/systemd.path.html&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:35&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:36&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/systemd/systemd/issues/14330&#34;&gt;https://github.com/systemd/systemd/issues/14330&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:36&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:37&#34;&gt;
&lt;p&gt;L&amp;rsquo;incertitude entre un ou deux redémarrage provient du fait
qu&amp;rsquo;inotify ne garantit pas un événement distinct par opération recherchée.
Si deux événements de même type se produisent avant qu&amp;rsquo;un observateur/abonné
ne soit informé du premier, un unique événement lui est rapporté.&amp;#160;&lt;a href=&#34;#fnref:37&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:38&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.man7.org/linux/man-pages/man1/inotifywatch.1.html&#34;&gt;https://www.man7.org/linux/man-pages/man1/inotifywatch.1.html&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:38&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:39&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://tim.siosm.fr/blog/2023/12/19/ssh-over-unix-socket/&#34;&gt;https://tim.siosm.fr/blog/2023/12/19/ssh-over-unix-socket/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:39&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:40&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.knot-resolver.cz/&#34;&gt;https://www.knot-resolver.cz/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:40&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:41&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://caddyserver.com/docs/caddyfile/directives/acme_server&#34;&gt;https://caddyserver.com/docs/caddyfile/directives/acme_server&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:41&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:42&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://etcd.io/&#34;&gt;https://etcd.io/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:42&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:43&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://openbao.org/&#34;&gt;https://openbao.org/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:43&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
		</item>
		<item>
			<title>Expérimentation de Fedora CoreOS sur Proxmox</title>
			<link>https://broken-by-design.fr/posts/proxmox-fcos1/</link>
			<pubDate>Wed, 29 May 2024 00:00:00 +0200</pubDate>
			<guid isPermaLink="true">https://broken-by-design.fr/posts/proxmox-fcos1/</guid>
			<description>&lt;p&gt;Ce billet est le premier d&amp;rsquo;une série de billets traitant de la création d&amp;rsquo;une
infrastructure virtualisée à l&amp;rsquo;aide de Proxmox&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; pour la partie
hyperviseur, de Fedora CoreOS&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; pour le système d&amp;rsquo;exploitation des machines
virtuelles invitées (&lt;em&gt;guests&lt;/em&gt;). L&amp;rsquo;infrastructure codifiée (&lt;em&gt;Infrastructure as
Code&lt;/em&gt;) est réalisée avec OpenTofu&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; (Hashicorp Terraform ayant rejoint
le côté obscur de la Force).&lt;/p&gt;
&lt;h2 id=&#34;présentation-de-proxmox&#34;&gt;Présentation de Proxmox&lt;/h2&gt;
&lt;p&gt;Proxmox est un ensemble d&amp;rsquo;outils, voire une distribution Linux à part entière
reposant sur Debian, permettant l&amp;rsquo;administration d&amp;rsquo;une infrastructure
virtualisée en ligne de commande, via une interface web, ou grâce à une API.
Proposant des options de stockage réparti, de réseau étendu à un groupe
d&amp;rsquo;instances (&lt;em&gt;cluster&lt;/em&gt;), de groupes de sécurité, de haute disponibilité, pour
n&amp;rsquo;en citer que quelques-unes, il s&amp;rsquo;agit d&amp;rsquo;une solution qui peut remplacer
aisément VMWare, au minimum sur les cas d&amp;rsquo;usage relativement simples.&lt;/p&gt;
&lt;h2 id=&#34;présentation-de-fedora-coreos&#34;&gt;Présentation de Fedora CoreOS&lt;/h2&gt;
&lt;p&gt;Fedora CoreOS est une distribution Linux orientée sur la stabilité et la
sécurité. Son objectif principal est l&amp;rsquo;hébergement de conteneurs, et pour cette
raison, elle est pourvue d&amp;rsquo;un socle minimaliste et durci, mis à jour
automatiquement. Ces mises à jour automatiques sont aisément réversibles en
cas de problème, grâce à son approche pseudo-immuable&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;,
reposant sur rpm-ostree, et son système de mise à jour (Zincati) permet
également d&amp;rsquo;orchestrer ces dernières de façon à maintenir un service hautement
disponible.&lt;/p&gt;
&lt;p&gt;Fedora CoreOS est également un système d&amp;rsquo;exploitation à part en cela
qu&amp;rsquo;il est conçu pour ne pas avoir besoin d&amp;rsquo;interagir directement avec le
système, que ce soit pour l&amp;rsquo;installation/configuration ou l&amp;rsquo;administration.
L&amp;rsquo;idée est qu&amp;rsquo;un cas de changement de configuration, on réinstalle totalement le
système. Au premier démarrage, lors de l&amp;rsquo;exécution de l&amp;rsquo;initramfs, le programme
ignition&lt;sup id=&#34;fnref:5&#34;&gt;&lt;a href=&#34;#fn:5&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt; exécute une recette qui configure le système : formatage et
partitionnement des disques, ajout des utilisateurs, copies de fichiers et de
services, etc..&lt;/p&gt;
&lt;p&gt;Si cette approche peut sembler lourde de prime abord, elle présente en réalité
l&amp;rsquo;avantage d&amp;rsquo;apporter la sérénité à ses administrateurs et administratrices ; en
effet, il est dès lors possible de réaliser la recette de la nouvelle
configuration à l&amp;rsquo;identique dans un environnement de préproduction, sans risque
d&amp;rsquo;interférence avec l&amp;rsquo;existant (&lt;em&gt;snowflake servers&lt;/em&gt;&lt;sup id=&#34;fnref:6&#34;&gt;&lt;a href=&#34;#fn:6&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;6&lt;/a&gt;&lt;/sup&gt;).&lt;/p&gt;
&lt;p&gt;Ignition et cloud-init&lt;sup id=&#34;fnref:7&#34;&gt;&lt;a href=&#34;#fn:7&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;7&lt;/a&gt;&lt;/sup&gt; sont des cousins éloignés. Les deux
participent à la configuration et la personnalisation d&amp;rsquo;une image système. Le
moment de l&amp;rsquo;exécution est cependant très différent et importe. En effet,
Ignition intervient lors de l&amp;rsquo;initramfs, tandis que cloud-init intervient plus
tard lors du démarrage du système d&amp;rsquo;exploitation. Ignition est donc en mesure de
modifier les tables des partitions avant que le véritable système d&amp;rsquo;exploitation
ne démarre, et préconfigure le système comme si cette configuration avait
toujours existé ou avait été modifiée lors d&amp;rsquo;une exécution précédente.&lt;/p&gt;
&lt;p&gt;Ignition possède néanmoins quelques limitations, assumées, notamment si on le
compare à Ansible. En effet, Ansible possède de très nombreux greffons lui
permettant d&amp;rsquo;effectuer des actions riches sur un système en cours d&amp;rsquo;exécution.
Ignition permet essentiellement la copie de fichiers et de services, et les
opérations complexes doivent être effectuées par des scripts shell (Fedora
CoreOS n&amp;rsquo;installe pas Python, par exemple). Ce choix est raisonnable étant donné
que relativement peu d&amp;rsquo;opérations d&amp;rsquo;administration sont attendues sur le socle
faisant tourner Fedora CoreOS.&lt;/p&gt;
&lt;p&gt;En outre, Ansible Vault permet le stockage et le déploiement sécurisé de
secrets, y compris dans les outils de versionnement de code comme git. Ignition,
pour sa part, ne permet pas la communication de secrets de manière sécurisée ;
au mieux, il est possible de les stocker dans un fichier qui sera téléchargé
puis fusionné avec le reste de la configuration par Ignition. Cette solution
n&amp;rsquo;étant pas très satisfaisante, il est donc nécessaire d&amp;rsquo;utiliser un
gestionnaire de secrets comme OpenBao (Hashicorp Vault ayant rejoint le côté
obscur de la Force)&lt;sup id=&#34;fnref:8&#34;&gt;&lt;a href=&#34;#fn:8&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;8&lt;/a&gt;&lt;/sup&gt; avec l&amp;rsquo;emballage de réponses&lt;sup id=&#34;fnref:9&#34;&gt;&lt;a href=&#34;#fn:9&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;9&lt;/a&gt;&lt;/sup&gt;, Bitwarden
Send&lt;sup id=&#34;fnref:10&#34;&gt;&lt;a href=&#34;#fn:10&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;10&lt;/a&gt;&lt;/sup&gt; ou Bitwarden Secret Manager&lt;sup id=&#34;fnref:11&#34;&gt;&lt;a href=&#34;#fn:11&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;11&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h2 id=&#34;défis-dun-déploiement-de-fedora-coreos-sur-proxmox&#34;&gt;Défis d&amp;rsquo;un déploiement de Fedora CoreOS sur Proxmox&lt;/h2&gt;
&lt;p&gt;Proxmox dispose d&amp;rsquo;une couche de compatibilité native avec Cloud-init. Celle-ci
n&amp;rsquo;est hélas pas générique, et ne permet pas de configurer toutes les options de
Cloud-init. Avec OpenTofu et le fournisseur &lt;code&gt;bpg/proxmox&lt;/code&gt;&lt;sup id=&#34;fnref:12&#34;&gt;&lt;a href=&#34;#fn:12&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;12&lt;/a&gt;&lt;/sup&gt;, il est
possible de fabriquer à la volée un ISO disposant du label CIDATA, et ainsi
d&amp;rsquo;exploiter le mode &amp;ldquo;nocloud&amp;rdquo; de cloud-init&lt;sup id=&#34;fnref:13&#34;&gt;&lt;a href=&#34;#fn:13&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;13&lt;/a&gt;&lt;/sup&gt;. Tout ceci n&amp;rsquo;aide
cependant pas au déploiement de Fedora CoreOS.&lt;/p&gt;
&lt;p&gt;Il existe une multitude de moyens de fournir un fichier de configuration à
Ignition : par HTTP après une indication par PXE ou sur la ligne de commande du
noyau, directement dans le fichier ISO d&amp;rsquo;installation après une personnalisation
de ce dernier, dans une variable du micrologiciel (firmware), etc. Hélas,
l&amp;rsquo;utilisation d&amp;rsquo;un ISO séparé, à l&amp;rsquo;instar du mode &amp;ldquo;nocloud&amp;rdquo; de cloud-init, n&amp;rsquo;est
pas une option. Nous allons néanmoins voir qu&amp;rsquo;aucune des autres options n&amp;rsquo;est
native à Proxmox ou satisfaisante.&lt;/p&gt;
&lt;h3 id=&#34;fourniture-de-ladresse-du-fichier-ignition-par-pxe&#34;&gt;Fourniture de l&amp;rsquo;adresse du fichier Ignition par PXE&lt;/h3&gt;
&lt;p&gt;Proxmox dispose d&amp;rsquo;une couche réseau programmable/configurable (&lt;em&gt;Software-defined
Network&lt;/em&gt; (SDN)) assez développée. Cette dernière permet la définition de
différentes zones réseau, avec un filtrage des flux par règles et par groupes de
sécurité. En outre, elle fournit différents services, dont un serveur DHCP
branché sur un IPAM (&lt;em&gt;IP Address Management&lt;/em&gt;), avec possible synchronisation des
adresses avec un serveur DNS.&lt;/p&gt;
&lt;p&gt;Hélas, il n&amp;rsquo;est pas possible (par l&amp;rsquo;interface web ou l&amp;rsquo;API) de personnaliser la
configuration DHCP pour y rajouter les options nécessaires à PXE, ni d&amp;rsquo;ajouter
un service pour publier les fichiers de configuration Ignition par HTTP ou TFTP.&lt;/p&gt;
&lt;p&gt;Il est bien sûr possible de se connecter en console, en root, pour modifier
cette configuration, mais cela demande des privilèges élevés sur l&amp;rsquo;hyperviseur,
et ce n&amp;rsquo;est pas officiellement supporté par Proxmox. Il est donc préférable de
rechercher une voie alternative, supportée et ne nécessitant que peu de
privilèges.&lt;/p&gt;
&lt;h3 id=&#34;fourniture-du-fichier-de-configuration-par-personnalisation-du-fichier-iso&#34;&gt;Fourniture du fichier de configuration par personnalisation du fichier ISO&lt;/h3&gt;
&lt;p&gt;La personnalisation du fichier ISO de Fedora CoreOS est assez aisée. En effet,
ses développeurs fournissent, notamment sous la forme de conteneurs, des outils
pour ajouter des fichiers et modifier la ligne de commande du
noyau&lt;sup id=&#34;fnref:14&#34;&gt;&lt;a href=&#34;#fn:14&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;14&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Cette approche nécessite cependant d&amp;rsquo;avoir un fichier ISO distinct par poste à
installer. Ce fichier doit à nouveau être téléversé en intégralité à chaque
modification de la configuration Ignition, ce qui est consommateur de bande
passante. Il peut surement être possible d&amp;rsquo;utiliser un LXC hébergé par Proxmox
pour faire cette personnalisation directement sur l&amp;rsquo;hyperviseur, sans nécessiter
le téléversement.&lt;/p&gt;
&lt;p&gt;Au niveau stockage, il est possible de ne pas trop surconsommer du fait que
Proxmox prend en charge nativement btrfs&lt;sup id=&#34;fnref:15&#34;&gt;&lt;a href=&#34;#fn:15&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;15&lt;/a&gt;&lt;/sup&gt; et ZFS, et que ces systèmes de
fichiers permettent la déduplication des blocs. Cette approche relève cependant
d&amp;rsquo;une certaine forme de bricolage, avec de potentielles pertes de performances
dans le cas de ZFS ou d&amp;rsquo;espace disque dans le cas de btrfs si la déduplication
n&amp;rsquo;est pas demandée assez souvent.&lt;/p&gt;
&lt;h3 id=&#34;fourniture-du-fichier-de-configuration-par-une-variable-du-micrologiciel&#34;&gt;Fourniture du fichier de configuration par une variable du micrologiciel&lt;/h3&gt;
&lt;p&gt;La fourniture du fichier de configuration par une variable de micrologiciel
s&amp;rsquo;effectue en ajoutant un argument à la commande qemu qui lance la machine
virtuelle. Cet argument ressemble à la ligne suivante :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-fw_cfg name=opt/com.coreos/config,file=/local/path/to/config.ign
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Cet argument peut être fourni en modifiant le fichier de configuration de la
machine virtuelle sur l&amp;rsquo;hyperviseur dans le répertoire
&lt;code&gt;/etc/pve/qemu-server/&amp;lt;vm_id&amp;gt;.conf&lt;/code&gt;. Cette méthode nécessite néanmoins la
connexion en utilisateur root (via le console ou en SSH), ce qui n&amp;rsquo;est pas
forcément souhaitable, et la manipulation plus ou moins manuelle de fichiers
système.&lt;/p&gt;
&lt;p&gt;Il peut être également fourni lors des appels à l&amp;rsquo;API, et le greffon OpenTofu
&lt;code&gt;bpg/proxmox&lt;/code&gt; permet de le faire avec l&amp;rsquo;attribut &lt;code&gt;kvm_paramters&lt;/code&gt; de la ressource
&lt;code&gt;proxmox_virtual_environment_vm&lt;/code&gt;. Cette méthode nécessite cependant qu&amp;rsquo;OpenTofu
se connecte avec l&amp;rsquo;utilisateur &lt;code&gt;root@pam&lt;/code&gt;, avec mot de passe et sans avoir
défini de second facteur d&amp;rsquo;authentification. En effet, Proxmox ne permet pas
l&amp;rsquo;utilisation de jetons d&amp;rsquo;API, même pour l&amp;rsquo;utilisateur &lt;code&gt;root@pam&lt;/code&gt;, pour cette
opération. Cette approche abaisse donc significativement le niveau de sécurité
et n&amp;rsquo;est donc pas souhaitable.&lt;/p&gt;
&lt;p&gt;En outre, l&amp;rsquo;option permettant la définition d&amp;rsquo;une variable dans le micrologiciel
prend en argument le chemin vers le fichier de configuration Ignition. Ce chemin
est local à l&amp;rsquo;hyperviseur. Hélas, il n&amp;rsquo;est pas possible de téléverser sur un
serveur Proxmox un fichier arbitraire par l&amp;rsquo;API ou l&amp;rsquo;interface web, malgré
l&amp;rsquo;existence d&amp;rsquo;une fonctionnalité de &amp;ldquo;snippets&amp;rdquo;&lt;sup id=&#34;fnref:16&#34;&gt;&lt;a href=&#34;#fn:16&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;16&lt;/a&gt;&lt;/sup&gt;. Il est donc là
encore nécessaire de se connecter en SSH/SFTP pour téléverser le fichier de
configuration&amp;hellip;&lt;/p&gt;
&lt;h3 id=&#34;convertir-un-fichier-cloud-init&#34;&gt;Convertir un fichier cloud-init&lt;/h3&gt;
&lt;p&gt;Geco IT&lt;sup id=&#34;fnref:17&#34;&gt;&lt;a href=&#34;#fn:17&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;17&lt;/a&gt;&lt;/sup&gt; a créé un script qui permet de convertir certaines options de
cloud-init en fichier de configuration Ignition.&lt;/p&gt;
&lt;p&gt;Leur méthode de création de VM ne passe pas par l&amp;rsquo;API Proxmox mais utilise un
autre script shell qui lance des outils en ligne de commandes de la
distribution Proxmox. Ces commandes sont exécutées en tant que root, et parmi
celles-ci, la commande suivante :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;qm set &amp;lt;vmid&amp;gt; -hookscript &amp;lt;snippet_storage&amp;gt;:snippets/hook-fcos.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;L&amp;rsquo;attribut &lt;code&gt;-hookscript&lt;/code&gt; peut être défini par l&amp;rsquo;API de Proxmox, et par le
greffon &lt;code&gt;bpg/proxmox&lt;/code&gt; d&amp;rsquo;OpenTofu. Cependant, à l&amp;rsquo;instar de l&amp;rsquo;attribut &lt;code&gt;-args&lt;/code&gt;,
celui-ci n&amp;rsquo;est accepté que si le compte d&amp;rsquo;API utilisé est &lt;code&gt;root@pam&lt;/code&gt;,
c&amp;rsquo;est-à-dire le compte root du serveur Proxmox, avec une authentification par
mot de passe et sans second facteur d&amp;rsquo;authentification.&lt;/p&gt;
&lt;p&gt;En conséquence, cette méthode n&amp;rsquo;apporte aucune sécurité additionnelle par
rapport à la précédente discutée, tout en réduisant l&amp;rsquo;expressivité du fichier de
configuration Ignition.&lt;/p&gt;
&lt;h2 id=&#34;une-proposition-de-solution--une-machine-virtuelle-dinstallation&#34;&gt;Une proposition de solution : une machine virtuelle d&amp;rsquo;installation&lt;/h2&gt;
&lt;p&gt;Comme nous avons pu le voir dans les sections précédentes, l&amp;rsquo;usage de l&amp;rsquo;API
Proxmox pour les attributs &lt;code&gt;-args&lt;/code&gt; et &lt;code&gt;-hookscript&lt;/code&gt; est rédhibitoire puisque
nécessitant non seulement d&amp;rsquo;utiliser le mot de passe du compte root dans la
configuration OpenTofu, mais aussi de désactiver les seconds facteurs
d&amp;rsquo;authentification.&lt;/p&gt;
&lt;p&gt;La solution PXE est certainement la plus élégante, mais l&amp;rsquo;impossibilité de
configurer le serveur DHCP de Proxmox (sans passer par le shell) pour permettre
un tel démarrage nous en prive. Finalement, l&amp;rsquo;approche ISO personnalisé ne
passerait pas à l&amp;rsquo;échelle d&amp;rsquo;un parc complet.&lt;/p&gt;
&lt;p&gt;Nous disposons cependant ici de toutes les briques suffisantes pour construire
une solution satisfaisante !&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;idée est la suivante : personnaliser un ISO de Fedora CoreOS afin d&amp;rsquo;y ajouter
un fichier Ignition permettant d&amp;rsquo;installer un serveur DHCP (pour distribuer les
IPs mais aussi la configuration PXE), un serveur HTTP pour servir les fichiers
indiqués par PXE, et un serveur SFTP afin de déposer les fichiers de
configuration Ignition servis par HTTP.&lt;/p&gt;
&lt;p&gt;À l&amp;rsquo;origine, je souhaitais détailler ici la solution, mais son développement
s&amp;rsquo;est avéré suffisamment complexe (et surprenant) pour constituer un billet de
blog séparé. À suivre !&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.proxmox.com/en/&#34;&gt;https://www.proxmox.com/en/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://fedoraproject.org/coreos/&#34;&gt;https://fedoraproject.org/coreos/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://opentofu.org/&#34;&gt;https://opentofu.org/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://mastodon.social/@pid_eins/112393043769199622&#34;&gt;https://mastodon.social/@pid_eins/112393043769199622&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:5&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://coreos.github.io/ignition/&#34;&gt;https://coreos.github.io/ignition/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:5&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:6&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.learnsteps.com/what-are-snowflake-servers/&#34;&gt;https://www.learnsteps.com/what-are-snowflake-servers/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:6&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:7&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://cloud-init.io/&#34;&gt;https://cloud-init.io/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:7&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:8&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://openbao.org/&#34;&gt;https://openbao.org/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:8&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:9&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://developer.hashicorp.com/vault/docs/concepts/response-wrapping&#34;&gt;https://developer.hashicorp.com/vault/docs/concepts/response-wrapping&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:9&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:10&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://bitwarden.com/fr-fr/products/send/&#34;&gt;https://bitwarden.com/fr-fr/products/send/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:10&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:11&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://bitwarden.com/fr-fr/products/secrets-manager/&#34;&gt;https://bitwarden.com/fr-fr/products/secrets-manager/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:11&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:12&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://registry.terraform.io/providers/bpg/proxmox/latest&#34;&gt;https://registry.terraform.io/providers/bpg/proxmox/latest&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:12&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:13&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://cloudinit.readthedocs.io/en/latest/reference/datasources/nocloud.html&#34;&gt;https://cloudinit.readthedocs.io/en/latest/reference/datasources/nocloud.html&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:13&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:14&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://docs.fedoraproject.org/en-US/fedora-coreos/live-booting/#_booting_via_iso&#34;&gt;https://docs.fedoraproject.org/en-US/fedora-coreos/live-booting/#_booting_via_iso&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:14&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:15&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://btrfs.readthedocs.io/en/latest/Deduplication.html&#34;&gt;https://btrfs.readthedocs.io/en/latest/Deduplication.html&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:15&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:16&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://forum.proxmox.com/threads/creating-snippets-using-pve-api.54081/&#34;&gt;https://forum.proxmox.com/threads/creating-snippets-using-pve-api.54081/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:16&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:17&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://wiki.geco-it.net/public:pve_fcos&#34;&gt;https://wiki.geco-it.net/public:pve_fcos&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:17&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
		</item>
		<item>
			<title>Identité et méthodes d&#39;authentification</title>
			<link>https://broken-by-design.fr/posts/cours-id-authn/</link>
			<pubDate>Mon, 26 Feb 2024 00:00:00 +0200</pubDate>
			<guid isPermaLink="true">https://broken-by-design.fr/posts/cours-id-authn/</guid>
			<description>&lt;h1 id=&#34;définition-des-termes&#34;&gt;Définition des termes&lt;/h1&gt;
&lt;p&gt;Un &lt;strong&gt;acteur&lt;/strong&gt; ou &lt;strong&gt;sujet&lt;/strong&gt; (&lt;em&gt;subject&lt;/em&gt;) est un membre actif d&amp;rsquo;un système d&amp;rsquo;information exerçant une &lt;strong&gt;action&lt;/strong&gt; ou une &lt;strong&gt;activité&lt;/strong&gt; sur les membres de ce système. Les acteurs peuvent être des personnes ou des processus.&lt;/p&gt;
&lt;p&gt;Par opposition, un &lt;strong&gt;objet&lt;/strong&gt; est un membre inactif du système d&amp;rsquo;information sur lequel peut porter une activité exercée par un acteur.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;&lt;strong&gt;identité&lt;/strong&gt; est la manière dont un acteur d&amp;rsquo;un système d&amp;rsquo;information se fait connaitre auprès des autres acteurs de ce système. On rattache à l&amp;rsquo;identité de nombreuses &lt;strong&gt;propriétés&lt;/strong&gt; ou &lt;strong&gt;attributs&lt;/strong&gt;. Par exemple, on peut citer l&amp;rsquo;adresse email, le numéro de téléphone, son nom et son prénom, un identifiant d&amp;rsquo;utilisateur ou d&amp;rsquo;utilisatrice (&lt;em&gt;User Identifier (UID)&lt;/em&gt;), un identifiant de processus (&lt;em&gt;Process Identifier PID&lt;/em&gt;), l&amp;rsquo;appartenance à des groupes, l&amp;rsquo;attribution de rôles, mais il peut s&amp;rsquo;agir plus largement de valeurs arbitraires propres à cet acteur.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;&lt;strong&gt;authentification&lt;/strong&gt; est le procédé par lequel un acteur prouve son identité aux autres acteurs du système. Il existe de nombreuses façons de prouver son identité : mots de passe, clés cryptographiques, biométrie, etc. Dans les textes juridiques, les authentifiants sont parfois appelés &amp;ldquo;moyens d&amp;rsquo;identification électroniques&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;&lt;strong&gt;autorisation&lt;/strong&gt; encadre les activités que l&amp;rsquo;acteur peut entreprendre sur les objets du système d&amp;rsquo;information.&lt;/p&gt;
&lt;h1 id=&#34;identité&#34;&gt;Identité&lt;/h1&gt;
&lt;h2 id=&#34;portée&#34;&gt;Portée&lt;/h2&gt;
&lt;p&gt;La &lt;strong&gt;portée&lt;/strong&gt; d&amp;rsquo;une identité peut être vue comme son périmètre d&amp;rsquo;action, c&amp;rsquo;est-à-dire l&amp;rsquo;espace dans lequel cette identité a du sens (un peu comme une carte d&amp;rsquo;identité française n&amp;rsquo;a pas de valeur au Royaume-Uni). Nous allons en envisager plusieurs : locale, centrale, répartie et décentralisée.&lt;/p&gt;
&lt;h3 id=&#34;de-la-portée-locale&#34;&gt;De la portée locale&lt;/h3&gt;
&lt;p&gt;Une identité peut être &lt;strong&gt;locale&lt;/strong&gt; à un système d&amp;rsquo;information, ou même à un sous-ensemble d&amp;rsquo;un système d&amp;rsquo;information. C&amp;rsquo;est le cas des &lt;strong&gt;comptes locaux&lt;/strong&gt; gérés par nsswitch et le module PAM (Pluggable Authentication Modules)&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; &lt;code&gt;pam_unix&lt;/code&gt; sur une machine Linux. Les identités locales présentent l&amp;rsquo;avantage d&amp;rsquo;être autonomes et toujours disponibles, sans être tributaires de la disponibilité de système tiers. La contrepartie est une difficulté notable à maintenir la cohérence des identités sur les différents systèmes, chacun ayant la même &lt;em&gt;force de vérité&lt;/em&gt; dans leur périmètre.&lt;/p&gt;
&lt;pre class=&#34;mermaid&#34;&gt;---
title: Illustration des comptes locaux
---
flowchart LR
  laptop[&#34;Client&#34;]
  subgraph srv1 [&#34;Serveur 1&#34;]
    direction LR
    proc1[/&#34;Processus 1&#34;/]
    db1[(&#34;Base locale 1&#34;)]
  end
  subgraph srv2 [&#34;Serveur 2&#34;]
    direction LR
    proc2[/&#34;Processus 2&#34;/]
    db2[(&#34;Base locale 2&#34;)]
  end
  subgraph srv3 [&#34;Serveur 3&#34;]
    direction LR
    proc3[/&#34;Processus 3&#34;/]
    db3[(&#34;Base locale 3&#34;)]
  end

  laptop --&gt; srv1 &amp; srv2 &amp; srv3
  proc1 --&gt; db1
  proc2 --&gt; db2
  proc3 --&gt; db3
&lt;/pre&gt;

&lt;h3 id=&#34;des-référentiels-didentités-centraux&#34;&gt;Des référentiels d&amp;rsquo;identités centraux&lt;/h3&gt;
&lt;p&gt;La portée d&amp;rsquo;une identité peut être plus large et une identité peut être connue de plusieurs membres d&amp;rsquo;un système d&amp;rsquo;information ; on parle alors d&amp;rsquo;une identité &lt;strong&gt;centralisée&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Un &lt;strong&gt;référentiel d&amp;rsquo;identités central&lt;/strong&gt; contient les identités d&amp;rsquo;un ensemble d&amp;rsquo;acteurs.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;intérêt d&amp;rsquo;un tel référentiel devient évident à mesure qu&amp;rsquo;un système d&amp;rsquo;information s&amp;rsquo;agrandit ; gérer manuellement des identités locales sur de nombreux systèmes peut mener à des incohérences, et des oublis. En rassemblant les informations dans un référentiel central, il n&amp;rsquo;y alors qu&amp;rsquo;une seule &lt;strong&gt;source de vérité&lt;/strong&gt;, faisant autorité pour l&amp;rsquo;ensemble du système d&amp;rsquo;information concerné. Il convient également de noter qu&amp;rsquo;il peut exister des &lt;strong&gt;copies&lt;/strong&gt; de ces informations conservées en local sur les différents systèmes assujettis à ce référentiel d&amp;rsquo;identité. Ces copies ne font pas autorité, et il convient de surveiller leur cohérence avec la source de vérité et de les invalider ou les mettre à jour, le cas échéant.&lt;/p&gt;
&lt;p&gt;Les copies sont souvent nécessaires à des fins &lt;strong&gt;de performance et de résilience&lt;/strong&gt;. En effet, centraliser les identités présente des défis techniques notamment en matière de disponibilité ; une &lt;strong&gt;panne du référentiel central&lt;/strong&gt; peut être de nature à stopper net l&amp;rsquo;ensemble des activités d&amp;rsquo;un système d&amp;rsquo;information.&lt;/p&gt;
&lt;p&gt;Parmi les protocoles fréquemment utilisés pour la centralisation des identités, il est possible de citer LDAP&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;pre class=&#34;mermaid&#34;&gt;---
title: Illustration d&#39;un annuaire centralisé
---
flowchart LR
  laptop[&#34;Client&#34;]
  subgraph srv1 [&#34;Serveur 1&#34;]
    direction TB
    proc1[/&#34;Processus 1&#34;/]
    dbs1[(&#34;Copie locale&#34;)]
  end
  subgraph srv2 [&#34;Serveur 2&#34;]
    direction TB
    proc2[/&#34;Processus 2&#34;/]
    dbs2[(&#34;Copie locale&#34;)]
  end
  subgraph srv3 [&#34;Serveur 3&#34;]
    direction TB
    proc3[/&#34;Processus 3&#34;/]
    dbs3[(&#34;Copie locale&#34;)]
  end

  subgraph ref [&#34;Référentiel d&#39;identité&#34;]
    ldapsrv[/&#34;Serveur LDAP&#34;/]
    db[(&#34;Base d&#39;identités&#34;)]
  end

  laptop --&gt; srv1 &amp; srv2 &amp; srv3
  srv1 &amp; srv2 &amp; srv3 --&#34;LDAP&#34;--&gt; ref
  proc1 --&gt; dbs1
  proc2--&gt; dbs2
  proc3 --&gt; dbs3
  ldapsrv --&gt; db
&lt;/pre&gt;

&lt;h3 id=&#34;des-référentiels-didentités-répartis&#34;&gt;Des référentiels d&amp;rsquo;identités répartis&lt;/h3&gt;
&lt;p&gt;Un référentiel d&amp;rsquo;identités peut être amené à voir sa taille grandir, que ce soit de manière organique ou lors d&amp;rsquo;acquisitions de sociétés. Dans ce dernier cas, en particulier, il existe alors plusieurs référentiels d&amp;rsquo;identités concurrents, qu&amp;rsquo;il pourrait être intéressant de fusionner. Cette opération est sensible, et difficile.&lt;/p&gt;
&lt;p&gt;Il existe des alternatives à la fusion ; l&amp;rsquo;établissement d&amp;rsquo;une &lt;strong&gt;forêt&lt;/strong&gt;&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; ou la mise en place d&amp;rsquo;un &lt;strong&gt;annuaire virtuel&lt;/strong&gt; (&lt;em&gt;Virtual Directory Service&lt;/em&gt; (VDS))&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Une forêt est constituée d&amp;rsquo;un ensemble de référentiels d&amp;rsquo;identités indépendants entre lesquels il existe une &lt;strong&gt;relation de confiance&lt;/strong&gt;. Ainsi, par &lt;strong&gt;transitivité&lt;/strong&gt; de la confiance, les membres d&amp;rsquo;un référentiel d&amp;rsquo;identité accordent leur confiance aux identités gérées par un autre référentiel d&amp;rsquo;identité. Ce genre de schéma est très répandu dans les infrastructures &lt;strong&gt;Active Directory&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Les services d&amp;rsquo;annuaires virtuels jouent le rôle de &lt;strong&gt;serveurs mandataires&lt;/strong&gt; pour l&amp;rsquo;accès à plusieurs référentiels d&amp;rsquo;identité. Ces derniers apparaissent alors comme &amp;ldquo;fusionnés&amp;rdquo; aux yeux des utilisateurs de service, alors qu&amp;rsquo;ils continuent d&amp;rsquo;être gérés individuellement.&lt;/p&gt;
&lt;pre class=&#34;mermaid&#34;&gt;---
title: Illustration d&#39;annuaires répartis (forest)
---
flowchart LR
  laptop[&#34;Client&#34;]
  subgraph srv1 [&#34;Serveur 1&#34;]
    direction TB
    proc1[/&#34;Processus 1&#34;/]
    dbs1[(&#34;Copie locale&#34;)]
  end
  subgraph srv2 [&#34;Serveur 2&#34;]
    direction TB
    proc2[/&#34;Processus 2&#34;/]
    dbs2[(&#34;Copie locale&#34;)]
  end

  subgraph refnet [&#34;Référentiel d&#39;identité #quot;example.net#quot;&#34;]
    direction TB
    ldapsrv[/&#34;Serveur LDAP&#34;/]
    db[(&#34;Base d&#39;identités&#34;)]
  end

  subgraph refcom [&#34;Référentiel d&#39;identité #quot;example.com#quot;&#34;]
    direction TB
    ldapsrv2[/&#34;Serveur LDAP&#34;/]
    db2[(&#34;Base d&#39;identités&#34;)]
  end

  laptop --&gt; srv1 &amp; srv2
  srv1 &amp; srv2 --&#34;LDAP&#34;--&gt; refcom
  proc1 --&gt; dbs1
  proc2 --&gt; dbs2
  ldapsrv --&gt; db
  srv1 &amp; srv2 --&#34;LDAP&#34;--&gt; refnet
  ldapsrv2 --&gt; db2
&lt;/pre&gt;

&lt;pre class=&#34;mermaid&#34;&gt;---
title: Illustration d&#39;annuaires répartis (VDS)
---
flowchart LR
  laptop[&#34;Client&#34;]
  subgraph srv1 [&#34;Serveur 1&#34;]
    proc1[/&#34;Processus 1&#34;/]
    dbs1[(&#34;Copie locale&#34;)]
  end
  subgraph srv2 [&#34;Serveur 2&#34;]
    proc2[/&#34;Processus 2&#34;/]
    dbs2[(&#34;Copie locale&#34;)]
  end
  subgraph srv3 [&#34;Serveur 3&#34;]
    proc3[/&#34;Processus 3&#34;/]
    dbs3[(&#34;Copie locale&#34;)]
  end

  subgraph vds [&#34;Virtual Directory Service&#34;]
    direction TB
    vdss[/&#34;Serveur VDS&#34;/]
    dbss[(&#34;Copie locale&#34;)]
  end

  subgraph refnet [&#34;Référentiel d&#39;identité #quot;example.net#quot;&#34;]
    ldapsrv[/&#34;Serveur LDAP&#34;/]
    db[(&#34;Base d&#39;identités&#34;)]
  end

  subgraph refcom [&#34;Référentiel d&#39;identité #quot;example.com#quot;&#34;]
    ldapsrv2[/&#34;Serveur LDAP&#34;/]
    db2[(&#34;Base d&#39;identités&#34;)]
  end

  laptop --&gt; srv1 &amp; srv2 &amp; srv3
  proc1 --&gt; dbs1
  proc2 --&gt; dbs2
  proc3 --&gt; dbs3
  srv1 &amp; srv2 &amp; srv3 --&#34;LDAP&#34;--&gt; vds
  vds --&#34;LDAP&#34;--&gt; refcom &amp; refnet
  vdss --&gt; dbss
  ldapsrv --&gt; db
  ldapsrv2 --&gt; db2
&lt;/pre&gt;

&lt;h3 id=&#34;des-référentiels-didentités-décentralisés&#34;&gt;Des référentiels d&amp;rsquo;identités décentralisés&lt;/h3&gt;
&lt;p&gt;Les référentiels d&amp;rsquo;identités répartis ont du sens lorsque l&amp;rsquo;ensemble des référentiels d&amp;rsquo;identités sont sous le contrôle d&amp;rsquo;entités juridiques ayant un rapport de confiance ou ayant la volonté d&amp;rsquo;apparaitre sous une même bannière. La confiance et l&amp;rsquo;unification s&amp;rsquo;effectuent par les gestionnaires des référentiels d&amp;rsquo;identités ; &lt;em&gt;le consommateur de ces référentiels n&amp;rsquo;a aucun pouvoir de décision&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Il existe cependant une alternative dans le cas où ce genre de centralisation ou de répartition n&amp;rsquo;est pas possible ou souhaitable : l&amp;rsquo;utilisation de &lt;strong&gt;référentiels d&amp;rsquo;identités décentralisés&lt;/strong&gt;. On parle alors d&amp;rsquo;&lt;strong&gt;identités fédérées&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Avec des référentiels d&amp;rsquo;identités décentralisés, chaque référentiel est géré par ses gestionnaires selon des politiques qui leur sont propres. C&amp;rsquo;est, en revanche, les responsables des systèmes d&amp;rsquo;information ayant besoin de connaitre l&amp;rsquo;identité de leurs utilisateurs et utilisatrices qui choisissent à quels fournisseurs de référentiels d&amp;rsquo;identités décentralisés ils font confiance ! Si l&amp;rsquo;identité d&amp;rsquo;un utilisateur ou d&amp;rsquo;une utilisatrice n&amp;rsquo;est pas gérée par un fournisseur de référentiels d&amp;rsquo;identité accrédité par les responsables d&amp;rsquo;un système d&amp;rsquo;information, il ou elle ne pourra pas se faire connaitre de ce système d&amp;rsquo;information.&lt;/p&gt;
&lt;p&gt;Concernant la disponibilité, la plupart des services consommant des identités fédérées maintiennent en local une base de données avec des attributs supplémentaires spécifiques à leurs besoins métier. En revanche, si un fournisseur de référentiel d&amp;rsquo;identités est indisponible, les utilisateurs et les utilisatrices de ce fournisseur ne pourront plus se connecter à aucun service.&lt;/p&gt;
&lt;p&gt;Les référentiels d&amp;rsquo;identités décentralisés sont devenus très populaires sur Internet, et de nombreux sites proposent ainsi de s&amp;rsquo;enregistrer ou de s&amp;rsquo;identifier à l&amp;rsquo;aide d&amp;rsquo;une identité fédérée. Ironiquement, cependant, peu de référentiels d&amp;rsquo;identités sont accrédités par les sites web, et les identités décentralisées reconnues se limitent souvent à celles gérées par quelques acteurs clés : Google, Facebook, Twitter, ou spécifiquement en France, France Connect.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;interrogation de ces référentiels se fait à l&amp;rsquo;aide de protocoles plus ou moins standards. Parmi les plus répandus, on peut notamment citer OpenID Connect&lt;sup id=&#34;fnref:5&#34;&gt;&lt;a href=&#34;#fn:5&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt; et SAML&lt;sup id=&#34;fnref:6&#34;&gt;&lt;a href=&#34;#fn:6&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;6&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;pre class=&#34;mermaid&#34;&gt;---
title: Illustration d&#39;annuaires décentralisés
---
flowchart LR
  laptop[&#34;Client&#34;]
  subgraph srv [Serveur]
    direction TB
    proc[/&#34;Processus&#34;/]
    dbs[(&#34;Base locale&#34;)]
  end

  subgraph refnet [&#34;Référentiel d&#39;identité #quot;example.net#quot;&#34;]
    direction TB
    oidcsrv1[/&#34;Serveur OpenID Connect&#34;/]
    db1[(&#34;Base d&#39;identités&#34;)]
  end

  subgraph refcom [&#34;Référentiel d&#39;identité #quot;example.com#quot;&#34;]
    direction TB
    samlsrv1[/&#34;Serveur SAML&#34;/]
    db2[(&#34;Base d&#39;identités&#34;)]
  end

  subgraph reforg [&#34;Référentiel d&#39;identité #quot;example.org#quot;&#34;]
    direction TB
    oidcsrv2[/&#34;Serveur OpenID Connect&#34;/]
    db3[(&#34;Base d&#39;identités&#34;)]
  end


  laptop --&#34;Protocole OIDC/SAML&#34;--&gt; srv
  srv --&#34;Accrédite&#34;--&gt; refnet
  srv --&#34;Accrédite&#34;--&gt; refcom
  srv --&#34;`N&#39;accrédite *PAS*`&#34;--&gt; reforg;
  proc --&gt; dbs
  laptop &lt;-.&#34;Protocole OIDC&#34;.-&gt; refnet
  laptop &lt;-.&#34;Protocole SAML&#34;.-&gt; refcom
  oidcsrv1 --&gt; db1
  samlsrv1 --&gt; db2
  oidcsrv2 --&gt; db3
  linkStyle 1,2 color:red;
&lt;/pre&gt;

&lt;h2 id=&#34;sur-la-séparation-des-référentiels-didentité&#34;&gt;Sur la séparation des référentiels d&amp;rsquo;identité&lt;/h2&gt;
&lt;p&gt;Le référentiel SecNumCloud&lt;sup id=&#34;fnref:7&#34;&gt;&lt;a href=&#34;#fn:7&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;7&lt;/a&gt;&lt;/sup&gt;&lt;sup id=&#34;fnref:8&#34;&gt;&lt;a href=&#34;#fn:8&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;8&lt;/a&gt;&lt;/sup&gt; prévoit que les comptes d&amp;rsquo;administration d&amp;rsquo;un prestataire de cloud qualifié soient gérés &amp;ldquo;à l&amp;rsquo;aide d&amp;rsquo;outils et d&amp;rsquo;annuaires distincts de ceux utilisés pour la gestion des comptes utilisateurs placés sous la responsabilité du commanditaire (c&amp;rsquo;est-à-dire de ses clients)&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Exigée pour les prestataires de cloud qualifiés, cette séparation des référentiels d&amp;rsquo;identités afin d&amp;rsquo;en dédier un pour les comptes d&amp;rsquo;administration du système d&amp;rsquo;information semble une bonne pratique de sécurité à adopter en général. Elle permet, en effet, de limiter la surface d&amp;rsquo;attaque des services manipulant notamment les clés cryptographiques utilisées pour l’administration (clés TLS, clés de signature des “jetons d’accès”, etc.).&lt;/p&gt;
&lt;h1 id=&#34;authentification&#34;&gt;Authentification&lt;/h1&gt;
&lt;p&gt;L’authentification est un sujet complexe, que ce cours va aborder sous de nombreux angles :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;les aspects &lt;strong&gt;juridiques&lt;/strong&gt; et &lt;strong&gt;normatifs&lt;/strong&gt; ;&lt;/li&gt;
&lt;li&gt;les &lt;strong&gt;facteurs&lt;/strong&gt; d&amp;rsquo;authentification ;&lt;/li&gt;
&lt;li&gt;la &lt;strong&gt;force&lt;/strong&gt; de l&amp;rsquo;authentification ;&lt;/li&gt;
&lt;li&gt;les &lt;strong&gt;mécanismes de preuve&lt;/strong&gt; mis en œuvre ;&lt;/li&gt;
&lt;li&gt;les &lt;strong&gt;risques de la réutilisation&lt;/strong&gt; de moyens de preuve d&amp;rsquo;identité ;&lt;/li&gt;
&lt;li&gt;le &lt;strong&gt;stockage&lt;/strong&gt; des éléments authentifiants.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;aspects-juridiques-de-lauthentification&#34;&gt;Aspects juridiques de l&amp;rsquo;authentification&lt;/h2&gt;
&lt;p&gt;L&amp;rsquo;authentification est un sujet traité à la fois par les juridictions nationales et internationales. Un défaut de conformité à ces dispositions peut entrainer des sanctions parfois sévères.&lt;/p&gt;
&lt;p&gt;La Commission Nationale Information et Libertés (CNIL) a à plusieurs reprises sanctionné des sociétés mettant en place des &lt;strong&gt;mécanismes d&amp;rsquo;authentification&lt;/strong&gt; trop faibles&lt;sup id=&#34;fnref:9&#34;&gt;&lt;a href=&#34;#fn:9&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;9&lt;/a&gt;&lt;/sup&gt;, des &lt;strong&gt;politiques de sécurité&lt;/strong&gt; entourant les moyens d&amp;rsquo;authentifications insuffisantes&lt;sup id=&#34;fnref:10&#34;&gt;&lt;a href=&#34;#fn:10&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;10&lt;/a&gt;&lt;/sup&gt;, ou des &lt;strong&gt;mécanismes de stockage&lt;/strong&gt; des éléments authentifiants trop faibles, mal déployés ou mal composés&lt;sup id=&#34;fnref:11&#34;&gt;&lt;a href=&#34;#fn:11&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;11&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Parmi les textes juridiques encadrant l&amp;rsquo;authentification, on peut notamment évoquer le &lt;strong&gt;règlement européen &amp;ldquo;Electronic Identification, Authentication and Trust Services&amp;rdquo; (eiDAS)&lt;sup id=&#34;fnref:12&#34;&gt;&lt;a href=&#34;#fn:12&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;12&lt;/a&gt;&lt;/sup&gt;&lt;/strong&gt; et la &lt;strong&gt;&amp;ldquo;directive révisée sur les services de paiement&amp;rdquo; (DSP2)&lt;/strong&gt;&lt;sup id=&#34;fnref:13&#34;&gt;&lt;a href=&#34;#fn:13&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;13&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;En France, la directive DSP2 a été transposée notamment dans les articles L133-4&lt;sup id=&#34;fnref:14&#34;&gt;&lt;a href=&#34;#fn:14&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;14&lt;/a&gt;&lt;/sup&gt; et L133-44&lt;sup id=&#34;fnref:15&#34;&gt;&lt;a href=&#34;#fn:15&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;15&lt;/a&gt;&lt;/sup&gt; du &lt;strong&gt;code monétaire et financier&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Pour le règlement eiDAS, des spécifications techniques viennent compléter les textes juridiques, notamment à des fins d&amp;rsquo;&lt;strong&gt;interopérabilité&lt;/strong&gt;&lt;sup id=&#34;fnref:16&#34;&gt;&lt;a href=&#34;#fn:16&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;16&lt;/a&gt;&lt;/sup&gt;. Des précisions techniques sont également apportées sur les contraintes pour satisfaire les différents &lt;strong&gt;niveaux de garantie&lt;/strong&gt; définis par le règlement&lt;sup id=&#34;fnref:17&#34;&gt;&lt;a href=&#34;#fn:17&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;17&lt;/a&gt;&lt;/sup&gt;. Une ordonnance&lt;sup id=&#34;fnref:18&#34;&gt;&lt;a href=&#34;#fn:18&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;18&lt;/a&gt;&lt;/sup&gt; donne le pouvoir à l&amp;rsquo;Agence Nationale de la Sécurité des Systèmes d&amp;rsquo;Information (ANSSI)&lt;sup id=&#34;fnref:19&#34;&gt;&lt;a href=&#34;#fn:19&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;19&lt;/a&gt;&lt;/sup&gt; de certifier des moyens d&amp;rsquo;authentification permettant de satisfaire ces niveaux de garantie. De plus amples informations sur le règlement eiDAS peuvent être trouvées sur le site de l&amp;rsquo;ANSSI&lt;sup id=&#34;fnref:20&#34;&gt;&lt;a href=&#34;#fn:20&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;20&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Nous reviendrons sur le contenu de ces textes au fur et à mesure que le cours abordera les notions qui y sont renseignées.&lt;/p&gt;
&lt;p&gt;Outre les textes à valeurs juridiques, en France, l&amp;rsquo;ANSSI a publié divers référentiels et guides :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;le &lt;strong&gt;Référentiel Général de Sécurité (RGS)&lt;/strong&gt; 2.0, et en particulier son annexe B1 sur les mécanismes cryptographiques et son annexe B3 sur les mécanismes d&amp;rsquo;authentification&lt;sup id=&#34;fnref:21&#34;&gt;&lt;a href=&#34;#fn:21&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;21&lt;/a&gt;&lt;/sup&gt; ;&lt;/li&gt;
&lt;li&gt;le guide &lt;strong&gt;&amp;ldquo;Recommandations relatives à l&amp;rsquo;authentification multifacteur et aux mots de passe&amp;rdquo;&lt;/strong&gt;&lt;sup id=&#34;fnref:22&#34;&gt;&lt;a href=&#34;#fn:22&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;22&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Le respect des règles et &amp;ldquo;recommandations&amp;rdquo; listées dans ces documents est requis pour l&amp;rsquo;obtention d&amp;rsquo;un certain nombre de qualifications de l&amp;rsquo;ANSSI, notamment SecNumCloud&lt;sup id=&#34;fnref1:7&#34;&gt;&lt;a href=&#34;#fn:7&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;7&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h2 id=&#34;les-facteurs-dauthentification&#34;&gt;Les facteurs d&amp;rsquo;authentification&lt;/h2&gt;
&lt;p&gt;Le règlement d&amp;rsquo;exécution (UE) 2015/1502&lt;sup id=&#34;fnref1:17&#34;&gt;&lt;a href=&#34;#fn:17&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;17&lt;/a&gt;&lt;/sup&gt; définit trois types de facteurs d&amp;rsquo;authentification.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;a) &amp;ldquo;&lt;strong&gt;facteur d&amp;rsquo;authentification basé sur la possession&lt;/strong&gt;&amp;rdquo;, un facteur d&amp;rsquo;authentification dont il revient au sujet de démontrer la possession;&lt;/p&gt;
&lt;p&gt;b) &amp;ldquo;&lt;strong&gt;facteur d&amp;rsquo;authentification basé sur la connaissance&lt;/strong&gt;&amp;rdquo;, un facteur d&amp;rsquo;authentification dont il revient au sujet de démontrer la connaissance;&lt;/p&gt;
&lt;p&gt;c) &amp;ldquo;&lt;strong&gt;facteur d&amp;rsquo;authentification inhérent&lt;/strong&gt;&amp;rdquo;, un facteur d&amp;rsquo;authentification qui est basé sur un attribut physique d&amp;rsquo;une personne physique, et dont il revient au sujet de démontrer qu&amp;rsquo;il possède cet attribut physique.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Cette définition est également présente dans le code monétaire et financier, ainsi que dans le RGS (à une subtilité prête ; voir le chapitre concernant la force de l&amp;rsquo;authentification).&lt;/p&gt;
&lt;h3 id=&#34;les-facteurs-dauthentification-basés-sur-la-possession&#34;&gt;Les facteurs d&amp;rsquo;authentification basés sur la possession&lt;/h3&gt;
&lt;p&gt;D&amp;rsquo;après le guide de l&amp;rsquo;ANSSI &amp;ldquo;Recommandations relatives à l&amp;rsquo;authentification multifacteur et aux mots de passe&amp;rdquo; :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Un facteur de possession est un moyen de stocker des secrets non mémorisables par un humain (et n’ayant pas vocation à être mémorisés par un humain). Il s’agit typiquement des clés cryptographiques qui permettent de réaliser des opérations de chiffrement, de signature ou d’authentification.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Le même guide spécifie également :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Un facteur de possession doit être un équipement attribué à un unique utilisateur. Afin de garantir la sécurité apportée par ce facteur, il est essentiel que des moyens de protection et de détection contre les tentatives de reproduction ou de falsification du facteur soient mis en place. Un facteur de possession peut être une carte à puce contenant une clé privée, une carte SIM d’un téléphone mobile comportant des données d’identification, ou un dispositif permettant de générer des codes à usage unique (OTP).&lt;/p&gt;&lt;/blockquote&gt;
&lt;h3 id=&#34;les-facteurs-dauthentification-basés-sur-la-connaissance&#34;&gt;Les facteurs d&amp;rsquo;authentification basés sur la connaissance&lt;/h3&gt;
&lt;p&gt;Les facteurs d&amp;rsquo;authentification basés sur la connaissance reposent sur le fait que l&amp;rsquo;acteur connaisse un secret. En général, il s&amp;rsquo;agit d&amp;rsquo;un &lt;strong&gt;mot de passe&lt;/strong&gt;, d&amp;rsquo;une &lt;strong&gt;phrase de passe&lt;/strong&gt;, ou d&amp;rsquo;un &lt;strong&gt;code PIN (&lt;em&gt;Personal Identification Number&lt;/em&gt;)&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Les &lt;strong&gt;jetons d&amp;rsquo;authentification&lt;/strong&gt; (&lt;em&gt;authentication token&lt;/em&gt; ou &lt;em&gt;bearer token&lt;/em&gt;) sont un cas intéressant lorsqu&amp;rsquo;on parle d&amp;rsquo;authentification multifacteurs. En effet, ces derniers sont soit des valeurs aléatoires assimilables à des clés cryptographiques symétriques, soit des informations structurées et signées et encodées sous la forme d&amp;rsquo;une chaine de caractères (par exemple en base64). La simple preuve de la connaissance d&amp;rsquo;un tel jeton est suffisante pour prouver son identité ; cela laisserait donc entendre qu&amp;rsquo;il s&amp;rsquo;agisse d&amp;rsquo;un facteur d&amp;rsquo;authentification basé sur la connaissance. Pourtant, il s&amp;rsquo;agit d&amp;rsquo;un secret non mémorisable par un humain, ce qui entrerait aussi dans certaines des définitions d&amp;rsquo;un facteur d&amp;rsquo;authentification basé sur la possession.&lt;/p&gt;
&lt;h3 id=&#34;les-facteurs-dauthentification-inhérents&#34;&gt;Les facteurs d&amp;rsquo;authentification inhérents&lt;/h3&gt;
&lt;p&gt;L&amp;rsquo;authentification par des facteurs inhérents est une question épineuse en France. En effet, l&amp;rsquo;ANSSI a longtemps été une pourfendeuse de la biométrie, indiquant que les facteurs inhérents sont au mieux un facteur d&amp;rsquo;identification et non d&amp;rsquo;authentification, ou dans le pire des cas une méthode de déverrouillage pour un autre facteur d&amp;rsquo;authentification. Cette position a dû être partiellement révisée par la contrainte européenne, au travers du règlement eiDAS et la directive DSP2.&lt;/p&gt;
&lt;p&gt;Cette méfiance vis-à-vis de la biométrie n&amp;rsquo;est pourtant pas sans justification.&lt;/p&gt;
&lt;p&gt;La vérification des facteurs inhérents s&amp;rsquo;effectue de manière &lt;strong&gt;probabiliste&lt;/strong&gt; ; contrairement à la vérification des mots de passe ou des signatures cryptographiques, l&amp;rsquo;acquisition des données nécessaires à ce type de vérification n&amp;rsquo;est pas &amp;ldquo;parfaite&amp;rdquo;, et les algorithmes sont paramétrés avec des taux de faux positifs (validation d&amp;rsquo;une personne non autorisée) et de faux négatifs (refus d&amp;rsquo;une personne autorisée). Suivant le paramétrage, l&amp;rsquo;utilisateur fait alors face soit à un risque en confidentialité et en intégrité, soit à un risque en disponibilité. Ces paramétrages doivent d&amp;rsquo;ailleurs tenir compte qu&amp;rsquo;au cours du temps, certaines caractéristiques physiques changent ou s&amp;rsquo;estompent.&lt;/p&gt;
&lt;p&gt;Ensuite, les facteurs inhérents ne sont &lt;strong&gt;pas renouvelables&lt;/strong&gt; à l&amp;rsquo;infini ; si la révocation d&amp;rsquo;un moyen est possible, son remplacement ne l&amp;rsquo;est pas forcément.&lt;/p&gt;
&lt;p&gt;Également, le risque de &lt;strong&gt;réutilisation&lt;/strong&gt; d&amp;rsquo;une même caractéristique physique pour l&amp;rsquo;authentification auprès de plusieurs systèmes d&amp;rsquo;information peut comporter des risques de compromission croisée : un système d&amp;rsquo;information compromis pourrait permettre d&amp;rsquo;en compromettre un autre, à la manière d&amp;rsquo;une attaque dite de &amp;ldquo;&lt;em&gt;credential stuffing&lt;/em&gt;&amp;rdquo;&lt;sup id=&#34;fnref:23&#34;&gt;&lt;a href=&#34;#fn:23&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;23&lt;/a&gt;&lt;/sup&gt;. Cette attaque ne se limite cependant pas aux exfiltrations de données biométriques depuis des bases de données compromises ; par le passé, des chercheurs en sécurité ont réussi à extraire des données biométriques à partir de simples photos&lt;sup id=&#34;fnref:24&#34;&gt;&lt;a href=&#34;#fn:24&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;24&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h3 id=&#34;remarques-concernant-lauthentification-des-processus&#34;&gt;Remarques concernant l&amp;rsquo;authentification des processus&lt;/h3&gt;
&lt;p&gt;La notion de facteurs d&amp;rsquo;authentification n&amp;rsquo;a réellement de sens que pour les utilisateurs. Par définition, un processus ne peut posséder un équipement ou mettre en œuvre un attribut physique.&lt;/p&gt;
&lt;p&gt;Pourtant, l&amp;rsquo;exigence 9.6, alinéa f du référentiel SecNumCloud dispose que :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Le prestataire doit mettre en place un système d’authentification multifacteur fort pour l’accès :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;aux interfaces d’administration utilisées par le prestataire ;&lt;/li&gt;
&lt;li&gt;aux interfaces d’administration dédiées aux commanditaires.&lt;/li&gt;
&lt;/ul&gt;&lt;/blockquote&gt;
&lt;p&gt;Avec une lecture littérale, il semblerait donc &lt;em&gt;impossible&lt;/em&gt; d&amp;rsquo;authentifier des processus autonomes (par exemple, les tâches planifiées ou les traitements de chaines d&amp;rsquo;intégration ou de déploiement continu (&lt;em&gt;CI/CD&lt;/em&gt;)) pour l&amp;rsquo;administration d&amp;rsquo;un cloud qualifié SecNumCloud. Fort heureusement, les auditeurs SecNumCloud ne suivent pas à la lettre cette exigence mal écrite, et les prestataires de Cloud qualifiés proposent pour la plupart des interfaces d&amp;rsquo;administration programmables (&lt;em&gt;API&lt;/em&gt;) sans avoir recours à une authentification multifacteur.&lt;/p&gt;
&lt;p&gt;Il convient cependant de noter que strictement parlant, il pourrait être considéré qu&amp;rsquo;un processus puisse mettre en œuvre un facteur d&amp;rsquo;authentification basé sur la possession à l&amp;rsquo;aide d&amp;rsquo;équipements de sécurité particuliers : les &lt;strong&gt;&lt;em&gt;Trusted Platform Module&lt;/em&gt; (TPM)&lt;/strong&gt;&lt;sup id=&#34;fnref:25&#34;&gt;&lt;a href=&#34;#fn:25&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;25&lt;/a&gt;&lt;/sup&gt;, les &lt;strong&gt;&lt;em&gt;Hardware Security Module&lt;/em&gt; (HSM)&lt;/strong&gt;&lt;sup id=&#34;fnref:26&#34;&gt;&lt;a href=&#34;#fn:26&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;26&lt;/a&gt;&lt;/sup&gt;, et les &lt;strong&gt;&lt;em&gt;Key Management Services&lt;/em&gt; (KMS)&lt;/strong&gt;&lt;sup id=&#34;fnref:27&#34;&gt;&lt;a href=&#34;#fn:27&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;27&lt;/a&gt;&lt;/sup&gt;. Ces équipements permettent la manipulation ou l&amp;rsquo;exercice de secrets sans en permettre l&amp;rsquo;extraction, la copie ou la falsification.&lt;/p&gt;
&lt;h2 id=&#34;la-force-de-lauthentification&#34;&gt;La force de l&amp;rsquo;authentification&lt;/h2&gt;
&lt;p&gt;Le règlement eiDAS définit trois niveaux de garantie : &lt;strong&gt;faible&lt;/strong&gt;, &lt;strong&gt;substantiel&lt;/strong&gt; et &lt;strong&gt;élevé&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;À chacun de ces niveaux de garantie sont associées des contraintes particulières. Parmi ces dernières, on peut notamment citer le nombre de facteurs d&amp;rsquo;authentification requis. Ainsi, le niveau faible ne requiert l&amp;rsquo;usage que d&amp;rsquo;un seul facteur, tandis que le niveau substantiel requiert au moins deux facteurs de nature différente.&lt;/p&gt;
&lt;p&gt;La directive européenne DSP2 transposée dans le code monétaire et financier définit l&amp;rsquo;authentification forte comme étant :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[&amp;hellip;] une authentification reposant sur l&amp;rsquo;utilisation de deux éléments ou plus appartenant aux catégories &amp;ldquo;connaissance&amp;rdquo; (quelque chose que seul l&amp;rsquo;utilisateur connait), &amp;ldquo;possession&amp;rdquo; (quelque chose que seul l&amp;rsquo;utilisateur possède) et &amp;ldquo;inhérence&amp;rdquo; (quelque chose que l&amp;rsquo;utilisateur est) et indépendants en ce sens que la compromission de l&amp;rsquo;un ne remet pas en question la fiabilité des autres, et qui est conçue de manière à protéger la confidentialité des données d&amp;rsquo;authentification ;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Cette définition de l&amp;rsquo;article L133-44 du code monétaire et financier vient en contradiction avec la définition de l&amp;rsquo;authentification forte que l&amp;rsquo;ANSSI emploie parfois. En effet, la définition de l&amp;rsquo;authentification forte dans le RGS est (presque) conforme à la définition du droit français:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Cette recommandation est en cohérence avec la notion traditionnelle « d’authentification forte », qui préconise de combiner deux mécanismes parmi ce que l’on sait, ce que l’on a, ce que l’on est ou ce que l’on sait faire.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;On notera au passage que le RGS évoque &amp;ldquo;ce que l&amp;rsquo;on sait faire&amp;rdquo; qui est un facteur qui n&amp;rsquo;est ni reconnu par le règlement eiDAS, ni le code monétaire et financier.&lt;/p&gt;
&lt;p&gt;En revanche, dans son guide &amp;ldquo;Recommandations relatives à l&amp;rsquo;authentification multifacteur et aux mots de passe&amp;rdquo; en version 2.0, le chapitre 2.5 distingue &amp;ldquo;authentification forte&amp;rdquo; et &amp;ldquo;authentification multifacteur&amp;rdquo;, en précisant :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;En langue française, l’authentification multifacteur est souvent confondue avec l’appellation authentification forte (ou robuste), ce qui laisserait entendre qu’une authentification multifacteur est nécessairement plus robuste qu’une authentification avec un unique facteur.&lt;/p&gt;
&lt;p&gt;[&amp;hellip;]&lt;/p&gt;
&lt;p&gt;Afin d’être considérée comme forte, une authentification doit reposer sur un protocole cryptographique permettant de résister à certaines attaques comme :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;l’écoute clandestine (eavesdroppping en anglais), qui consiste pour un attaquant à passivement écouter le canal de communication entre le prouveur et le vérifieur ;&lt;/li&gt;
&lt;li&gt;les attaques par rejeu, qui consistent pour un attaquant à récupérer des informations d’authentification (comme un mot de passe ou son empreinte) et à utiliser ces informations pour les rejouer afin d’usurper l’identité de la cible (l’attaque pass-the-hash [21] en est un exemple) ;&lt;/li&gt;
&lt;li&gt;les attaques de l’homme-du-milieu, qui consistent pour un attaquant à intercepter et modifier les communications se déroulant entre le prouveur et le vérifieur lors de l’authentification sans être détecté ;&lt;/li&gt;
&lt;li&gt;la non-forgeabilité : l’observation par un attaquant de plusieurs échanges d’authentification d’un prouveur ne doit pas lui permettre d’usurper son identité dans un nouvel échange d’authentification.&lt;/li&gt;
&lt;/ul&gt;&lt;/blockquote&gt;
&lt;p&gt;En outre, l&amp;rsquo;expression &amp;ldquo;authentification forte&amp;rdquo; est de plus en plus galvaudée par le marketing.&lt;/p&gt;
&lt;p&gt;Il convient donc de toujours &lt;strong&gt;s&amp;rsquo;assurer de la définition de l&amp;rsquo;authentification forte&lt;/strong&gt; qu&amp;rsquo;un interlocuteur ou une interlocutrice utilise.&lt;/p&gt;
&lt;h2 id=&#34;les-mécanismes-dauthentification&#34;&gt;Les mécanismes d&amp;rsquo;authentification&lt;/h2&gt;
&lt;p&gt;Cette section du cours n&amp;rsquo;a pas vocation à être exhaustive. La liste qui suit n&amp;rsquo;est même pas forcément représentative des mécanismes les plus fréquemment utilisés. Elle permet cependant de couvrir un large éventail de techniques afin d&amp;rsquo;apporter une culture générale sur le sujet.&lt;/p&gt;
&lt;p&gt;Dans cette section, on utilisera le terme de prouveur pour désigner celui qui tente de prouver son identité ; c&amp;rsquo;est-à-dire de s&amp;rsquo;authentifier. Le terme vérificateur désigne celui qui vérifie les preuves d&amp;rsquo;identité. On peut penser de prime abord que seul l&amp;rsquo;utilisateur tente de prouver son identité auprès d&amp;rsquo;un serveur pour accéder à son compte. La réalité est que presque toujours, le serveur prouve également son identité auprès du logiciel mis en œuvre par l&amp;rsquo;utilisateur ou l&amp;rsquo;utilisatrice. En conséquence, il serait incorrect de considérer que prouveur et utilisateurs sont synonymes dans le chapitre qui suit.&lt;/p&gt;
&lt;h3 id=&#34;la-preuve-par-divulgation&#34;&gt;La preuve par divulgation&lt;/h3&gt;
&lt;p&gt;La méthode la plus universelle pour prouver son identité est de divulguer un secret au vérificateur. Ce dernier peut alors comparer ce secret à celui attendu pour cet acteur. S&amp;rsquo;ils correspondent, alors la preuve est faite. C&amp;rsquo;est le cas typique de l&amp;rsquo;utilisateur qui envoie son mot de passe tel quel à un serveur. C&amp;rsquo;est également le cas pour les codes temporels (TOTP), les codes &lt;em&gt;Transaction Authentification Number (TAN)&lt;/em&gt; (par exemple, des codes reçus par email ou par SMS et à reproduire auprès du vérificateur), les codes PIN, les jetons d&amp;rsquo;authentification, etc. C&amp;rsquo;est également le cas des &amp;ldquo;identifiants de session&amp;rdquo;, comme les &amp;ldquo;cookies de session&amp;rdquo;, qui ne sont ni plus ni moins que des jetons d&amp;rsquo;authentification présentés à chacune des requêtes.&lt;/p&gt;
&lt;p&gt;Ce mécanisme d&amp;rsquo;authentification présente de nombreux défauts, et a pour seul avantage d&amp;rsquo;être extrêmement simple à implémenter, à tout le moins du côté du prouveur. Côté vérificateur, les choses sont plus complexe : il s&amp;rsquo;agit de stocker de manière sécurisée le matériel nécessaire à la vérification de l&amp;rsquo;identité. Ce stockage sécurisé est l&amp;rsquo;objet d&amp;rsquo;un chapitre ultérieur.&lt;/p&gt;
&lt;p&gt;Outre la nécessité d&amp;rsquo;un stockage sécurisé, ce mécanisme d&amp;rsquo;authentification nécessite que le secret exige sur un canal de communication assurant la confidentialité des données. Sans cela, un attaquant ou une attaquante n&amp;rsquo;aurait qu&amp;rsquo;à écouter passivement le réseau pour apprendre le secret. En outre, tous les logiciels manipulant le secret en clair et dans sa forme originale, tel que connu du prouveur, devraient mettre en place des mesures de sécurité afin de limiter les risques de divulgation de ce secret en cas de compromission logicielle : nettoyer la mémoire, mettre en place des pages de garde (&lt;em&gt;page guards&lt;/em&gt;), isoler les traitements des secrets dans des processus séparés. En pratique, cela n&amp;rsquo;est presque jamais fait. C&amp;rsquo;est ainsi que des vulnérabilités comme Heartbleed&lt;sup id=&#34;fnref:28&#34;&gt;&lt;a href=&#34;#fn:28&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;28&lt;/a&gt;&lt;/sup&gt;, qui avait permis de faire des lectures arbitraires dans la mémoire des processus utilisant OpenSSL pour sécuriser les communications, ont permis de récupérer les mots de passe non protégés directement en mémoire. Tous les secrets ainsi exfiltrés étaient directement utilisables pour se connecter aux comptes associés.&lt;/p&gt;
&lt;p&gt;Finalement, ce mécanisme d&amp;rsquo;authentification ne présente aucune protection contre le rejeu. Ainsi, si le canal de communication est intercepté ou si l&amp;rsquo;utilisateur ou l&amp;rsquo;utilisatrice est victime d&amp;rsquo;une attaque par hameçonnage (&lt;em&gt;phishing&lt;/em&gt;), et qu&amp;rsquo;il ou elle saisit son mot de passe sur le site frauduleux, alors l&amp;rsquo;attaquant ou l&amp;rsquo;attaquante apprendra le moyen de preuve et pourra le mettre en œuvre pour accéder au compte associé. Il conviendra néanmoins de nuancer l&amp;rsquo;impact de la vulnérabilité aux attaques par rejeu avec la durée de vie du secret divulgué : certains sont à usage unique ou ont une faible durée de validité (TOTP, TAN, etc.), tandis que d&amp;rsquo;autres ont des durées de vie beaucoup plus longues (par exemple, les mots de passe).&lt;/p&gt;
&lt;pre class=&#34;mermaid&#34;&gt;---
title: Authentification par divulgation d&#39;un mot de passe
---
sequenceDiagram
  autonumber
  actor peggy as Peggy
  box
    actor victor as Victor
    participant db as Base de données
  end

  peggy -&gt;&gt; victor:&#34;Je m&#39;appelle Peggy. Mon mot de passe est #quot;Bonjour1!#quot;.&#34;

  victor -&gt;&gt; victor:Calcule la dérivée du mot de passe reçu

  victor -&gt;&gt; db:&#34;Quel est la dérivée du mot de pase de Peggy ?&#34;
  db -&gt;&gt; victor:&#34;Voici la dérivée du mot de passe de Peggy&#34;

  victor -&gt;&gt; victor:Compare les deux dérivées

  alt Mot de passe valide
    victor -&gt;&gt; peggy:&#34;Bonjour Peggy&#34;
  else Mot de passe invalide
    victor -&gt;&gt; peggy:&#34;Je ne crois pas, non&#34;
  end
&lt;/pre&gt;

&lt;h3 id=&#34;la-preuve-par-défi&#34;&gt;La preuve par défi&lt;/h3&gt;
&lt;p&gt;Les mécanismes d&amp;rsquo;authentification reposant sur des défis sont des procédés interactifs : un dialogue se met en place entre le vérificateur et le prouveur. Ce dialogue permet de s&amp;rsquo;accorder sur une valeur aléatoire, parfois appelée &lt;strong&gt;nonce&lt;/strong&gt;. Cet accord peut être unilatéral : le vérificateur décide arbitrairement de cette valeur. Ensuite le prouveur effectue une opération cryptographique sur cette valeur aléatoire et envoie le résultat au vérificateur. Ce dernier vérifie alors la preuve à l&amp;rsquo;aide d&amp;rsquo;un élément en sa possession et qui est associé à l&amp;rsquo;identité supposée du prouveur.&lt;/p&gt;
&lt;p&gt;Il existe de nombreux protocoles reposant sur les défis ; certains ont de très bonnes propriétés de sécurité ; d&amp;rsquo;autres sont catastrophiquement mauvais, et même pires que la preuve par divulgation !&lt;/p&gt;
&lt;h4 id=&#34;rfc-7616--http-digest&#34;&gt;RFC 7616 : HTTP Digest&lt;/h4&gt;
&lt;p&gt;La RFC 7616&lt;sup id=&#34;fnref:29&#34;&gt;&lt;a href=&#34;#fn:29&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;29&lt;/a&gt;&lt;/sup&gt; décrit le mécanisme d&amp;rsquo;authentification HTTP Digest.&lt;/p&gt;
&lt;p&gt;Le vérificateur génère un nonce et l&amp;rsquo;envoie au prouveur. Ce dernier utilise alors une fonction de hachage cryptographique sur la concaténation de l&amp;rsquo;identité à prouver, le mot de passe associé à cette identité, le nonce, le verbe HTTP et l&amp;rsquo;URI demandée. Le résultat de la fonction de hachage est envoyé au vérificateur. Ce dernier exécute la fonction de hachage de son côté avec les mêmes entrées. Si le résultat de la fonction de hachage appelée par le vérificateur est identique à celui transmis par le prouveur, alors la preuve est faite.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;intérêt supposé de ce mécanisme d&amp;rsquo;authentification est que le mot de passe n&amp;rsquo;est à aucun moment transmis dans la requête HTTP. Celui-ci est protégé par la résistance de la fonction de hachage cryptographique à la découverte d&amp;rsquo;une préimage&lt;sup id=&#34;fnref:30&#34;&gt;&lt;a href=&#34;#fn:30&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;30&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Cet intérêt supposé est cependant assez peu pertinent étant donné que l&amp;rsquo;essentiel des communications HTTP est de nos jours transporté sur des canaux de communication chiffrés (par TLS ou HTTP/3 qui intègrent directement le chiffrement).&lt;/p&gt;
&lt;p&gt;Un intérêt notable de ce mécanisme d&amp;rsquo;authentification est l&amp;rsquo;inclusion d&amp;rsquo;un nonce. Ce dernier permet de contrer les attaques par rejeu ; en effet, même en cas d&amp;rsquo;interception d&amp;rsquo;une preuve, il n&amp;rsquo;est pas possible de l&amp;rsquo;utiliser pour réaliser des tentatives d&amp;rsquo;authentification futures par simple rejeu.&lt;/p&gt;
&lt;p&gt;En revanche, ce mécanisme d&amp;rsquo;authentification requiert que le vérificateur connaisse le mot de passe de l&amp;rsquo;utilisateur&lt;sup id=&#34;fnref:31&#34;&gt;&lt;a href=&#34;#fn:31&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;31&lt;/a&gt;&lt;/sup&gt; et qu&amp;rsquo;il le stocke tel quel, ou sous un format réversible. En conséquence, en cas de fuite de la base de données du vérificateur, un attaquant pourrait immédiatement utiliser les valeurs récupérées pour usurper l&amp;rsquo;identité de tous les acteurs auprès de ce vérificateur. Cet inconvénient majeur disqualifie totalement ce mécanisme d&amp;rsquo;authentification, qui ne doit jamais être employé.&lt;/p&gt;
&lt;p&gt;Un autre problème de sécurité est que la divulgation de toute preuve à un attaquant ou une attaquante lui permet d&amp;rsquo;effectuer ensuite une recherche exhaustive hors-ligne sur le mot de passe qui a permis de générer cette preuve ; tous les autres éléments sont connus. La possibilité de recherche exhaustive hors-ligne sur des mots de passe est agravée par le fait que les fonctions de hachage spécifiées dans la RFC sont très insuffisantes ; ces considérations de sécurité sont identiques à celles discutées dans le chapitre sur le stockage des dérivées des mots de passe.&lt;/p&gt;
&lt;pre class=&#34;mermaid&#34;&gt;---
title: Authentification avec HTTP Digest (simplifiée)
---
sequenceDiagram
  autonumber
  actor peggy as Peggy
  box
    actor victor as Victor
    participant db as Base de données
  end

  peggy -&gt;&gt; victor:&#34;Je voudrais faire X sur l&#39;adresse Y.&#34;

  victor -&gt;&gt; peggy:&#34;Heu, t&#39;es qui ? Voici un nonce.&#34;

  peggy -&gt;&gt; peggy: Calcule le condensat, avec son nom, son mot de passe, X, Y et le nonce

  peggy -&gt;&gt; victor:&#34;Je m&#39;appelle Peggy. Je voudrais faire X sur l&#39;adresse Y. Voici le nonce et mon condensat.&#34;

  victor -&gt;&gt; db: &#34;C&#39;est quoi le mot de passe de Peggy ?&#34;

  db -&gt;&gt; victor: &#34;Le mot de passe de Peggy est #quot;Bonjour1!#quot;...&#34;

  victor -&gt;&gt; victor:Calcule le condensat, avec le nom #quot;Peggy#quot;, le mot de passe de Peggy, X, Y et le nonce

  alt Les condensats correspondent
    victor -&gt;&gt; peggy:&#34;Bonjour Peggy. Voici le résultat de X sur Y.&#34;
  else Les condensats ne correspondent pas
    victor -&gt;&gt; peggy:&#34;Je ne crois pas, non&#34;
  end
&lt;/pre&gt;

&lt;h4 id=&#34;la-signature-électronique&#34;&gt;La signature électronique&lt;/h4&gt;
&lt;p&gt;La signature électronique est une méthode d&amp;rsquo;authentification très courante. Elle est notamment employée par les protocoles SSH, TLS, et IPsec.&lt;/p&gt;
&lt;p&gt;Le principe général est que le prouveur dispose d&amp;rsquo;une clé privée et le vérificateur dispose de la clé publique associée. Le prouveur effectue la signature électronique d&amp;rsquo;un nonce et le vérificateur n&amp;rsquo;a alors qu&amp;rsquo;à utiliser la clé publique pour en vérifier l&amp;rsquo;authenticité. Si elle est authentique, alors la preuve est faite.&lt;/p&gt;
&lt;p&gt;Ce mécanisme d&amp;rsquo;authentification présente l&amp;rsquo;avantage de lever toute contrainte relative à la confidentialité du stockage par le vérificateur : seule une clé publique est stockée, dont la divulgation ne remet pas en cause la sécurité du mécanisme d&amp;rsquo;authentification. La contrainte d&amp;rsquo;intégrité du stockage de la clé publique peut elle-même être levée si la clé publique est inscrite dans un certificat, faisait partie d&amp;rsquo;une infrastructure de clés. Il faudra néanmoins assurer l&amp;rsquo;intégrité du certificat racine de l&amp;rsquo;infrastructure de clés.&lt;/p&gt;
&lt;p&gt;Des précautions doivent cependant être prises, notamment pour éviter les attaques par rejeu. En effet, il est important que le prouveur s&amp;rsquo;assure que les nonces ne soient jamais réutilisés (en général ou au minimum par un même vérificateur). En effet, si un nonce était réutilisé, il ne serait plus nécessaire d&amp;rsquo;avoir accès à la clé privée permettant la signature ; il suffirait juste de rejouer la preuve correspondante qui aurait été générée la première fois que ce nonce avait été signé. Un attaquant ou une attaquante pourrait également hameçonner un prouveur dans le cadre d&amp;rsquo;une attaque par relais. Cette attaque consiste alors à présenter au prouveur le nonce choisi par le vérificateur, récupérer cette preuve et la jouer à son compte auprès du véritable vérificateur.&lt;/p&gt;
&lt;p&gt;Pour contrer ces attaques par rejeu ou par relais, la plupart des implémentations font intervenir le prouveur dans le choix du nonce ; le prouveur est alors sûr qu&amp;rsquo;au moins sa propre contribution à l&amp;rsquo;établissement du nonce est réellement aléatoire et non rejouée.&lt;/p&gt;
&lt;p&gt;Une autre contremesure aux attaques par relais est de s&amp;rsquo;assurer que le prouveur utilise une clé privée différente par vérificateur. Le prouveur peut utiliser, par exemple, le nom du site web consulté comme discriminant. Ainsi, en cas d&amp;rsquo;hameçonnage, le site web de l&amp;rsquo;attaquant ou de l&amp;rsquo;attaquante ne dispose pas de la même URL et, pour générer la signature, la clé privée utilisée est différente de la clé qui serait utilisée pour le vérificateur légitime. En conséquence, la preuve interceptée par l&amp;rsquo;attaquant ou l&amp;rsquo;attaquante n&amp;rsquo;est pas valide auprès du véritable vérificateur ! Cette parade peut être utilisée en plus de la précédente ; leur combinaison est utilisée par les protocoles WebAuthn, U2F et FIDO2, détaillés ultérieurement dans ce cours.&lt;/p&gt;
&lt;pre class=&#34;mermaid&#34;&gt;---
title: Authentification d&#39;un serveur TLS avec confidentialité persistente (simplifiée)
---
sequenceDiagram
  autonumber
  actor peggy as Peggy (Serveur TLS)
  actor victor as Victor (Client TLS)

  victor -&gt;&gt; victor:Tire un nonce

  victor -&gt;&gt; victor:Tire une bi-clé temporaire (DHE)

  victor -&gt;&gt; peggy:&#34;Je voudrais consulter https://broken-by-design.fr. Voici un nonce et une clé publique temporaire&#34;

  peggy -&gt;&gt; peggy:Tire un nonce

  peggy -&gt;&gt; peggy:Tire une bi-clé temporaire (DHE)

  peggy -&gt;&gt; peggy:Prépare le message &#34;Voici un autre nonce&#34;

  peggy -&gt;&gt; peggy:Prépare le message &#34;Voici un certificat pour broken-by-design.fr&#34;

  peggy -&gt;&gt; peggy:Prépare le message &#34;Voici une autre clé publique temporaire&#34;

  peggy -&gt;&gt; peggy:Calcule un condensat cryptographique de l&#39;ensemble des messages échangés et préparés

  peggy -&gt;&gt; peggy:Signe avec sa clé privée le condensat cryptographique

  peggy -&gt;&gt; victor:&#34;Voici un autre nonce&#34;

  peggy -&gt;&gt; victor:&#34;Voici un certificat pour broken-by-design.fr&#34;

  peggy -&gt;&gt; victor:&#34;Voici une autre clé publique temporaire&#34;

  peggy -&gt;&gt; victor:&#34;Voici la signature des messages précédents&#34;

  victor -&gt;&gt; victor:Vérifie l&#39;authenticité du certificat

  victor -&gt;&gt; victor:Calcule le condensat cryptographique de l&#39;ensemble des messages reçus (sauf la signature).

  victor -&gt;&gt; victor:Vérifie la signature cryptographique reçue avec la clé publique du certificat

  alt La signature est valide
    par Calcul des clés par Peggy
      peggy -&gt;&gt; victor:&#34;Top ! À partir de maintenant, échangeons de manière sécurisée.&#34;
      peggy -&gt;&gt; peggy:Calcule le PMS et les autres clés
    and Calcul des clés par Victor
      victor -&gt;&gt; peggy:&#34;Top ! À partir de maintenant, échangeons de manière sécurisée.&#34;
      victor -&gt;&gt; victor:Calcule le PMS et les autres clés
    end
    victor -&gt; peggy:&#34;#10216;illisible#10217; (vérification de l&#39;intégrité des échanges précédents)&#34;
    victor -&gt; peggy:&#34;#10216;illisible#10217; (échanges métier)&#34;
  else La signature est invalide
    victor -&gt;&gt; peggy:&#34;Je ne crois pas, non&#34;
  end
&lt;/pre&gt;

&lt;h3 id=&#34;la-preuve-par-déchiffrement&#34;&gt;La preuve par déchiffrement&lt;/h3&gt;
&lt;p&gt;La preuve par déchiffrement repose sur la capacité du prouveur à démontrer la connaissance d&amp;rsquo;un secret arbitraire qui lui a été transmis sous une forme chiffrée par le vérificateur.&lt;/p&gt;
&lt;p&gt;Pour déchiffrer ce secret arbitraire, le prouveur doit disposer d&amp;rsquo;une clé symétrique ou d&amp;rsquo;une clé privée. La clé symétrique peut être issue d&amp;rsquo;un calcul, comme le résultat d&amp;rsquo;une fonction de dérivation de mot de passe (voir chapitre sur le stockage des éléments authentifiants pour en apprendre plus sur ces fonctions).&lt;/p&gt;
&lt;p&gt;En déchiffrant le secret arbitraire envoyé par le vérificateur, le prouveur démontre qu&amp;rsquo;il connait la clé de déchiffrement et donc qu&amp;rsquo;il est celui qu&amp;rsquo;il prétend être. Cela est pourtant insuffisant pour convaincre le vérificateur, puisque ce dernier ne sait encore rien du résultat de ce déchiffrement. Une nouvelle opération cryptographique est donc nécessaire : le prouveur doit exercer ce secret arbitraire dans une opération cryptographique et envoyer le résultat de cette dernière au vérificateur. Le vérificateur pourra alors vérifier que l&amp;rsquo;opération cryptographique a bien mis en œuvre le secret qu&amp;rsquo;il avait envoyé au prouveur.&lt;/p&gt;
&lt;p&gt;Les implémentations de cette preuve varient beaucoup. Elle est employée par le protocole Kerberos ou par certaines suites cryptographiques de TLS.&lt;/p&gt;
&lt;p&gt;Avec les suites cryptographiques de TLS ne mettant pas en œuvre la confidentialité persistante (&lt;em&gt;perfect forward secrecy (PFS)&lt;/em&gt;), le vérificateur (le client TLS) va envoyer au prouveur (le serveur TLS) un secret chiffré avec la clé publique contenue dans le certificat du serveur TLS. Si le serveur TLS est bien en possession de la clé privée associée à la clé publique contenue dans le certificat, il pourra déchiffrer ce secret. Ce secret, appelé &amp;ldquo;&lt;em&gt;pre-master secret (PMS)&lt;/em&gt;&amp;rdquo; est utilisé ensuite par le vérificateur et le prouveur pour calculer les clés cryptographiques qui seront utilisées pour sécuriser l&amp;rsquo;ensemble de la communication TLS. Si le prouveur n&amp;rsquo;a pas été en mesure de déchiffrer le PMS, il ne sera pas en mesure de lire, ni de répondre aux messages chiffrés envoyés par le vérificateur. Si en revanche, il est en mesure de le faire, alors implicitement, il aura prouvé qu&amp;rsquo;il était en possession de la clé privée et la preuve d&amp;rsquo;identité sera faite.&lt;/p&gt;
&lt;pre class=&#34;mermaid&#34;&gt;---
title: Authentification TLS sans confidentialité persistente (simplifiée)
---
sequenceDiagram
  autonumber
  actor peggy as Peggy (Serveur TLS)
  actor victor as Victor (Client TLS)

  victor -&gt;&gt; victor:Tire un nonce

  victor -&gt;&gt; peggy:&#34;Je voudrais consulter https://broken-by-design.fr. Voici un nonce.&#34;

  peggy -&gt;&gt; peggy:Tire un autre nonce

  peggy -&gt;&gt; victor:&#34;Voici un autre nonce&#34;

  peggy -&gt;&gt; victor:&#34;Voici un certificat pour broken-by-design.fr&#34;

  victor -&gt;&gt; victor:Vérifie l&#39;authenticité du certificat reçu

  victor -&gt;&gt; victor:Tire le PMS

  victor -&gt;&gt; victor:Chiffre le PMS avec la clé publique du certificat

  victor -&gt;&gt; peggy:&#34;Voici le PMS chiffré&#34;

  par Peggy indique chiffrer ses communications
      peggy -&gt;&gt; victor:&#34;Top ! À partir de maintenant, échangeons de manière sécurisée.&#34;
  and Victor indique chiffrer ses communications
      victor -&gt;&gt; peggy:&#34;Top ! À partir de maintenant, échangeons de manière sécurisée.&#34;
  end

  alt Peggy ne connait pas la clé privée
    peggy --x victor:Peggy ne dispose pas des clés pour chiffrer un message pour Victor
  else Peggy connait la clé privée
    peggy -&gt;&gt; peggy:Déchiffre le PMS avec sa clé privée

    par Calcul des clés par Peggy
      peggy -&gt;&gt; peggy:Calcule les autres clés à partir du PMS
    and Calcul des clés par Victor
      victor -&gt;&gt; victor:Calcule les autres clés à partir du PMS
    end

    alt Peggy envoie en premier à Victor un message de vérification des échanges
      peggy -&gt;&gt; peggy:Calcule un condensat cryptographique de tous les messages échangés jusqu&#39;ici
      peggy -&gt;&gt; peggy:Protège le condensat en intégrité et confidentialité avec les clés calculées
      peggy -&gt;&gt; victor:&#34;[Chiffré] Voici le condensat de nos échanges&#34;
      victor -&gt;&gt; victor:Calcule un condensat cryptographique de tous les messages échangés jusqu&#39;ici sauf le dernier reçu
      victor -&gt;&gt; victor:Compare le condensat reçu à celui qu&#39;il a calculé
      alt Les condensats ne correspondent pas
        victor -&gt;&gt; peggy: &#34;Je ne crois pas, non.&#34;
      else Les condensats correspondent
        victor -&gt;&gt; victor:Calcule un condensat cryptographique de tous les messages échangés jusqu&#39;ici
        victor -&gt;&gt; victor:Protège le condensat en intégrité et confidentialité avec les clés calculées
        victor -&gt;&gt; peggy:&#34;[Chiffré] Voici le condensat de nos échanges&#34;
        peggy -&gt;&gt; peggy:Calcule un condensat cryptographique de tous les messages échangés jusqu&#39;ici sauf le dernier reçu
        peggy -&gt;&gt; peggy:Compare le condensat reçu à celui qu&#39;il a calculé
        alt Les condensats correspondent
          peggy -&gt; victor:&#34;[Chiffré] Données métier&#34;
        else Les condensats ne correspondent pas
          peggy -&gt;&gt; victor: &#34;Je ne crois pas, non.&#34;
        end

      end
    else Victor envoie en premier à Peggy un message de vérification des échanges
      victor -&gt;&gt; victor:Calcule un condensat cryptographique de tous les messages échangés jusqu&#39;ici
      victor -&gt;&gt; victor:Protège le condensat en intégrité et confidentialité avec les clés calculées
      victor -&gt;&gt; peggy:&#34;[Chiffré] Voici le condensat de nos échanges&#34;
      peggy -&gt;&gt; peggy:Calcule un condensat cryptographique de tous les messages échangés jusqu&#39;ici sauf le dernier reçu
      peggy -&gt;&gt; peggy:Compare le condensat reçu à celui qu&#39;il a calculé

      alt Les condensats ne correspondent pas
        peggy -&gt;&gt; victor: &#34;Je ne crois pas, non.&#34;
      else Les condensats correspondent
        peggy -&gt;&gt; peggy:Calcule un condensat cryptographique de tous les messages échangés jusqu&#39;ici
        peggy -&gt;&gt; peggy:Protège le condensat en intégrité et confidentialité avec les clés calculées
        peggy -&gt;&gt; victor:&#34;[Chiffré] Voici le condensat de nos échanges&#34;
        victor -&gt;&gt; victor:Calcule un condensat cryptographique de tous les messages échangés jusqu&#39;ici sauf le dernier reçu
        victor -&gt;&gt; victor:Compare le condensat reçu à celui qu&#39;il a calculé
        alt Les condensats correspondent
          victor -&gt; peggy:&#34;[Chiffré] Données métier&#34;
        else Les condensats ne correspondent pas
          victor -&gt;&gt; peggy: &#34;Je ne crois pas, non.&#34;
        end
      end
    end
  end
&lt;/pre&gt;

&lt;p&gt;Avec Kerberos, le mot de passe du prouveur est utilisé pour déchiffrer une clé symétrique envoyée par le serveur d&amp;rsquo;authentification (&lt;em&gt;authentication server (AS)&lt;/em&gt;). Cette clé est ensuite utilisée par le prouveur pour chiffrer un message à destination du serveur d&amp;rsquo;émission de tickets (&lt;em&gt;ticket granting service (TGS)&lt;/em&gt;). Ce serveur s&amp;rsquo;attend à ce que le message soit chiffré avec une clé particulière : celle envoyée chiffrée au prouveur par le serveur d&amp;rsquo;authentification. Ce mécanisme d&amp;rsquo;authentification est un peu plus complexe qu&amp;rsquo;expliqué plus haut, car le rôle de vérificateur est, en fait, endossé par deux acteurs distincts : le serveur d&amp;rsquo;authentification d&amp;rsquo;une part, et le serveur d&amp;rsquo;émission de tickets d&amp;rsquo;autre part.&lt;/p&gt;
&lt;pre class=&#34;mermaid&#34;&gt;---
title: Authentification Kerberos (simplifiée)
---
sequenceDiagram
  autonumber
  actor peggy as Peggy (Client)
  box Serveur(s)
    actor trent as Trent (Serveur d&#39;authentification)
    actor victor as Victor (Serveur d&#39;émission de tickets)
    participant db as Base de données
  end

  peggy -&gt;&gt; trent:&#34;Je suis Peggy.&#34;.
  trent -&gt;&gt; db:&#34;C&#39;est quoi la dérivée du mot de passe de Peggy ?&#34;
  db -&gt;&gt; trent:&#34;La dérivée du mot de passe de Peggy est...&#34;
  trent -&gt;&gt; db:&#34;C&#39;est quoi la clé de Victor ?&#34;
  db -&gt;&gt; trent:&#34;La clé de Victor est...&#34;
  trent -&gt;&gt; trent:Tire une clé A
  trent -&gt;&gt; peggy:&#34;[Chiffré avec la dérivée du mot de passe de Peggy] Voici la clé A.
  trent -&gt;&gt; peggy:&#34;[Chiffré avec la clé de Victor] Elle dit s&#39;appeler Peggy. Ce message est valide M secondes/minutes/heures. Voici la clé A.&#34;
  peggy -&gt;&gt; peggy:Dérive son mot de passe
  peggy -&gt;&gt; peggy:Déchiffre la clé A avec la dérivée de son mot de passe
  peggy -&gt;&gt; victor:&#34;Trent m&#39;a donné ce message pour toi.&#34;
  victor -&gt;&gt; victor:Déchiffre le message de Trent avec sa propre clé
  victor -&gt;&gt; victor:Vérifie la période de validité de ces informations
  alt La période de validité est expirée
    victor -&gt;&gt; peggy:&#34;Je ne crois pas, non.&#34;
  else La période de validité est en cours
    peggy -&gt;&gt; victor:&#34;[Chiffré avec la clé A] &#34;Je suis Peggy. Je veux accéder au serveur X.&#34;
    victor -&gt;&gt; victor:Déchiffre le message Peggy avec la clé A
    victor -&gt;&gt; victor:Vérifie que le nom Peggy figure bien dans les deux messages déchiffrés
    alt Peggy ne connait pas véritablement la clé A, car c&#39;était le mauvais mot de passe. Son nom ne figure pas dans son message après déchiffrement.
      victor -&gt;&gt; peggy:&#34;Je ne crois pas, non.&#34;
    else Peggy connait la clé A. Son nom figure bien dans le message qu&#39;elle a chiffré.
      Note right of victor:Victor continue le protocole avec la partie &#34;autorisation&#34;
    end
  end
&lt;/pre&gt;

&lt;p&gt;La preuve d&amp;rsquo;identité par déchiffrement est plus complexe à mettre en œuvre et ses assurances de sécurité sont plus faibles que d&amp;rsquo;autres types de preuves, notamment comme implémentée dans TLS 1.3. En conséquence, cette preuve est de moins en moins utilisée. Il s&amp;rsquo;agit d&amp;rsquo;un bel exemple du développement itératif et de l&amp;rsquo;amélioration continue des protocoles cryptographiques ; beaucoup de ceux conçus dans les années 90 sont désormais écartés au profit de constructions plus récentes et robustes.&lt;/p&gt;
&lt;h4 id=&#34;la-preuve-avec-divulgation-nulle-de-connaissance&#34;&gt;La preuve avec divulgation nulle de connaissance&lt;/h4&gt;
&lt;p&gt;Les mécanismes reposant sur la preuve par divulgation nulle de connaissance (ou sans apport de connaissance) sont assez divers. Le principe commun de tous ces mécanismes est que l&amp;rsquo;élément secret utilisé par le prouveur n&amp;rsquo;est à aucun moment divulgué au vérificateur. Ce dernier reçoit la preuve de la connaissance de ce secret, sans obtenir d&amp;rsquo;information sur le secret !&lt;/p&gt;
&lt;p&gt;La divulgation nulle de connaissance semble souvent &amp;ldquo;magique&amp;rdquo;. Jean-Jacques Quisquater et Louis Guillou ont publié en 1989 un article de vulgarisation intitulé &amp;ldquo;Comment expliquer à vos enfants les protocoles sans apport de connaissance&amp;rdquo;, dont le récit est rapporté et traduit dans un article Wikipedia, et dont la lecture peut se révéler éclairante.&lt;sup id=&#34;fnref:32&#34;&gt;&lt;a href=&#34;#fn:32&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;32&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Une caractéristique intéressante de la preuve à divulgation nulle de connaissance telle qu&amp;rsquo;implémentée dans le protocole de Schnorr&lt;sup id=&#34;fnref:33&#34;&gt;&lt;a href=&#34;#fn:33&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;33&lt;/a&gt;&lt;/sup&gt;, ou dans celui de Guillou-Quisquater&lt;sup id=&#34;fnref:34&#34;&gt;&lt;a href=&#34;#fn:34&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;34&lt;/a&gt;&lt;/sup&gt;, est que le vérificateur peut être raisonnablement certain de la preuve&lt;sup id=&#34;fnref:35&#34;&gt;&lt;a href=&#34;#fn:35&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;35&lt;/a&gt;&lt;/sup&gt; qui lui est apportée par le prouveur, tout en étant parfaitement incapable de convaincre un tiers de la même chose, a posteriori. Cette propriété est particulièrement intéressante dans le cas d&amp;rsquo;applications préservant la vie privée et nécessitant d&amp;rsquo;authentifier un acteur tout en pouvant nier de manière plausible avoir des preuves que cette authentification ait eu lieu.&lt;/p&gt;
&lt;pre class=&#34;mermaid&#34;&gt;---
title: Illustration du protocole de Feige–Fiat–Shamir (simplifié)
---
sequenceDiagram
  autonumber
  actor p as Peggy
  box
    actor v as Victor
    participant db as Base de données
  end

  p -&gt;&gt; v:&#34;Je suis Peggy.&#34;
  v -&gt;&gt; db:&#34;C&#39;est quoi la clé publique de Peggy ?&#34;
  db -&gt;&gt; v:&#34;La clé publique de Peggy est...&#34;
  v -&gt;&gt; p:&#34;Convaincs moi.&#34;
  p -&gt;&gt; p: Se munit de sa clé privée S
  loop Jusqu&#39;à ce que Victor soit convaincu ou que Peggy ne calcule pas correctement
    p -&gt;&gt; p:Tire une valeur aléatoire x, et calcule une fonction D(x) = X
    p -&gt;&gt; v:&#34;Voici X&#34;
    v -&gt;&gt; v:Tire à pile ou face
    v --&gt; p:&#34;Voici le résultat du tirage à pile ou face&#34;
    p -&gt;&gt; p:Calcule la fonction F(S, x, pile ou face) = Y
    p -&gt;&gt; v:&#34;Voici le résultat du calcul&#34;
    v -&gt;&gt; v:Vérifie le calcul avec la clé publique de Peggy avec une fonction G(X, Y, clé publique de Peggy)
    alt Le calcul est correct
      v -&gt;&gt; v:Est un peu plus convaincu
    else Le calcul est incorrect
      v -&gt;&gt; p: &#34;Je ne te crois pas. Fin de conversation.&#34;
    end
  end
&lt;/pre&gt;

&lt;h4 id=&#34;la-preuve-par-calculs-répartis&#34;&gt;La preuve par calculs répartis&lt;/h4&gt;
&lt;p&gt;Par proximité avec les protocoles à divulgation nulle de connaissance, il peut être fait mention également de ceux utilisant des fonctions pseudo-aléatoires oublieuses (&lt;em&gt;oblivious pseudo-random functions (OPRF)&lt;/em&gt; ; il n&amp;rsquo;existe pas de traduction faisant autorité).&lt;/p&gt;
&lt;p&gt;Les OPRF sont des fonctions impliquant deux parties qui contribuent aux entrées d&amp;rsquo;une fonction générant un nombre aléatoire. L&amp;rsquo;une des parties apprend la valeur de sortie de la fonction, sans avoir appris la contribution de l&amp;rsquo;autre partie ; et l&amp;rsquo;autre partie n&amp;rsquo;apprend rien. La RFC 9497&lt;sup id=&#34;fnref:36&#34;&gt;&lt;a href=&#34;#fn:36&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;36&lt;/a&gt;&lt;/sup&gt; décrit une fonction de cette nature. Cette construction est utilisée dans deux protocoles d&amp;rsquo;authentification très différents : Privacy Pass&lt;sup id=&#34;fnref:37&#34;&gt;&lt;a href=&#34;#fn:37&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;37&lt;/a&gt;&lt;/sup&gt; et Opaque&lt;sup id=&#34;fnref:38&#34;&gt;&lt;a href=&#34;#fn:38&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;38&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Privacy Pass est un protocole d&amp;rsquo;authentification permettant de prouver non pas une identité individuelle, mais l&amp;rsquo;appartenance à un groupe d&amp;rsquo;individus, sans pouvoir distinguer l&amp;rsquo;individu. Il s&amp;rsquo;agit bien d&amp;rsquo;une authentification : un acteur prouve une identité (de groupe) à un vérificateur, qui, en cas de succès, le reconnait bien comme ayant cette identité (d&amp;rsquo;appartenance à ce groupe). On pourrait, par exemple, imaginer un service de vidéos à la demande payant, qui authentifierait un acteur sans être capable de tracer ce qu&amp;rsquo;il visionne ; tout ce qu&amp;rsquo;il saurait, c&amp;rsquo;est que l&amp;rsquo;acteur accèdant à la vidéo est à jour de son abonnement. La cryptographie impliquée est un peu avancée pour ce cours, mais le lecteur intéressé pourra en apprendre plus en consultant les documents du groupe de travail &amp;ldquo;Privacy Pass&amp;rdquo; de l&amp;rsquo;&lt;em&gt;Internet Engineering Task Force (IETF)&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Opaque, quant à lui, est un protocole d&amp;rsquo;authentification de la catégorie des &lt;em&gt;Strong Asymmetric Password-based Authenticated Key Exchange (SaPAKE)&lt;/em&gt;, et utilise donc un mot de passe pour effectuer l&amp;rsquo;authentification. Il utilise cependant une OPRF afin de permettre de prouver une identité spécifique sans divulguer d&amp;rsquo;information sur le mot de passe auprès du vérificateur ! L&amp;rsquo;OPRF est, en effet, utilisée pour calculer une valeur dérivée du mot de passe qui permet le déverrouillage d&amp;rsquo;un coffre-fort numérique contenant une clé privée. Cette clé privée est ensuite utilisée pour générer la signature d&amp;rsquo;un défi, comme dans le cas classique des protocoles à signature de défis. L&amp;rsquo;intérêt d&amp;rsquo;avoir utilisé une OPRF est que le vérificateur est impliqué dans chaque tentative de déverrouillage du coffre-fort, ce qui lui permet d&amp;rsquo;empêcher les attaques par recherche exhaustive et de &amp;ldquo;verrouiller&amp;rdquo; le compte associé à cette identité si le nombre d&amp;rsquo;échecs est trop important ! Une fonctionnalité bien utile qui devrait être implémentée par tous les fournisseurs de gestionnaires de mots de passe en ligne synchronisés dans le cloud&amp;hellip; De son côté, Whatsapp a mis en œuvre Opaque pour ses sauvegardes chiffrées de bout-en-bout&lt;sup id=&#34;fnref:39&#34;&gt;&lt;a href=&#34;#fn:39&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;39&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;pre class=&#34;mermaid&#34;&gt;---
title: Authentification avec le protocole Opaque (simplifiée)
---
sequenceDiagram
  autonumber
  actor p as Peggy
  box
    actor v as Victor
    participant db as Base de données
  end

  p -&gt;&gt; p:Tire une valeur aléatoire R
  p -&gt;&gt; p:Calcule 1/R
  p -&gt;&gt; p:Dérive son mot de passe
  p -&gt;&gt; v:&#34;Je suis Peggy.&#34;
  p -&gt;&gt; v:&#34;[Chiffré avec R]La dérivée de mon mot de passe est...&#34;
  v -&gt;&gt; p:&#34;Voici ton coffre-fort.&#34;
  v -&gt;&gt; v: Se munit de sa clé S
  v -&gt;&gt; p:&#34;[Chiffré avec S][Chiffré avec R]La dérivée de mon mot de passe est...&#34;
  v -&gt;&gt; v: Tire un nonce
  v -&gt;&gt; p:&#34;Voici un nonce&#34;
  p --&gt; p:Déchiffre le message reçu avec 1/R, ce qui donne &#34;[Chiffré avec S]La dérivée de mon mot de passe est...&#34;
  alt Peggy ne connait pas son mot de passe
    Note right of p:Utiliser &#34;[Chiffré avec S]La dérivée de mon mot de passe est...&#34; comme clé ne permet pas de déchiffrer le coffre-fort. &#34;Peggy&#34; ne peut continuer le protocole.
  else
    p -&gt;&gt; p:Utilise &#34;[Chiffré avec S]La dérivée de mon mot de passe est...&#34; comme clé pour déchiffrer le coffre-fort
    p -&gt;&gt; p:Utilise la clé privée contenue dans le coffre pour signer le nonce
    p -&gt;&gt; v:&#34;Voici le nonce signé&#34;
    v -&gt;&gt; db:&#34;C&#39;est quoi la clé publique de Peggy ?&#34;
    db -&gt;&gt; v:&#34;La clé publique de Peggy est...&#34;
    v -&gt;&gt; v:Vérifie la signature du nonce avec la clé publique de Peggy
    alt La signature est valide
      v -&gt;&gt; p:&#34;Bonjour Peggy!&#34;
    else La signature est invalide
      v -&gt;&gt; p:&#34;Je ne crois pas, non.&#34;
    end
  end
&lt;/pre&gt;

&lt;h2 id=&#34;du-stockage-des-éléments-authentifiants&#34;&gt;Du stockage des éléments authentifiants&lt;/h2&gt;
&lt;p&gt;Pour effectuer l&amp;rsquo;authentification d&amp;rsquo;un acteur, le vérificateur a besoin d&amp;rsquo;avoir accès à une information permettant de vérifier la preuve d&amp;rsquo;identité. De la nature de la preuve dépend la nature de l&amp;rsquo;information à stocker côté vérificateur. Le cas le plus typique est celui du mot de passe, mais il en existe d&amp;rsquo;autres, comme les secrets permettant la génération des codes temporels (TOTP), des clés publiques ou des certificats.&lt;/p&gt;
&lt;h3 id=&#34;protocoles-reposant-sur-de-la-cryptographie-à-clé-publique&#34;&gt;Protocoles reposant sur de la cryptographie à clé publique&lt;/h3&gt;
&lt;p&gt;Dans le cas où la preuve consiste en une signature numérique vérifiable avec la cryptographie à clé publique, tous les éléments stockés par le vérificateur sont publics par nature ; la seule protection requise est en intégrité, afin de prévenir un attaquant de remplacer les éléments de vérification par les siens. La confidentialité peut néanmoins être un sujet, en particulier si les clés sont réutilisées auprès de plusieurs vérificateurs (voir la section de ce cours dédiée à la réutilisation des moyens de preuve).&lt;/p&gt;
&lt;h3 id=&#34;protocole-reposant-sur-de-la-cryptographie-à-clé-secrète&#34;&gt;Protocole reposant sur de la cryptographie à clé secrète&lt;/h3&gt;
&lt;p&gt;La cryptographie à clé secrète ou cryptographie symétrique effectue les opérations de vérification avec la même clé que celle qui a permis de créer la preuve. En conséquence, cette clé doit être stockée en clair, sous une forme réversible, ou dans un équipement de sécurité (par exemple, un TPM, un HSM, ou une carte à puce) permettant sa mise en œuvre sans risque d&amp;rsquo;extraction, copie ou falsification. Ce dernier cas est malheureusement trop rare.&lt;/p&gt;
&lt;p&gt;Étant donné que la compromission en confidentialité du stockage du vérificateur permet ensuite l&amp;rsquo;usurpation de l&amp;rsquo;identité des acteurs, les protocoles utilisant de la cryptographie à clé secrète sont à éviter, en particulier s&amp;rsquo;il s&amp;rsquo;agit de l&amp;rsquo;unique facteur d&amp;rsquo;authentification.&lt;/p&gt;
&lt;p&gt;C&amp;rsquo;est le cas notamment des protocoles utilisant les mécanismes de preuve de type challenge/response, comme le mode &amp;ldquo;digest&amp;rdquo; de HTTP, spécifié dans la RFC 7616&lt;sup id=&#34;fnref1:29&#34;&gt;&lt;a href=&#34;#fn:29&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;29&lt;/a&gt;&lt;/sup&gt;. C&amp;rsquo;est également le cas du protocole TOTP, spécifié dans la RFC 6238&lt;sup id=&#34;fnref:40&#34;&gt;&lt;a href=&#34;#fn:40&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;40&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h3 id=&#34;protocoles-reposant-sur-les-mots-de-passe&#34;&gt;Protocoles reposant sur les mots de passe&lt;/h3&gt;
&lt;p&gt;Le stockage des mots de passe par le vérificateur est sans doute la problématique liée à l&amp;rsquo;authentification la plus connue, du fait de la quasi-omniprésence des mots de passe comme méthode d&amp;rsquo;authentification, des méthodes de stockage qui ont largement évolué à mesure que les techniques d&amp;rsquo;attaque se sont sophistiquées, et des sanctions de la CNIL qui ont été mises en avant sur ces sujets.&lt;/p&gt;
&lt;p&gt;Si le mot de passe de l&amp;rsquo;utilisateur est stocké en clair par le vérificateur, alors la problématique est la même que lorsqu&amp;rsquo;est utilisé un protocole reposant sur de la cryptographie à clé secrète.&lt;/p&gt;
&lt;p&gt;Une meilleure méthode consiste à stocker non pas le mot de passe lui-même, mais le résultat d&amp;rsquo;une fonction dite de dérivation au mot de passe. Ce résultat de la dérivée est parfois appelé &amp;ldquo;empreinte&amp;rdquo;. Parfois, la fonction de dérivation est appelée &amp;ldquo;fonction de hachage&amp;rdquo;, de manière abusive, du fait que nombre de ces dérivations sont faites à l&amp;rsquo;aide de fonctions de hachage cryptographiques. Il existe de très nombreuses fonctions de dérivation, comme nous le verrons plus loin, avec des niveaux de sécurité assez variables.&lt;/p&gt;
&lt;p&gt;Finalement, la meilleure méthode reste encore de ne pas transmettre du tout le mot de passe au vérificateur, mais plutôt d&amp;rsquo;utiliser le mot de passe pour générer une preuve vérifiable ; cette preuve est alors l&amp;rsquo;unique élément transmis au vérificateur qui ignore tout du mot de passe de l&amp;rsquo;acteur ! C&amp;rsquo;est le cas avec le protocole OPAQUE présenté précédemment dans ce cours.&lt;/p&gt;
&lt;p&gt;Concernant la dérivation des mots de passe, les principales attaques sont :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;la recherche exhaustive ou guidée (&lt;em&gt;bruteforce&lt;/em&gt;) ;&lt;/li&gt;
&lt;li&gt;le précalcul ;&lt;/li&gt;
&lt;li&gt;le &amp;ldquo;bourrage&amp;rdquo; de mots de passe (&lt;em&gt;credential stuffing&lt;/em&gt;)&lt;sup id=&#34;fnref:41&#34;&gt;&lt;a href=&#34;#fn:41&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;41&lt;/a&gt;&lt;/sup&gt; ;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;l&amp;rsquo;épluchage&amp;rdquo; de mots de passe (&lt;em&gt;credential shucking&lt;/em&gt;)&lt;sup id=&#34;fnref:42&#34;&gt;&lt;a href=&#34;#fn:42&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;42&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour ce qui est de la recherche exhaustive ou guidée, si le mot de passe est trop faible, la méthode de dérivation utilisée n&amp;rsquo;aura pas d&amp;rsquo;incidence sur la difficulté à retrouver le mot de passe. Même avec la meilleure fonction théoriquement possible, le mot de passe &amp;ldquo;password&amp;rdquo; sera cassé presque instantanément. Le guide ANSSI &amp;ldquo;Recommandations relatives à l&amp;rsquo;authentification multifacteur et aux mots de passe&amp;rdquo; indique qu&amp;rsquo;un mot de passe doit avoir une entropie allant de 65 bits à plus de 100 bits en fonction du niveau de risque associé au compte protégé par ce mot de passe. L&amp;rsquo;entropie est calculée avec le log_2 du nombre de combinaisons possibles d&amp;rsquo;un jeu de caractères sur une longueur donnée. Par exemple, si un mot de passe est uniquement numérique, et composé de 10 chiffres, alors l&amp;rsquo;entropie est de 10 puissance 10, et l&amp;rsquo;entropie est donc log_2(10^10), soit 33 bits.&lt;/p&gt;
&lt;p&gt;De même, si l&amp;rsquo;acteur utilise le même mot de passe auprès de plusieurs vérificateurs, alors la sécurité du stockage de ce mot de passe est équivalente à la sécurité de la méthode de stockage la plus faible employée par l&amp;rsquo;un de ces vérificateurs. Si cette méthode de stockage est trop faible, alors le mot de passe peut être recouvré puis utilisé auprès d&amp;rsquo;un vérificateur ayant pourtant une bonne méthode de stockage ; c&amp;rsquo;est ce qu&amp;rsquo;on appelle le &amp;ldquo;bourrage&amp;rdquo; de mots de passe. Dans ce cas, peu importe la fonction de dérivation employée : le mot de passe peut être cassé en une seule tentative, puisque le mot de passe est en fait déjà connu.&lt;/p&gt;
&lt;p&gt;Pour freiner la recherche exhaustive, il convient d&amp;rsquo;utiliser une fonction de dérivation qui soit raisonnablement couteuse à calculer. Plus la fonction est couteuse, plus il faudra de temps pour retrouver le mot de passe à partir de sa dérivée. Il y a cependant un arbitrage à faire, car pour chaque tentative de vérification d&amp;rsquo;un mot de passe, le vérificateur devra utiliser cette fonction couteuse également. S&amp;rsquo;il y a peu d&amp;rsquo;utilisateurs, comme c&amp;rsquo;est le cas pour une authentification locale sur un poste de travail, cela ne présente pas un gros problème, mais sur un site web avec des millions d&amp;rsquo;utilisateurs et d&amp;rsquo;utilisatrices, le cout peut rapidement devenir prohibitif.&lt;/p&gt;
&lt;p&gt;Le précalcul est une attaque qui vise à précalculer un grand nombre de dérivées de mots de passe, et d&amp;rsquo;indexer efficacement le résultat de ces calculs. Cet index permet d&amp;rsquo;optimiser le temps nécessaire pour casser les mots de passe dont les dérivées auraient fuité. Plus besoin d&amp;rsquo;exécuter la fonction de dérivation pour chaque mot de passe à attaquer ! Il suffit de regarder si la dérivée est présente dans l&amp;rsquo;index, et si oui de regarder quel mot de passe lui correspond. Ces index sont appelés des tables arc-en-ciel (&lt;em&gt;rainbow tables&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;Pour contrer le précalcul, une donnée aléatoire spécifique à chaque compte de chaque système d&amp;rsquo;information doit être ajoutée au mot de passe en entrée de la fonction de dérivation. Cette donnée est parfois appelée &amp;ldquo;sel&amp;rdquo; ou &amp;ldquo;diversificateur&amp;rdquo;. Plus cette donnée contient d&amp;rsquo;entropie, plus le cout du précalcul devient élevé. Le guide ANSSI &amp;ldquo;Recommandations relatives à l&amp;rsquo;authentification multifacteur et aux mots de passe&amp;rdquo; préconise une donnée d&amp;rsquo;au moins 128 bits d&amp;rsquo;entropie !&lt;/p&gt;
&lt;p&gt;Finalement, l&amp;rsquo;attaque par épluchage des mots de passe consiste à exploiter le fait que la fonction de dérivation soit en fait une composition de plusieurs fonctions de dérivation unitairement moins fortes que leur assemblage. L&amp;rsquo;exploitation consiste alors à attaquer chacune de ces fonctions individuellement ; si certaines sont trop faibles, alors l&amp;rsquo;attaquant peut accélérer d&amp;rsquo;autant sa recherche exhaustive. C&amp;rsquo;est par exemple ce qui a été reproché par la CNIL à Doctissimo, qui avait utilisé un assemblage MD5+bcrypt.&lt;/p&gt;
&lt;p&gt;La fonction de dérivation de mots de passe à l&amp;rsquo;état de l&amp;rsquo;art est argon2id. Cette fonction dérive les mots de passe de telle façon que les calculs ne puissent être faits sur des cartes graphiques. Cette propriété est importante, car les recherches exhaustives ont longtemps été faites sur des cartes graphiques, disposant de processeurs capables d&amp;rsquo;effectuer de très grandes quantités de certains types de calcul, bien supérieures aux processeurs généralistes. Ensuite, argon2id peut consommer de grandes quantités de mémoire lors de la dérivation des mots de passe, ce qui permet d&amp;rsquo;accroitre encore le cout d&amp;rsquo;une recherche exhaustive. Finalement, argon2id met en œuvre un certain nombre de précautions pour éviter des attaques par canaux auxiliaires rendus possibles à cause des techniques permettant de faire consommer plus de mémoire : une protection sur la protection, en somme !&lt;/p&gt;
&lt;p&gt;Il existe d&amp;rsquo;autres fonctions, moins efficaces que argon2id, qui peuvent être mentionnées. Par ordre décroissant de protection, il peut être cité : scrypt, bcrypt, PBKDF2. Toutes ces fonctions, comme argon2id, intègrent toutes par conception un diversificateur pour contrer les précalculs.&lt;/p&gt;
&lt;h2 id=&#34;de-la-réutilisation-des-moyens-de-prouver-son-identité&#34;&gt;De la réutilisation des moyens de prouver son identité&lt;/h2&gt;
&lt;p&gt;L&amp;rsquo;utilisation d&amp;rsquo;un même moyen permettant de prouver son identité n&amp;rsquo;est pas recommandée. Les conséquences sont cependant assez diverses en fonction du moyen.&lt;/p&gt;
&lt;p&gt;La réutilisation d&amp;rsquo;un moyen dans le cadre d&amp;rsquo;un mécanisme d&amp;rsquo;authentification par divulgation a des conséquences catastrophiques si le canal de communication ou la sécurité logicielle du prouveur et du vérificateur sont insuffisamment protégés en confidentialité. En effet, l&amp;rsquo;attaquant ou l&amp;rsquo;attaquante pourra alors apprendre le secret et le réutiliser en l&amp;rsquo;état auprès d&amp;rsquo;un autre vérificateur.&lt;/p&gt;
&lt;p&gt;La réutilisation de mots de passe pose également des difficultés relatives au stockage par le vérificateur. Le stockage du mot de passe lui-même, en clair ou sous un format réversible, signifie que l&amp;rsquo;attaquant ou l&amp;rsquo;attaquante ayant accès à ce stockage peut apprendre le mot de passe et le réutiliser tel quel auprès d&amp;rsquo;autres vérificateurs. Même si le stockage ne contient que des dérivées des mots de passe, le risque reste réel si l&amp;rsquo;entropie de ces mots de passe est trop faible. En effet, ils pourront être retrouvés par recherche exhaustive, avec les mêmes conséquences que s&amp;rsquo;ils avaient été stockés en clair.&lt;/p&gt;
&lt;p&gt;Avec les mécanismes d&amp;rsquo;authentification utilisant la signature électronique, l&amp;rsquo;utilisation d&amp;rsquo;une même clé privée auprès de plusieurs vérificateurs présente également des risques.&lt;/p&gt;
&lt;p&gt;D&amp;rsquo;une part, il arrive que des erreurs d&amp;rsquo;implémentation permettent à un vérificateur malveillant d&amp;rsquo;exploiter une vulnérabilité dans le code du prouveur, menant à la divulgation de la clé privée utilisée pour prouver son identité &lt;sup id=&#34;fnref:43&#34;&gt;&lt;a href=&#34;#fn:43&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;43&lt;/a&gt;&lt;/sup&gt;&lt;sup id=&#34;fnref:44&#34;&gt;&lt;a href=&#34;#fn:44&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;44&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;D&amp;rsquo;autre part, un attaquant ou une attaquante ayant pu obtenir la liste des clés publiques associées à des identités auprès de divers vérificateurs pourrait relier les identités entre elles. Il ou elle lui serait alors possible de tracer et corréler les activités sur les systèmes d&amp;rsquo;information accessibles après authentification auprès de ces vérificateurs&lt;sup id=&#34;fnref:45&#34;&gt;&lt;a href=&#34;#fn:45&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;45&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h2 id=&#34;considérations-de-sécurité-relatives-aux-moyens-de-prouver-son-identité&#34;&gt;Considérations de sécurité relatives aux moyens de prouver son identité&lt;/h2&gt;
&lt;p&gt;Fort de toutes les connaissances évoquées dans ce chapitre, il peut sembler difficile de faire le bon choix. Quelles normes, référentiels ou lois s&amp;rsquo;appliquent ? Quelle force ? Quel protocole ? Faut-il utiliser plusieurs facteurs ? Si oui, lesquels ? Quelles assurances le stockage du vérificateur doit-il fournir ? Quelles assurances le protocole de transport réseau doit-il fournir ? Faut-il utiliser des facteurs physiques comme des cartes à puce ? Si oui, à quel cout ? Qu&amp;rsquo;utiliser quand on accède à une API ?&lt;/p&gt;
&lt;p&gt;Pour ajouter à la complexité technique, il faut ajouter celles relatives aux humains. Quelle solution est la plus acceptable et réaliste ? Est-il réaliste de demander à un humain de mémoriser des mots de passe de plus de 12, voire 16 caractères, générés aléatoirement par une machine et sur 4 classes de caractères ? Que faire si un facteur est perdu ? Comment tenir compte des méthodes de hameçonnage et d&amp;rsquo;ingénierie sociale, et quel risque leur associer ?&lt;/p&gt;
&lt;p&gt;En 2024, les capacités de calcul sont telles que la plupart des humains sont incapables de mémoriser un mot de passe ou une phrase de passe résistant à une attaque par recherche exhaustive, en particulier si la méthode de stockage des dérivées des mots de passe côté vérificateur est insuffisante. Les mauvaises pratiques du milieu&lt;sup id=&#34;fnref:46&#34;&gt;&lt;a href=&#34;#fn:46&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;46&lt;/a&gt;&lt;/sup&gt; et la complexité d&amp;rsquo;analyse d&amp;rsquo;une adresse réticulaire (&lt;em&gt;Uniform Resource Locator (URL)&lt;/em&gt;) sont telles que même les spécialistes peinent à distinguer un lien légitime d&amp;rsquo;un lien redirigeant vers un site d’hameçonnage &lt;sup id=&#34;fnref:47&#34;&gt;&lt;a href=&#34;#fn:47&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;47&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Ces conclusions ont mené les industries sensibles à déconsidérer les facteurs d&amp;rsquo;authentification basés sur la connaissance (mots de passe, codes PIN, jetons d&amp;rsquo;authentification), nécessitant un stockage assurant la confidentialité (HTTP digest, etc.) et ceux qui sont vulnérables aux attaques par rejeu ou par relais (mécanisme de preuve par divulgation (dont les TOTP), codes TAN, clés privées réutilisées auprès de plusieurs vérificateurs&amp;hellip;). D&amp;rsquo;un autre côté, rares sont les organismes qui disposent du budget nécessaire pour fournir à tous leurs utilisateurs et utilisatrices des facteurs de possession tels que des cartes à puce, des clés USB implémentant U2F ou FIDO2, ou même des téléphones portables (Duo Push, Microsoft Authenticator). Ces moyens sont généralement réservés au public sensible, comme les équipes de sécurité et les équipes opérationnelles et d&amp;rsquo;administration.&lt;/p&gt;
&lt;p&gt;Pour ces raisons, des mécanismes d&amp;rsquo;authentification reposant sur le standard W3C WebAuthn&lt;sup id=&#34;fnref:48&#34;&gt;&lt;a href=&#34;#fn:48&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;48&lt;/a&gt;&lt;/sup&gt; et utilisant des stockages logiciels plutôt que physiques (&lt;em&gt;soft tokens&lt;/em&gt;) ont émergé, avec l&amp;rsquo;avènement des passkeys en 2023, principalement sous l&amp;rsquo;impulsion de Google, Apple et Microsoft.&lt;/p&gt;
&lt;p&gt;Les passkeys sont des clés utilisées dans le cadre du protocole WebAuthn. Ce protocole prévoit qu&amp;rsquo;une clé privée distincte soit utilisée par chaque vérificateur (&lt;em&gt;relying party&lt;/em&gt; dans la norme). Pour cela, WebAuthn utilise un identifiant unique (&lt;em&gt;Uniform Resource Identifier (URI)&lt;/em&gt;) pour distinguer les vérificateurs, le cas typique étant l&amp;rsquo;adresse réticulaire (URL) du site web demandant une authentification. Chacune de ces clés privées est stockée dans un coffre-fort auquel le prouveur pourra avoir accès sur demande. Pour éviter l&amp;rsquo;inconvénient de la perte, ce coffre-fort est généralement synchronisé dans le cloud ; c&amp;rsquo;est le cas, par exemple, pour les passkeys gérées par Apple (stockage dans iCloud) ou par Bitwarden (stockage dans le coffre-fort de mots de passe). L&amp;rsquo;utilisateur ou l&amp;rsquo;utilisatrice n&amp;rsquo;a alors qu&amp;rsquo;à s&amp;rsquo;authentifier auprès du service qui stocke ce coffre-fort pour récupérer l&amp;rsquo;ensemble de ses passkeys.&lt;/p&gt;
&lt;p&gt;Contrairement aux mots de passe qui pourraient être stockés dans ces mêmes coffres-forts, les passkeys sont par conception :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;un mécanisme d&amp;rsquo;authentification forte, employant des clés cryptographiques ;&lt;/li&gt;
&lt;li&gt;un mécanisme d&amp;rsquo;authentification multifacteur, puisqu&amp;rsquo;un ou plusieurs facteurs d&amp;rsquo;authentification sont nécessaires pour déverrouiller le coffre-fort contenant les passkeys ;&lt;/li&gt;
&lt;li&gt;unique à chaque vérificateur, sans réutilisation, ce qui les immunise aux attaques par relais&lt;sup id=&#34;fnref:49&#34;&gt;&lt;a href=&#34;#fn:49&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;49&lt;/a&gt;&lt;/sup&gt; et aux hameçonnages.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Contrairement aux facteurs de possession physiques, les passkeys sont par conception :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;immunisées à la perte ;&lt;/li&gt;
&lt;li&gt;peu onéreuses.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Enfin, les passkeys étant uniques à chaque vérificateur, elles offrent des propriétés intéressantes pour la vie privée. En effet, il n&amp;rsquo;existe aucun lien entre deux clés privées distinctes. Cela empêche donc plusieurs vérificateurs de se liguer en vue de tracer et corréler les activités d&amp;rsquo;un même utilisateur ou d&amp;rsquo;une même utilisatrice sur leurs systèmes d&amp;rsquo;information respectifs.&lt;/p&gt;
&lt;pre class=&#34;mermaid&#34;&gt;---
title: Authentification avec WebAuthn (simplifiée)
---
sequenceDiagram
  autonumber
  box Client
    actor p as Peggy
    participant cf as Coffre-fort
    participant b as Navigateur
  end
  box Serveur
    participant v as Victor
    participant db as Base de données
  end

  p -&gt;&gt; b:&#34;Je suis Peggy. Je veux accéder à https://broken-by-design.fr/&#34;
  b --&gt; v:&#34;Je suis Peggy. Je veux accéder à https://broken-by-design.fr/&#34;
  v -&gt;&gt; v:Tire un nonce
  v -&gt;&gt; b:&#34;Prouve le. Voici un nonce.&#34;
  p -&gt;&gt; cf:Déverrouille son coffre-fort, par exemple avec un mot de passe
  b -&gt;&gt; cf:&#34;Je visite https://broken-by-design.fr et voici le nonce&#34;
  cf -&gt;&gt; cf:Vérifie que Peggy a déverrouillé le coffre-fort il y a peu (*user verification*)
  cf -&gt;&gt; cf:Récupère la clé associée à https://broken-by-design.fr/
  cf -&gt;&gt; cf:Signe le nonce et le site visité
  cf -&gt;&gt; b:&#34;Voici la signature&#34;
  b -&gt;&gt; v:&#34;Voici la signature&#34;
  v -&gt;&gt; db:&#34;C&#39;est quoi la clé publique de Peggy ?&#34;
  db -&gt;&gt; v:&#34;Voici la clé publique de Peggy&#34;
  v -&gt;&gt; v: Vérifie la signature
  alt La signature est valide
    v -&gt;&gt; b:&#34;Bonjour Peggy!&#34;
    b -&gt;&gt; p:&#34;Bonjour Peggy!&#34;
  else La signature est invalide
    v -&gt;&gt; b: &#34;Je ne pense pas, non.&#34;
    b -&gt;&gt; p: &#34;Je ne pense pas, non.&#34;
  end
&lt;/pre&gt;

&lt;h1 id=&#34;autorisation&#34;&gt;Autorisation&lt;/h1&gt;
&lt;p&gt;L&amp;rsquo;autorisation est le fait d&amp;rsquo;&lt;strong&gt;accorder ou non&lt;/strong&gt;, à un &lt;strong&gt;sujet&lt;/strong&gt; (c&amp;rsquo;est-à-dire un acteur, une organisation, ou un groupe), à l&amp;rsquo;issue d&amp;rsquo;un contrôle d&amp;rsquo;accès, les droits, permissions ou privilèges, lui permettant d&amp;rsquo;effectuer une &lt;strong&gt;activité&lt;/strong&gt; sur un &lt;strong&gt;objet&lt;/strong&gt; ou une &lt;strong&gt;vue&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Derrière cette définition assez générique se cachent des réalités simples et intuitives, mais aussi des modèles de sécurité permettant l&amp;rsquo;application de politiques plus ou moins abstraites (modèles de Bell-Lapadula, Biba, Clark-Wilson, Multilevel Security (MLS)&amp;hellip;). Ce chapitre détaillera ces différents modèles.&lt;/p&gt;
&lt;h2 id=&#34;étiquetage-explicite-ou-intrinsèque&#34;&gt;Étiquetage explicite ou intrinsèque&lt;/h2&gt;
&lt;p&gt;Les sujets, actions et objets soumis à un système de contrôle d&amp;rsquo;accès ont besoin d&amp;rsquo;être identifiés de manière à pouvoir y faire référence lors de l&amp;rsquo;écriture de règles de contrôle d&amp;rsquo;accès.&lt;/p&gt;
&lt;p&gt;Pour les sujets, nous avons déjà discuté assez largement de la manière de les identifier dans ce cours.&lt;/p&gt;
&lt;p&gt;Pour ce qui est des objets, l&amp;rsquo;identification peut être effectuée de manière explicite, par l&amp;rsquo;ajout d&amp;rsquo;une étiquette (&lt;em&gt;label&lt;/em&gt;). Cette étiquette peut décrire une identité individuelle pour cet objet. Néanmoins, la plupart du temps, il s&amp;rsquo;agit plutôt d&amp;rsquo;une identité d&amp;rsquo;appartenance à un groupe. Par exemple, il pourrait s&amp;rsquo;agir d&amp;rsquo;une étiquette &amp;ldquo;objets correspondant à des données bancaires&amp;rdquo; ou &amp;ldquo;objets contenant des données personnelles&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;étiquetage s&amp;rsquo;effectue généralement par l&amp;rsquo;ajout d&amp;rsquo;une métadonnée associée à l&amp;rsquo;objet. Sous Linux, cela s&amp;rsquo;effectue le plus souvent avec les attributs étendus&lt;sup id=&#34;fnref:50&#34;&gt;&lt;a href=&#34;#fn:50&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;50&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;étiquetage est le système le plus répandu d&amp;rsquo;identification des objets, mais il est également possible d&amp;rsquo;identifier un objet de manière intrinsèque, par exemple en fonction de son nom ou de sa localisation. Ce système est notamment utilisé par le Linux Security Module (LSM) AppArmor qui définit des politiques de sécurité sur des fichiers en fonction de leur chemin d&amp;rsquo;accès dans le système de fichiers. Un autre exemple est le contrôle d&amp;rsquo;accès sur un site web, en fonction de la section &amp;ldquo;chemin&amp;rdquo; d&amp;rsquo;une adresse réticulaire (URL Path).&lt;/p&gt;
&lt;h2 id=&#34;contrôle-daccès-discrétionnaire-dac&#34;&gt;Contrôle d&amp;rsquo;accès discrétionnaire (DAC)&lt;/h2&gt;
&lt;p&gt;La plupart des personnes manipulant un ordinateur sont familières avec le contrôle d&amp;rsquo;accès discrétionnaire (DAC), même si la désignation leur est inconnue.&lt;/p&gt;
&lt;p&gt;Ce type de contrôle d&amp;rsquo;accès consiste à laisser la liberté au &lt;strong&gt;propriétaire&lt;/strong&gt; d&amp;rsquo;un &lt;strong&gt;objet&lt;/strong&gt; de déterminer les droits d&amp;rsquo;accès à ce dernier. C&amp;rsquo;est le modèle de contrôle d&amp;rsquo;accès par défaut sous Linux, avec les appels système &lt;code&gt;chown(2)&lt;/code&gt; et &lt;code&gt;chmod(2)&lt;/code&gt; qui permettent respectivement de changer le propriétaire d&amp;rsquo;un fichier et les droits (lecture, écriture, exécution) qui sont associés à l&amp;rsquo;utilisateur propriétaire, à un groupe d&amp;rsquo;utilisateurs, et aux autres utilisateurs.&lt;/p&gt;
&lt;p&gt;Ce contrôle d&amp;rsquo;accès est parfaitement adapté pour la gestion du contrôle d&amp;rsquo;accès à des données personnelles. Néanmoins, dans une entreprise, le contrat de travail contient quasi systématiquement une clause de cession des droits patrimoniaux de l&amp;rsquo;ensemble des productions du personnel. Pour le dire plus vulgairement, l&amp;rsquo;entreprise est la propriétaire des documents produits. Comme il n&amp;rsquo;est pas raisonnable d&amp;rsquo;attendre du chef ou de la cheffe d&amp;rsquo;entreprise de prendre toutes les décisions d&amp;rsquo;attribution des droits, des politiques de sécurité sont établies, qui s&amp;rsquo;appliquent ensuite de manière verticale sur l&amp;rsquo;ensemble des objets produits par le personnel de l&amp;rsquo;entreprise. L&amp;rsquo;étiquetage entre alors en jeu.&lt;/p&gt;
&lt;h2 id=&#34;contrôle-daccès-obligatoire-mac&#34;&gt;Contrôle d&amp;rsquo;accès obligatoire (MAC)&lt;/h2&gt;
&lt;p&gt;Le contrôle d&amp;rsquo;accès obligatoire (&lt;em&gt;Mandatory Access Control&lt;/em&gt;) a parfois été incorrectement appelé &amp;ldquo;contrôle d&amp;rsquo;accès mandataire&amp;rdquo; par les agents du gouvernement français, probablement pour des raisons de proximité phonétique avec &amp;ldquo;&lt;em&gt;mandatory&lt;/em&gt;&amp;rdquo;&amp;hellip;&lt;/p&gt;
&lt;p&gt;Ce type de contrôle d&amp;rsquo;accès consiste en l&amp;rsquo;établissement d&amp;rsquo;une politique de sécurité qui s&amp;rsquo;applique de manière verticale à l&amp;rsquo;ensemble des sujets, des actions et des objets d&amp;rsquo;un système d&amp;rsquo;information.&lt;/p&gt;
&lt;p&gt;Les politiques sont des descriptions abstraites des relations entre les sujets, les actions et les objets. Bien qu&amp;rsquo;elles puissent établir des règles à propos de sujets ou d&amp;rsquo;objets individuels spécifiques, elles portent plus généralement sur des étiquettes pouvant être associées à plusieurs sujets ou objets.&lt;/p&gt;
&lt;h3 id=&#34;les-modèles-théoriques&#34;&gt;Les modèles théoriques&lt;/h3&gt;
&lt;h4 id=&#34;les-modèles-de-mac-classiques&#34;&gt;Les modèles de MAC classiques&lt;/h4&gt;
&lt;p&gt;La littérature contient de nombreuses variantes et approches au contrôle d&amp;rsquo;accès obligatoire. Certaines sont assez intuitives, par exemple en attribuant des &lt;strong&gt;rôles&lt;/strong&gt; aux sujets (&lt;em&gt;Role-based Access Control&lt;/em&gt; (RBAC)). D&amp;rsquo;autres approches utilisent des &lt;strong&gt;attributs&lt;/strong&gt; arbitraires associés aux sujets, actions ou objets (&lt;em&gt;Attribute-based Access Control&lt;/em&gt; (ABAC)), ou encore des informations contextuelles à propos du sujet (&lt;em&gt;Context-based Access Control&lt;/em&gt; (CBAC)) : (heure d&amp;rsquo;accès, géolocalisation, capacités du terminal, force de l&amp;rsquo;authentification, etc&amp;hellip;).&lt;/p&gt;
&lt;h4 id=&#34;orbac&#34;&gt;OrBAC&lt;/h4&gt;
&lt;p&gt;Certaines approches au contrôle d&amp;rsquo;accès obligatoires rajoutent des couches d&amp;rsquo;abstraction supplémentaires, en bâtissant sur ceux déjà cités. Par exemple, le modèle de &lt;strong&gt;contrôle d&amp;rsquo;accès fondé sur l&amp;rsquo;organisation&lt;/strong&gt; (&lt;em&gt;Organization-based Access Control&lt;/em&gt; (OrBAC)) repose sur les approches par rôles (RBAC), par actions (&lt;em&gt;Task-based Access Control&lt;/em&gt; (TBAC)), par vues (&lt;em&gt;View-based Access Control&lt;/em&gt; (VBAC)) et par équipes (&lt;em&gt;Team-based Access Control&lt;/em&gt; (TBAC, à nouveau&amp;hellip;)). Le modèle OrBAC abstrait le triplet &amp;ldquo;sujets, action, objets&amp;rdquo; en un nouveau triplet &amp;ldquo;&lt;strong&gt;rôles&lt;/strong&gt;, &lt;strong&gt;activités&lt;/strong&gt;, &lt;strong&gt;vues&lt;/strong&gt;&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Des règles de contrôle d&amp;rsquo;accès peuvent alors être écrites concernant ce nouveau triplet en faisant abstraction du contexte d&amp;rsquo;implémentation, c&amp;rsquo;est-à-dire de l&amp;rsquo;organisation (société, association, etc.) pour laquelle elles sont écrites. Cela permet ainsi de les écrire une fois pour toutes, pour un nombre arbitraire d&amp;rsquo;organisations qui y auront recours.&lt;/p&gt;
&lt;p&gt;Une couche de &amp;ldquo;traduction&amp;rdquo; spécifique à chaque organisation doit alors être utilisée pour transposer ces règles abstraites en des règles pragmatiques concernant des acteurs, les actions et les objets de chaque organisation.&lt;/p&gt;
&lt;h4 id=&#34;sécurité-multiniveau&#34;&gt;Sécurité multiniveau&lt;/h4&gt;
&lt;p&gt;L&amp;rsquo;approche par sécurité multiniveau (&lt;em&gt;Multilevel Security&lt;/em&gt; (MLS)) est assez ancienne. Elle est particulièrement appréciée dans les domaines militaires et gouvernementaux, du fait de la verticalité intrinsèque de cette approche.
Néanmoins, cette approche a également ses mérites en dehors du domaine exécutif. Elle est, par exemple, intéressante pour la centralisation des données de santé (&lt;em&gt;monitoring&lt;/em&gt;) et de journalisation d&amp;rsquo;un système d&amp;rsquo;information.&lt;/p&gt;
&lt;p&gt;Le principe général de la sécurité multiniveau est, en effet, d&amp;rsquo;établir une hiérarchie de niveaux d&amp;rsquo;autorisation. Les acteurs associés à un niveau sont alors autorisés à effectuer un jeu d&amp;rsquo;actions restreint avec les objets associés aux niveaux situés en dessous du niveau de l&amp;rsquo;acteur. Un autre jeu d&amp;rsquo;actions, généralement distinct et disjoint, est également autorisé pour cet acteur avec les objets associés aux niveaux situés au-dessus du niveau de l&amp;rsquo;acteur.&lt;/p&gt;
&lt;p&gt;Parmi les modèles de sécurité reposant sur la sécurité multiniveau, on peut notamment citer le modèle de Bell-Lapadula&lt;sup id=&#34;fnref:51&#34;&gt;&lt;a href=&#34;#fn:51&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;51&lt;/a&gt;&lt;/sup&gt;, le modèle Biba&lt;sup id=&#34;fnref:52&#34;&gt;&lt;a href=&#34;#fn:52&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;52&lt;/a&gt;&lt;/sup&gt;, ou encore celui de Clark-Wilson&lt;sup id=&#34;fnref:53&#34;&gt;&lt;a href=&#34;#fn:53&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;53&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h5 id=&#34;le-modèle-bell-lapadula&#34;&gt;Le modèle Bell-Lapadula&lt;/h5&gt;
&lt;p&gt;Le modèle Bell-Lapadula utilise la sécurité multiniveau à des fins de confidentialité. Le principe général est qu&amp;rsquo;un acteur situé à un certain niveau de sécurité ne peut qu&amp;rsquo;écrire aux niveaux supérieurs et ne peut que lire aux niveaux inférieurs. En anglais, on parle d&amp;rsquo;une approche &amp;ldquo;&lt;em&gt;Write Up, Read Down&lt;/em&gt; (WURD)&amp;rdquo;. Avec cette approche, les acteurs de la hiérarchie peuvent concentrer les informations confidentielles, sans qu&amp;rsquo;aucune information notamment agrégée ne puisse redescendre.&lt;/p&gt;
&lt;p&gt;Ce modèle est implémenté dans Linux à l&amp;rsquo;aide de SElinux (&lt;em&gt;Security-Enhanced Linux&lt;/em&gt;), qui dispose d&amp;rsquo;une fonctionnalité multiniveau grâce aux étiquettes de niveaux de sensibilité.&lt;/p&gt;
&lt;h5 id=&#34;le-modèle-biba&#34;&gt;Le modèle Biba&lt;/h5&gt;
&lt;p&gt;Le modèle Biba utilise la sécurité multiniveau à des fins d&amp;rsquo;intégrité. Le principe général est comparable à celui de Bell-Lapadula, bien qu&amp;rsquo;il soit en quelque sorte inversé. Avec le modèle Biba, il n&amp;rsquo;y pas d&amp;rsquo;écriture aux niveaux supérieurs, et pas de lecture aux niveaux inférieurs. Ainsi, les niveaux les plus privilégiés sont protégés de toute interférence ou corruption de la part des niveaux inférieurs. En anglais, on parle d&amp;rsquo;une approche &amp;ldquo;&lt;em&gt;Read Up, Write Down&lt;/em&gt; (RUWD)&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Ce modèle peut être adroitement utilisé conjointement avec le modèle de Bell-Lapadula afin d&amp;rsquo;agréger des données confidentielles au niveau du commandement, et permettre ensuite au commandement de faire redescendre des ordres qui sont fonction de ces données agrégées.&lt;/p&gt;
&lt;h5 id=&#34;le-modèle-de-clark-wilson&#34;&gt;Le modèle de Clark-Wilson&lt;/h5&gt;
&lt;p&gt;Le modèle de Clark-Wilson s&amp;rsquo;intéresse également à l&amp;rsquo;intégrité. Son approche est plus dynamique et modélise le triplet &amp;ldquo;sujet,programme, objets&amp;rdquo;. Ce triplet signifie que les sujets ne peuvent manipuler les objets que par des programmes spécifiques. Ceci est plus restrictif que dans les autres modèles où le contrôle d&amp;rsquo;accès s&amp;rsquo;effectue en fonction de l&amp;rsquo;acteur, sans tenir compte de comment il y accède.&lt;/p&gt;
&lt;p&gt;Ce modèle est notamment implémentable sous Linux grâce aux politiques de contrôles des types (&lt;em&gt;type enforcement&lt;/em&gt; (TE)) de SElinux.
Le &lt;em&gt;type enforcement&lt;/em&gt; permet d&amp;rsquo;associer notamment à chaque utilisateur système ou rôle (ce qui est une autre notion de SElinux), à chaque programme exécutable, à chaque fichier, à chaque &lt;strong&gt;socket&lt;/strong&gt; un type. Une politique TE régit ensuite les interactions entre les types (écriture, lecture, exécution, modification des métadonnées, etc.), ainsi que les transitions entre les types : tel utilisateur de type W peut exécuter un programme de type X, ce qui lui permet de lire les fichiers de type Y et d&amp;rsquo;écrire les fichiers de type Z.&lt;/p&gt;
&lt;h4 id=&#34;modèle-de-brewer-et-nash-ou-de-la-muraille-de-chine&#34;&gt;Modèle de Brewer et Nash ou de la muraille de Chine&lt;/h4&gt;
&lt;p&gt;Le modèle de Brewer et Nash consiste à appliquer une politique de sécurité permettant de prévenir les conflits d&amp;rsquo;intérêts, notamment en matière commerciale. Dans ce modèle, le contrôle d&amp;rsquo;accès est dynamique ; par défaut l&amp;rsquo;acteur a virtuellement accès à toutes les données. Néanmoins, en fonction des données auxquelles il accède, il se voit au fur et à mesure restreindre l&amp;rsquo;accès à d&amp;rsquo;autres données. Par exemple, si les sociétés A et B sont concurrentes, accéder aux données de la société A fait que l&amp;rsquo;on perdra automatiquement les accès aux données de la société B.&lt;/p&gt;
&lt;p&gt;Un exemple d&amp;rsquo;implémentation de ce modèle est l&amp;rsquo;outil StemJail&lt;sup id=&#34;fnref:54&#34;&gt;&lt;a href=&#34;#fn:54&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;54&lt;/a&gt;&lt;/sup&gt; pour Linux, développé par Mickaël Salaün (ANSSI), avec Marion Daubignard (ANSSI) et sous la coulpe d&amp;rsquo;Hérvé Debar (SudParis Télécom), dans le cadre de la thèse de doctorat de Mickaël.&lt;/p&gt;
&lt;h3 id=&#34;des-rôles-et-des-groupes&#34;&gt;Des rôles et des groupes&lt;/h3&gt;
&lt;p&gt;Avec l&amp;rsquo;approche &lt;em&gt;Role-based Access Control&lt;/em&gt; (RBAC), des rôles sont attribués à des sujets. Comme vu précédemment dans ce cours, le terme de sujet recouvre plusieurs réalités : des acteurs mais aussi des groupes d&amp;rsquo;acteurs. Or, dans certaines définitions de ce que sont les rôles, il est retenu que les rôles sont des groupes d&amp;rsquo;acteurs et de permissions, tandis que d&amp;rsquo;autres définitions retiennent que les rôles sont des collections de permissions&lt;sup id=&#34;fnref:55&#34;&gt;&lt;a href=&#34;#fn:55&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;55&lt;/a&gt;&lt;/sup&gt;. Ainsi, certaines implémentations considérant que les rôles sont des groupes d&amp;rsquo;acteurs et de permissions n&amp;rsquo;implémentent pas du tout la notion de groupes d&amp;rsquo;acteurs (sans permissions), considérant celle-ci redondante avec celle des rôles. Pour rajouter un peu de confusion, certaines implémentations ne nomment pas les rôles &amp;ldquo;rôles&amp;rdquo; mais &amp;ldquo;groupes&amp;rdquo; (e.g. Gitlab) ou &amp;ldquo;équipes&amp;rdquo; (e.g. Gitea/Forgejo).&lt;/p&gt;
&lt;p&gt;D&amp;rsquo;une manière générale, il est fortement déconseillé d&amp;rsquo;attribuer des permissions à des acteurs de façon nominative, à moins qu&amp;rsquo;il ne soit possible de placer un commentaire explicite à côté de ces permissions accordées nominativement, afin de justifier leur attribution.&lt;/p&gt;
&lt;p&gt;Prenons l&amp;rsquo;exemple d&amp;rsquo;un personnel d&amp;rsquo;entreprise, inspiré d&amp;rsquo;un cas réel : au cours de sa vie professionnelle au sein de cette entreprise, ce personnel intègre une équipe de développement et obtient les permissions nécessaires à l&amp;rsquo;accomplissement de son affectation. Plus tard, ce même personnel réoriente sa carrière et devient ingénieur avant-vente, et se voit attribuer en conséquence de nouvelles permissions pour l&amp;rsquo;accomplissement de sa nouvelle affectation. Finalement, ce personnel bascule totalement dans l&amp;rsquo;équipe commerciale, et obtient encore de nouvelles permissions. Comme prévu dans la politique de sécurité de la société, les permissions sont auditées annuellement, afin de s&amp;rsquo;assurer que personne ne détient des permissions indues. Lorsque la personne en charge de l&amp;rsquo;audit vérifiera les permissions de ce personnel, il lui sera très difficile de s&amp;rsquo;assurer de la légitimité de chaque permission unitaire sans investigation. Si les permissions avaient été accordées en fonction de l&amp;rsquo;appartenance ou non à un groupe d&amp;rsquo;acteurs, il suffirait de contrôler la pertinence de l&amp;rsquo;appartenance aux groupes des développeurs, des avant-ventes et des commerciaux.&lt;/p&gt;
&lt;p&gt;En conséquence, même lorsque la notion de rôles est celle de groupes d&amp;rsquo;acteurs et de permissions, il est fortement conseillé de créer des rôles composés uniquement d&amp;rsquo;acteurs et de rôles composés exclusivement de permissions et de créer une hiérarchie entre ces rôles, de façon à ce que les rôles &amp;ldquo;groupes&amp;rdquo; héritent des permissions des rôles &amp;ldquo;permissions&amp;rdquo;.&lt;/p&gt;
&lt;h2 id=&#34;oauth2-openid-connect-et-assertions-de-sécurité&#34;&gt;OAuth2, OpenID Connect et assertions de sécurité&lt;/h2&gt;
&lt;p&gt;Les protocoles OAuth2 et OpenID Connect sont détaillés dans cette section en préparation du TP compagnon de ce cours. Il existe d&amp;rsquo;autres protocoles d&amp;rsquo;autorisation, comme Kerberos ou SAML, qui ne seront pas abordés dans ce cours, mais qui offrent des propriétés de sécurité intéressantes ou comparables.&lt;/p&gt;
&lt;h3 id=&#34;oauth2&#34;&gt;OAuth2&lt;/h3&gt;
&lt;p&gt;OAuth2 est un protocole standard d&amp;rsquo;autorisation, extensible, principalement utilisé dans le contexte web. Une partie de sa spécification, ce qui est appelé le &amp;ldquo;cadriciel OAuth2&amp;rdquo; (&lt;em&gt;framework&lt;/em&gt;), repose dans la RFC 6749&lt;sup id=&#34;fnref:56&#34;&gt;&lt;a href=&#34;#fn:56&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;56&lt;/a&gt;&lt;/sup&gt;. Cette RFC est également completée par les RFC 6750&lt;sup id=&#34;fnref:57&#34;&gt;&lt;a href=&#34;#fn:57&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;57&lt;/a&gt;&lt;/sup&gt; et 8252&lt;sup id=&#34;fnref:58&#34;&gt;&lt;a href=&#34;#fn:58&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;58&lt;/a&gt;&lt;/sup&gt;. Le principe général d&amp;rsquo;OAuth2 repose sur un protocole impliquant quatre participants :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;une personne propriétaire d&amp;rsquo;une ressource (en anglais &amp;ldquo;&lt;em&gt;resource owner&lt;/em&gt;&amp;rdquo;);&lt;/li&gt;
&lt;li&gt;un serveur de ressources (en anglais &amp;ldquo;&lt;em&gt;resource server&lt;/em&gt;&amp;rdquo;);&lt;/li&gt;
&lt;li&gt;une tierce partie souhaitant obtenir accès à cette ressource ; il s&amp;rsquo;agit généralement d&amp;rsquo;une application (en anglais &amp;ldquo;&lt;em&gt;client&lt;/em&gt;&amp;rdquo; ou &amp;ldquo;&lt;em&gt;relying party&lt;/em&gt;&amp;rdquo;);&lt;/li&gt;
&lt;li&gt;un serveur d&amp;rsquo;autorisation (en anglais &amp;ldquo;&lt;em&gt;authorization server&lt;/em&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&#34;mermaid&#34;&gt;---
title: Représentation simplifiée des interactions entre les parties du protocole OAuth2
---
sequenceDiagram
  autonumber
  actor p as Propriétaire
  actor a as Serveur d&#39;autorisation
  actor r as Serveur de ressources
  actor c as Client

  c -&gt;&gt; r:&#34;Je souhaite accéder à la ressource X.&#34;
  r -&gt;&gt; c:&#34;Il faut un jeton d&#39;accès. Va voir le serveur d&#39;autorisation.&#34;
  c -&gt;&gt; a:&#34;J&#39;aurais besoin d&#39;un jeton d&#39;accès pour la ressource X. Je redirige le propriétaire vers toi.&#34;
  a -&gt;&gt; p:&#34;T&#39;es qui ?&#34;
  p -&gt;&gt; a:&#34;Je suis Peggy, et en voici la preuve.&#34;
  a -&gt;&gt; a:Vérifie la preuve.
  a -&gt;&gt; p:&#34;OK, Peggy. J&#39;ai ce Client qui voudrait accéder à X dont tu es propriétaire. T&#39;en penses quoi ?&#34;
  p -&gt;&gt; a:&#34;OK pour donner accès à Client à la ressource X.&#34;
  a -&gt;&gt; c:&#34;OK, voici un jeton d&#39;accès pour X.&#34;
  c -&gt;&gt; r:&#34;Je souhaite accéder à la ressource X. Voici le jeton d&#39;accès.&#34;
  r -&gt;&gt; r:Vérifie le jeton d&#39;accès.
  alt Le jeton d&#39;accès est valide
    r -&gt;&gt; c:&#34;Voici la ressource X.&#34;
  else Le jeton d&#39;accès est invalide, forgé ou expiré
    r -&gt;&gt; c:&#34;Accès refusé.&#34;
  end
&lt;/pre&gt;

&lt;p&gt;Le serveur de ressources et le serveur d&amp;rsquo;autorisation ont établi une relation de confiance au préalable. Cette relation de confiance permet au serveur de ressources de reconnaitre et vérifier des jetons d&amp;rsquo;accès émis par le serveur d&amp;rsquo;autorisation.&lt;/p&gt;
&lt;p&gt;De même, la personne propriétaire d&amp;rsquo;une ressource a préalablement établi une relation de confiance avec le serveur d&amp;rsquo;autorisation ; elle est notamment capable de lui prouver son identité, d&amp;rsquo;une part, et de le convaincre qu&amp;rsquo;elle est propriétaire d&amp;rsquo;une certaine donnée, d&amp;rsquo;autre part.&lt;/p&gt;
&lt;p&gt;Finalement, la tierce partie et le serveur d&amp;rsquo;autorisation ont également préalablement établi une relation de confiance qui permet à la tierce partie de prouver son identité au serveur d&amp;rsquo;autorisation.&lt;/p&gt;
&lt;p&gt;Ainsi, lorsque la tierce partie manifeste le besoin d&amp;rsquo;accéder à la ressource, elle sollicite le serveur d&amp;rsquo;autorisation pour obtenir un jeton d&amp;rsquo;accès et s&amp;rsquo;authentifie auprès de lui. Après avoir vérifié l&amp;rsquo;identité de la personne propriétaire de la ressource, le serveur d&amp;rsquo;autorisation lui demande l&amp;rsquo;accord pour délivrer un jeton d&amp;rsquo;accès à cette ressource pour cette tierce partie spécifique. En cas d&amp;rsquo;accord, un jeton est délivré. La tierce partie peut alors contacter le serveur de ressources et présenter le jeton d&amp;rsquo;accès. Le serveur de ressources vérifie le jeton d&amp;rsquo;accès, et s&amp;rsquo;il est valide, donne accès à la ressource.&lt;/p&gt;
&lt;p&gt;Ce protocole permet de délivrer des autorisations d&amp;rsquo;accès à des ressources protégées, avec une granularité réglable, sans révéler à la tierce partie l&amp;rsquo;identité ou les moyens d&amp;rsquo;identification (les &amp;ldquo;authentifiants&amp;rdquo;) du propriétaire de la ressource. De surcroit, ce protocole permet de délivrer à la tierce partie des jetons d&amp;rsquo;accès à usage restreint : ils sont incessibles et potentiellement limités dans le temps.&lt;/p&gt;
&lt;p&gt;Une critique récurrente qui peut être adressée contre le cadriciel d&amp;rsquo;OAuth2 est la multitude de ces modes opératoires, certains étant par essence d&amp;rsquo;une sécurité relativement douteuse. C&amp;rsquo;est notamment le cas du mode implicite, ou lorsque sont utilisés des clients &amp;ldquo;publics&amp;rdquo;. Ce cours ne rentrera pas plus avant dans ces considérations, mais de plus amples informations peuvent être trouvées dans la RFC de référence, à la section &amp;ldquo;Considérations de sécurité&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Une utilisation &amp;ldquo;abusive&amp;rdquo; ou &amp;ldquo;détournée&amp;rdquo; du protocole d&amp;rsquo;OAuth2 est souvent constatée pour l&amp;rsquo;authentification décentralisée. Dans ce contexte d&amp;rsquo;usage, le serveur de ressources et le serveur d&amp;rsquo;autorisation sont la même entité. Lorsqu&amp;rsquo;une personne veut s&amp;rsquo;authentifier auprès d&amp;rsquo;une application tierce, elle demande à cette application de demander une autorisation d&amp;rsquo;accès au serveur d&amp;rsquo;autorisation. Le serveur d&amp;rsquo;autorisation demande à cette personne de s&amp;rsquo;authentifier, puis renvoie à la tierce partie un jeton d&amp;rsquo;accès pour une ressource quelconque contenant une information identifiant la personne qui s&amp;rsquo;est authentifiée. Si la tierce partie est en mesure d&amp;rsquo;obtenir cette ressource grâce au jeton d&amp;rsquo;accès, alors elle peut déduire que la personne a été capable de prouver son identité au serveur d&amp;rsquo;autorisation.&lt;/p&gt;
&lt;p&gt;Cette utilisation abusive a été normalisée par une extension au protocole OAuth2 : OpenID Connect.&lt;/p&gt;
&lt;h3 id=&#34;openid-connect&#34;&gt;OpenID Connect&lt;/h3&gt;
&lt;p&gt;OpenID Connect (OIDC)&lt;sup id=&#34;fnref:59&#34;&gt;&lt;a href=&#34;#fn:59&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;59&lt;/a&gt;&lt;/sup&gt; est une extension au protocole OAuth2. Elle rajoute notamment une couche d&amp;rsquo;identité, qui permet de normaliser la communication de l&amp;rsquo;identité d&amp;rsquo;une personne connue du serveur OIDC à la tierce partie (appelée en anglais &lt;em&gt;relying party&lt;/em&gt;), et de fournir également des informations complémentaires à son sujet. Ces informations sont appelées des assertions (&lt;em&gt;claims&lt;/em&gt;), qui peuvent être de nature arbitraire, tant qu&amp;rsquo;elles sont exprimables dans le format JWT (&lt;em&gt;JSON Web Token&lt;/em&gt;)&lt;sup id=&#34;fnref:60&#34;&gt;&lt;a href=&#34;#fn:60&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;60&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Le principe général d&amp;rsquo;OAuth 2 est appliqué avec OpenID Connect. La différence majeure est que le serveur d&amp;rsquo;autorisation est également le serveur de ressources, et que la ressource consultée est un document appelé &amp;ldquo;&lt;em&gt;ID Token&lt;/em&gt;&amp;rdquo;, contenant des assertions relatives à la personne s&amp;rsquo;étant authentifiée au serveur d&amp;rsquo;autorisation.&lt;/p&gt;
&lt;p&gt;Le document &lt;em&gt;ID Token&lt;/em&gt; contient diverses assertions requises ou optionnelles. Les assertions requises sont :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;iss&lt;/code&gt; : &amp;ldquo;issuer&amp;rdquo; : l&amp;rsquo;identifiant de l&amp;rsquo;émetteur de cet ID Token ;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sub&lt;/code&gt; : &amp;ldquo;subject&amp;rdquo; : l&amp;rsquo;identifiant de la personne cherchant à prouver son identité à la tierce partie ;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aud&lt;/code&gt; : &amp;ldquo;audience&amp;rdquo; : l&amp;rsquo;identifiant de la tierce partie ;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;exp&lt;/code&gt; : &amp;ldquo;expiry date&amp;rdquo; : la date d&amp;rsquo;expiration de cet ID Token ;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;iat&lt;/code&gt; : &amp;ldquo;issued at&amp;rdquo; : la date d&amp;rsquo;émission de cet ID Token.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Les assertions suivantes sont parfois requises, parfois optionnelles :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;auth_time&lt;/code&gt; : &amp;ldquo;authentication time&amp;rdquo; : heure de la dernière authentification réussie de la personne cherchant à prouver son identité à la tierce partie auprès du serveur OpenID Connect. Cette assertion est requise si l&amp;rsquo;application tierce a explicitement exprimé le besoin d&amp;rsquo;en connaitre à propos cette information.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nonce&lt;/code&gt; : une valeur arbitraire ajoutée à l&amp;rsquo;ID Token à la demande de la tierce application, en vue de contrer des attaques par rejeu éventuelles.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Les serveurs OpenID Connect peuvent être généralement configurés pour ajouter des assertions additionnelles arbitraires. Certaines peuvent ainsi spécifier les groupes auxquels appartient le sujet de l&amp;rsquo;ID Token ou les rôles dont il disposerait.&lt;/p&gt;
&lt;h3 id=&#34;user-managed-access&#34;&gt;User-managed Access&lt;/h3&gt;
&lt;p&gt;User-managed Access (UMA) est une autre extension au protocole OAuth2. Spécifiée par la Kantara Initiative&lt;sup id=&#34;fnref:61&#34;&gt;&lt;a href=&#34;#fn:61&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;61&lt;/a&gt;&lt;/sup&gt;, elle permet au propriétaire d&amp;rsquo;une ressource d&amp;rsquo;établir à l&amp;rsquo;avance des règles régissant l&amp;rsquo;émission de jetons d&amp;rsquo;accès à cette ressource.
L&amp;rsquo;application tierce sera alors autonome pour obtenir des jetons d&amp;rsquo;accès à cette ressource sous réserve de satisfaction des règles édictées par le propriétaire et sans interaction explicite avec ce dernier.&lt;/p&gt;
&lt;p&gt;Cette extension permet notamment la création d&amp;rsquo;un référentiel central d&amp;rsquo;autorisation, seule source de vérité des autorisations d&amp;rsquo;accès sur l&amp;rsquo;ensemble des ressources d&amp;rsquo;un système d&amp;rsquo;information.&lt;/p&gt;
&lt;p&gt;Hélas, s&amp;rsquo;il y a bon nombre de fournisseurs de service pour le protocole UMA, son adoption par les applications tierces est encore modeste.&lt;/p&gt;
&lt;h1 id=&#34;remerciements&#34;&gt;Remerciements&lt;/h1&gt;
&lt;p&gt;Je tiens à remercier mes relecteurs et relectrices pour leurs contributions à ce cours. Un merci tout spécial à &lt;a href=&#34;https://infosec.exchange/@karl&#34;&gt;@karl@infosec.exchange&lt;/a&gt; et &lt;a href=&#34;https://mastodon.gougere.fr/@bortzmeyer&#34;&gt;@bortzmeyer@mastodon.gougere.fr&lt;/a&gt; pour leurs suggestions d&amp;rsquo;amélioration nombreuses et détaillées.&lt;/p&gt;
&lt;p&gt;Le contenu de ce cours ne saurait les engager.&lt;/p&gt;
&lt;h1 id=&#34;licence&#34;&gt;Licence&lt;/h1&gt;
&lt;p&gt;Ce cours est publié sous licence &lt;a href=&#34;https://creativecommons.org/licenses/by/4.0/&#34;&gt;CC-BY&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Vous êtes autorisé à :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Partager — copier, distribuer et communiquer le matériel par tous moyens et sous tous formats pour toute utilisation, y compris commerciale.&lt;/li&gt;
&lt;li&gt;Adapter — remixer, transformer et créer à partir du matériel pour toute utilisation, y compris commerciale.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;L&amp;rsquo;Offrant ne peut retirer les autorisations concédées par la licence tant que vous appliquez les termes de cette licence.&lt;/p&gt;
&lt;p&gt;Selon les conditions suivantes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Attribution — Vous devez créditer l&amp;rsquo;Œuvre, intégrer un lien vers la licence et indiquer si des modifications ont été effectuées à l&amp;rsquo;Œuvre. Vous devez indiquer ces informations par tous les moyens raisonnables, sans toutefois suggérer que l&amp;rsquo;Offrant vous soutient ou soutient la façon dont vous avez utilisé son Œuvre.&lt;/li&gt;
&lt;li&gt;Pas de restrictions complémentaires — Vous n&amp;rsquo;êtes pas autorisé à appliquer des conditions légales ou des mesures techniques qui restreindraient légalement autrui à utiliser l&amp;rsquo;Œuvre dans les conditions décrites par la licence.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/linux-pam/linux-pam&#34;&gt;https://github.com/linux-pam/linux-pam&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.rfc-editor.org/rfc/rfc4511.html&#34;&gt;https://www.rfc-editor.org/rfc/rfc4511.html&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://learn.microsoft.com/fr-fr/windows-server/identity/ad-ds/plan/using-the-organizational-domain-forest-model&#34;&gt;https://learn.microsoft.com/fr-fr/windows-server/identity/ad-ds/plan/using-the-organizational-domain-forest-model&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Virtual_directory&#34;&gt;https://en.wikipedia.org/wiki/Virtual_directory&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:5&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://openid.net/developers/how-connect-works/&#34;&gt;https://openid.net/developers/how-connect-works/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:5&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:6&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://wiki.oasis-open.org/security/FrontPage&#34;&gt;https://wiki.oasis-open.org/security/FrontPage&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:6&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:7&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://cyber.gouv.fr/secnumcloud-pour-les-fournisseurs-de-services-cloud&#34;&gt;https://cyber.gouv.fr/secnumcloud-pour-les-fournisseurs-de-services-cloud&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:7&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref1:7&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:8&#34;&gt;
&lt;p&gt;version 3.2, chapitre 9.6, alinéa a&amp;#160;&lt;a href=&#34;#fnref:8&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:9&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.legifrance.gouv.fr/cnil/id/CNILTEXT000046693390&#34;&gt;https://www.legifrance.gouv.fr/cnil/id/CNILTEXT000046693390&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:9&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:10&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.legifrance.gouv.fr/cnil/id/CNILTEXT000042203965/&#34;&gt;https://www.legifrance.gouv.fr/cnil/id/CNILTEXT000042203965/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:10&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:11&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.legifrance.gouv.fr/cnil/id/CNILTEXT000047552103&#34;&gt;https://www.legifrance.gouv.fr/cnil/id/CNILTEXT000047552103&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:11&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:12&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://eur-lex.europa.eu/legal-content/FR/TXT/?uri=CELEX:32014R0910&#34;&gt;https://eur-lex.europa.eu/legal-content/FR/TXT/?uri=CELEX:32014R0910&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:12&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:13&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://eur-lex.europa.eu/legal-content/FR/TXT/?uri=celex%3A32015L2366&#34;&gt;https://eur-lex.europa.eu/legal-content/FR/TXT/?uri=celex%3A32015L2366&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:13&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:14&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.legifrance.gouv.fr/codes/article_lc/LEGIARTI000035430451&#34;&gt;https://www.legifrance.gouv.fr/codes/article_lc/LEGIARTI000035430451&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:14&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:15&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.legifrance.gouv.fr/codes/article_lc/LEGIARTI000035407334/&#34;&gt;https://www.legifrance.gouv.fr/codes/article_lc/LEGIARTI000035407334/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:15&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:16&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://ec.europa.eu/digital-building-blocks/sites/display/DIGITAL/eIDAS+eID+Profile&#34;&gt;https://ec.europa.eu/digital-building-blocks/sites/display/DIGITAL/eIDAS+eID+Profile&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:16&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:17&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://eur-lex.europa.eu/legal-content/FR/ALL/?uri=CELEX:32015R1502&#34;&gt;https://eur-lex.europa.eu/legal-content/FR/ALL/?uri=CELEX:32015R1502&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:17&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref1:17&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:18&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.legifrance.gouv.fr/jorf/id/JORFTEXT000035720606&#34;&gt;https://www.legifrance.gouv.fr/jorf/id/JORFTEXT000035720606&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:18&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:19&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://cyber.gouv.fr&#34;&gt;https://cyber.gouv.fr&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:19&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:20&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://cyber.gouv.fr/lidentification-electronique&#34;&gt;https://cyber.gouv.fr/lidentification-electronique&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:20&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:21&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://cyber.gouv.fr/le-referentiel-general-de-securite-version-20-les-documents&#34;&gt;https://cyber.gouv.fr/le-referentiel-general-de-securite-version-20-les-documents&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:21&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:22&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://cyber.gouv.fr/publications/recommandations-relatives-lauthentification-multifacteur-et-aux-mots-de-passe&#34;&gt;https://cyber.gouv.fr/publications/recommandations-relatives-lauthentification-multifacteur-et-aux-mots-de-passe&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:22&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:23&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.cloudflare.com/fr-fr/learning/bots/what-is-credential-stuffing/&#34;&gt;https://www.cloudflare.com/fr-fr/learning/bots/what-is-credential-stuffing/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:23&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:24&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://jankrissler.blogspot.com/2016/09/hacker-fakes-german-ministers.html&#34;&gt;https://jankrissler.blogspot.com/2016/09/hacker-fakes-german-ministers.html&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:24&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:25&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Trusted_Platform_Module&#34;&gt;https://en.wikipedia.org/wiki/Trusted_Platform_Module&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:25&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:26&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Hardware_security_module&#34;&gt;https://en.wikipedia.org/wiki/Hardware_security_module&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:26&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:27&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.lemagit.fr/conseil/Key-Management-System-KMS-une-pierre-angulaire-du-chiffrement&#34;&gt;https://www.lemagit.fr/conseil/Key-Management-System-KMS-une-pierre-angulaire-du-chiffrement&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:27&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:28&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://heartbleed.com/&#34;&gt;https://heartbleed.com/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:28&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:29&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.rfc-editor.org/rfc/rfc7616.html&#34;&gt;https://www.rfc-editor.org/rfc/rfc7616.html&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:29&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref1:29&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:30&#34;&gt;
&lt;p&gt;Une des propriétés de sécurité attendues des fonctions de hachage cryptographiques est qu&amp;rsquo;il soit virtuellement impossible de déterminer, autrement que par la recherche exhaustive, une valeur qui, passée à la fonction de hachage en entrée, produirait un résultat connu.&amp;#160;&lt;a href=&#34;#fnref:30&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:31&#34;&gt;
&lt;p&gt;Le serveur peut également stocker une dérivée du mot de passe, mais pour ce protocole, cette dérivée de mot de passe a la même sensibilité que le mot de passe lui-même : le connaitre est suffisant pour s&amp;rsquo;authentifier.&amp;#160;&lt;a href=&#34;#fnref:31&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:32&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://fr.wikipedia.org/wiki/Preuve_%C3%A0_divulgation_nulle_de_connaissance#La_grotte_d&#39;Ali_Baba&#34;&gt;https://fr.wikipedia.org/wiki/Preuve_%C3%A0_divulgation_nulle_de_connaissance#La_grotte_d&#39;Ali_Baba&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:32&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:33&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://fr.wikipedia.org/wiki/Protocole_d%27authentification_de_Schnorr&#34;&gt;https://fr.wikipedia.org/wiki/Protocole_d%27authentification_de_Schnorr&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:33&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:34&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://fr.wikipedia.org/wiki/Guillou-Quisquater&#34;&gt;https://fr.wikipedia.org/wiki/Guillou-Quisquater&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:34&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:35&#34;&gt;
&lt;p&gt;Les protocoles à divulgation nulle de connaissance sont des protocoles probabilistes. Le vérificateur ne dispose jamais d&amp;rsquo;une preuve formelle de l&amp;rsquo;identité ; il acquiert juste une conviction reposant sur une probabilité écrasante que le prouveur connait ou possède le secret prouvant son identité. Le seuil de probabilité à partir duquel il est convaincu est paramétrable et à la discrétion du vérificateur.&amp;#160;&lt;a href=&#34;#fnref:35&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:36&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.rfc-editor.org/rfc/rfc9497.html&#34;&gt;https://www.rfc-editor.org/rfc/rfc9497.html&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:36&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:37&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://datatracker.ietf.org/wg/privacypass/documents/&#34;&gt;https://datatracker.ietf.org/wg/privacypass/documents/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:37&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:38&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://eprint.iacr.org/2018/163.pdf&#34;&gt;https://eprint.iacr.org/2018/163.pdf&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:38&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:39&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.whatsapp.com/security/WhatsApp_Security_Encrypted_Backups_Whitepaper.pdf&#34;&gt;https://www.whatsapp.com/security/WhatsApp_Security_Encrypted_Backups_Whitepaper.pdf&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:39&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:40&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.rfc-editor.org/rfc/rfc6238.html&#34;&gt;https://www.rfc-editor.org/rfc/rfc6238.html&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:40&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:41&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.cloudflare.com/fr-fr/learning/bots/what-is-credential-stuffing/&#34;&gt;https://www.cloudflare.com/fr-fr/learning/bots/what-is-credential-stuffing/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:41&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:42&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.scottbrady91.com/authentication/beware-of-password-shucking&#34;&gt;https://www.scottbrady91.com/authentication/beware-of-password-shucking&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:42&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:43&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-0777&#34;&gt;https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-0777&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:43&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:44&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-31497&#34;&gt;https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-31497&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:44&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:45&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://words.filippo.io/dispatches/whoami-updated/&#34;&gt;https://words.filippo.io/dispatches/whoami-updated/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:45&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:46&#34;&gt;
&lt;p&gt;Il semble très difficile d&amp;rsquo;astreindre les départements marketing et communications à utiliser uniquement des noms de domaine bien identifiés, que les utilisateurs et utilisatrices finaux sont habitués à reconnaitre&amp;hellip;&amp;#160;&lt;a href=&#34;#fnref:46&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:47&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/orangetw/My-Presentation-Slides/blob/main/data/2019-A-New-Era-Of-SSRF-Exploiting-URL-Parser-In-Trending-Programming-Languages.pdfs&#34;&gt;https://github.com/orangetw/My-Presentation-Slides/blob/main/data/2019-A-New-Era-Of-SSRF-Exploiting-URL-Parser-In-Trending-Programming-Languages.pdfs&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:47&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:48&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.w3.org/groups/wg/webauthn/publications/&#34;&gt;https://www.w3.org/groups/wg/webauthn/publications/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:48&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:49&#34;&gt;
&lt;p&gt;Le standard WebAuthn requiert la vérification de l&amp;rsquo;identité du vérificateur. Cette vérification est généralement faite à l&amp;rsquo;aide de TLS et de l&amp;rsquo;infrastructure de gestion de clés &amp;ldquo;web&amp;rdquo;. Si un attaquant réussit à disposer de la clé privée associée à un certificat légitime pour un vérificateur donné, alors il sera en mesure d&amp;rsquo;effectuer tout de même des attaques relais. WebAuthn dispose d&amp;rsquo;une mécanique appelée &amp;ldquo;&lt;em&gt;channel binding&lt;/em&gt;&amp;rdquo; ou &amp;ldquo;&lt;em&gt;token binding&lt;/em&gt;&amp;rdquo; permettant de prévenir totalement les attaques par relais, mais cette fonctionnalité n&amp;rsquo;a jamais été implémentée à large échelle.&amp;#160;&lt;a href=&#34;#fnref:49&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:50&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://man7.org/linux/man-pages/man7/xattr.7.html&#34;&gt;https://man7.org/linux/man-pages/man7/xattr.7.html&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:50&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:51&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://websites.umich.edu/~cja/LPS12b/refs/belllapadula1.pdf&#34;&gt;https://websites.umich.edu/~cja/LPS12b/refs/belllapadula1.pdf&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:51&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:52&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.researchgate.net/publication/235043659_Integrity_Considerations_for_Secure_Computer_Systems&#34;&gt;https://www.researchgate.net/publication/235043659_Integrity_Considerations_for_Secure_Computer_Systems&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:52&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:53&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://groups.csail.mit.edu/ana/Publications/PubPDFs/A%20Comparison%20of%20Commercial%20and%20Military%20Computer%20Security%20Policies.pdf&#34;&gt;https://groups.csail.mit.edu/ana/Publications/PubPDFs/A%20Comparison%20of%20Commercial%20and%20Military%20Computer%20Security%20Policies.pdf&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:53&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:54&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://stemjail.github.io/&#34;&gt;https://stemjail.github.io/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:54&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:55&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://profsandhu.com/workshop/role-group.pdf&#34;&gt;https://profsandhu.com/workshop/role-group.pdf&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:55&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:56&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.rfc-editor.org/rfc/rfc6749.html&#34;&gt;https://www.rfc-editor.org/rfc/rfc6749.html&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:56&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:57&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.rfc-editor.org/rfc/rfc6750.html&#34;&gt;https://www.rfc-editor.org/rfc/rfc6750.html&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:57&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:58&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.rfc-editor.org/rfc/rfc8252.html&#34;&gt;https://www.rfc-editor.org/rfc/rfc8252.html&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:58&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:59&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://openid.net/developers/specs/&#34;&gt;https://openid.net/developers/specs/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:59&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:60&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.rfc-editor.org/rfc/rfc7519.html&#34;&gt;https://www.rfc-editor.org/rfc/rfc7519.html&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:60&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:61&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://docs.kantarainitiative.org/uma/wg/rec-oauth-uma-grant-2.0.html&#34;&gt;https://docs.kantarainitiative.org/uma/wg/rec-oauth-uma-grant-2.0.html&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:61&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
		</item>
		<item>
			<title>Identité et méthodes d&#39;authentification : TP</title>
			<link>https://broken-by-design.fr/posts/cours-id-authn-tp/</link>
			<pubDate>Mon, 26 Feb 2024 00:00:00 +0200</pubDate>
			<guid isPermaLink="true">https://broken-by-design.fr/posts/cours-id-authn-tp/</guid>
			<description>&lt;h1 id=&#34;tp&#34;&gt;TP&lt;/h1&gt;
&lt;p&gt;Ce TP consiste à mettre en place un référentiel d&amp;rsquo;identités et un service qui
utilisera ce référentiel pour effectuer l&amp;rsquo;authentification décentralisée de ces
utilisateurs et utilisatrices. Ce service sera la forge logicielle Forgejo et
le référentiel d&amp;rsquo;identités sera Keycloak.&lt;/p&gt;
&lt;p&gt;Le référentiel d&amp;rsquo;identités sera configuré pour permettre l&amp;rsquo;authentification
sans mot de passe, à l&amp;rsquo;aide de WebAuthn et de passkeys.&lt;/p&gt;
&lt;p&gt;Pour stocker et gérer les passkeys, nous aurons recours à Bitwarden et son
extension navigateur d&amp;rsquo;une part et à un serveur Vaultwarden d&amp;rsquo;autre part.
Vaultwarden est un serveur libre compatible avec l&amp;rsquo;API de Bitwarden. Il nous
permet d&amp;rsquo;effectuer ce TP sans &amp;ldquo;polluer&amp;rdquo; les serveurs Bitwarden officiels avec
des comptes créés pour ce TP.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;authentification avec WebAuthn nécessite que les sites soient servis sur
HTTPS. Pour cette raison, nous allons mettre en place un serveur HTTPS qui
tiendra lieu de serveur mandataire inverse (&lt;em&gt;reverse proxy&lt;/em&gt;).&lt;/p&gt;
&lt;h1 id=&#34;ajouter-une-adresse-ip-dédiée-au-tp&#34;&gt;Ajouter une adresse IP dédiée au TP&lt;/h1&gt;

&lt;details&gt;
  &lt;summary&gt;(Action) Ajouter une adresse IP locale dédiée pour le TP. Bloquer le cas échéant les connexions depuis le réseau externe.&lt;/summary&gt;
  &lt;p&gt;Sur Linux, ajouter une interface de type dummy et configurer une adresse IP
dédiée pour le TP. Par exemple, 10.108.0.1.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo ip l a dummy0 type dummy
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo ip a a 10.108.0.1 dev dummy0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo ip l s dummy0 up
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Sur Windows et Mac, trouver une manière de faire&amp;hellip;&lt;/p&gt;
&lt;/details&gt;

&lt;h1 id=&#34;installation-du-serveur-mandataire-inverse&#34;&gt;Installation du serveur mandataire inverse&lt;/h1&gt;
&lt;p&gt;Avant toute chose, il convient de configurer le serveur mandataire, et de
configurer notre navigateur internet afin qu&amp;rsquo;il fasse confiance aux certificats
émis par ce serveur mandataire. Pour ce faire, nous allons utiliser Caddy.&lt;/p&gt;
&lt;p&gt;Caddy est un serveur qui peut à la fois jouer le rôle de serveur HTTP, mais
aussi assurer la gestion d&amp;rsquo;une infrastructure de gestions de clés (IGC), et
même délivrer des certificats à l&amp;rsquo;aide du protocole ACME&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Le conteneur Caddy a besoin d&amp;rsquo;exposer le port 443. Il stocke ses fichiers
relatifs à l&amp;rsquo;IGC dans un volume qui doit être monté sur le chemin /data.
Finalement, sa configuration est effectuée avec un fichier &amp;ldquo;Caddyfile&amp;rdquo;, situé
au chemin /etc/caddy/Caddyfile.&lt;/p&gt;
&lt;p&gt;La syntaxe des Caddyfile est documentée sur le site officiel de
Caddy&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Pour le moment, nous allons simplement le déclarer et le démarrer pour obtenir
le certificat racine de l&amp;rsquo;infrastructure de gestion de clés.&lt;/p&gt;
&lt;p&gt;(Action) Créer un répertoire &lt;code&gt;caddy&lt;/code&gt; dans votre répertoire de travail pour ce
TP.&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;(Action) Écrire un fichier de configuration &lt;code&gt;Caddyfile&lt;/code&gt; minimaliste et le stocker dans &lt;code&gt;caddy/Caddyfile&lt;/code&gt;.&lt;/summary&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    http_port 80   # écoute sur le port 80
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    https_port 443  # écoute sur le port 443
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    admin off  # désactivation de l&amp;#39;API qui n&amp;#39;est pas utilisée dans ce TP
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    log {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        output stdout  # journalisation sur stdout afin de le récupérer par le driver de log de l&amp;#39;engine
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        format console  # journalisation au format console pour faciliter la lisibilité des logs (pas recommandé en production)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        level info  # journalisation de niveau info, pour avoir des informations, mais pas trop
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    local_certs  # tous les certificats sont émis par l&amp;#39;IGC interne, au lieu d&amp;#39;aller les chercher sur Internet
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    skip_install_trust  # n&amp;#39;effectue pas une étape inutile quand on fait tourner Caddy dans un conteneur
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Étendre l&amp;rsquo;image officielle de Caddy pour ajouter ce fichier de configuration. Pour cela, créer le fichier &lt;code&gt;Containerfile&lt;/code&gt; (ou &lt;code&gt;Dockerfile&lt;/code&gt;) suivant, et le stocker dans le répertoire &lt;code&gt;caddy&lt;/code&gt;.&lt;/summary&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;FROM docker.io/caddy:2.10.0-alpine
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;COPY Caddyfile /etc/caddy
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Créer un fichier &lt;code&gt;podman-compose.yml&lt;/code&gt; ou &lt;code&gt;docker-compose.yml&lt;/code&gt; qui inclura les différentes définitions fournies ultérieurement&lt;/summary&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;version: &amp;#39;3.7&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Déclarer dans le fichier compose un conteneur caddy&lt;/summary&gt;
  &lt;p&gt;Le réseau &lt;code&gt;caddy_frontend&lt;/code&gt; est le réseau public sur lequel seront exposés les
ports 80 et 443. Le réseau &lt;code&gt;caddy_backend&lt;/code&gt; est le réseau privé sur lequel
seront connectés les différents services rendus disponibles par Caddy.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;volumes:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  caddy_data:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    driver: local
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;networks:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  caddy_frontend:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    name: caddy_frontend
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    internal: false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  caddy_backend:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    name: caddy_backend
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    internal: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;services:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  caddy:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    build: caddy/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    container_name: caddy
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    restart: always
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ports:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      - 8080:80
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      - 8443:443
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    volumes:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      - caddy_data:/data
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    networks:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      - caddy_frontend
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      - caddy_backend
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Démarrer le conteneur&lt;/summary&gt;
  &lt;p&gt;Depuis un shell, taper :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;podman compose -f podman-compose.yml up -d
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker compose -f docker-compose.yml up -d
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Récupérer le certificat racine&lt;/summary&gt;
  &lt;p&gt;Depuis un shell, taper :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;podman cp caddy:/data/caddy/pki/authorities/local/root.crt caddy.crt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker cp caddy:/data/caddy/pki/authorities/local/root.crt caddy.crt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Insérer le certificat racine dans le magasin de certificat de son navigateur.&lt;/summary&gt;
  &lt;p&gt;Avec Firefox, cela peut se faire de manière programmatique, avec l&amp;rsquo;utilitaire
certtool. Cet utilitaire peut être installé avec le paquet &amp;ldquo;libnss3-tool&amp;rdquo; sur
Debian/Ubuntu, et le paquet &amp;ldquo;nss-tools&amp;rdquo; sur Fedora.&lt;/p&gt;
&lt;p&gt;Ensuite, exécuter la commande suivante dans un shell :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;find $HOME -type f -name &amp;#34;cert9.db&amp;#34; | while read filename ; do certutil -A -n &amp;#34;CA TP&amp;#34; -t &amp;#34;TC&amp;#34; -i $PWD/caddy.crt -d &amp;#34;$(dirname &amp;#34;$filename&amp;#34;)&amp;#34; ; done
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;

&lt;h1 id=&#34;installation-de-vaultwarden&#34;&gt;Installation de Vaultwarden&lt;/h1&gt;
&lt;p&gt;Vaultwarden est un serveur compatible avec l&amp;rsquo;API Bitwarden. Il permet le
stockage de mots de passe et de passkeys.&lt;/p&gt;
&lt;p&gt;Il va être installé sous la forme d&amp;rsquo;un conteneur.&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;(Action) Ajouter le nom de domaine vault.tp-authn.broken-by-design.fr dans le fichier hosts, et le faire pointer vers 10.108.0.1&lt;/summary&gt;
  &lt;p&gt;Sur Linux et Mac, éditer le fichier /etc/hosts. Sur Windows, éditer le fichier
C:\Windows\system32\drivers\etc\hosts.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;10.108.0.1 vault.tp-authn.broken-by-design.fr
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Ajouter dans le fichier compose la déclaration des ressources pour un serveur Vaultwarden&lt;/summary&gt;
  &lt;p&gt;Dans la section volumes, ajouter :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  vault_data:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    driver: local
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Dans la section services, ajouter :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  vault:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    image: ghcr.io/dani-garcia/vaultwarden:1.33.2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    container_name: vault
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    restart: always
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    volumes:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      - vault_data:/data
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    networks:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      - caddy_backend
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    environment:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      SIGNUPS_ALLOWED: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      SIGNUPS_DOMAINS_WHITELIST: tp-authn.broken-by-design.fr
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      INVITATIONS_ALLOWED: false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      DOMAIN: https://vault.tp-authn.broken-by-design.fr:8443
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      SHOW_PASSWORD_HINT: false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    depends_on:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      - caddy
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Ajouter l&amp;rsquo;hôte virtuel pour Vaultwarden dans la configuration de Caddy&lt;/summary&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;vault.tp-authn.broken-by-design.fr:80 {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  redir vault.tp-authn.broken-by-design.fr:8443{uri}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  log
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;vault.tp-authn.broken-by-design.fr:443 {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  reverse_proxy vault:80
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  log
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Détruire, reconstruire et recréer les conteneurs&lt;/summary&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;podman compose -f podman-compose.yml down
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;podman compose -f podman-compose.yml build
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;podman compose -f podman-compose.yml up -d
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker compose -f docker-compose.yml down
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker compose -f docker-compose.yml build
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker compose -f docker-compose.yml up -d
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;

&lt;p&gt;(Action) Ouvrir dans son navigateur
&lt;a href=&#34;https://vault.tp-authn.broken-by-design.fr:8443/&#34;&gt;https://vault.tp-authn.broken-by-design.fr:8443/&lt;/a&gt; et se créer un compte&lt;/p&gt;
&lt;p&gt;(Action) Installer l&amp;rsquo;extension navigateur Bitwarden&lt;/p&gt;
&lt;p&gt;(Action) Se connecter à son compte Vaultwarden dans l&amp;rsquo;extension Bitwarden.
Penser à sélectionner &amp;ldquo;Connexion sur auto-hébergé&amp;rdquo; et renseigner l&amp;rsquo;URL du
serveur &amp;ldquo;&lt;a href=&#34;https://vault.tp-authn.broken-by-design.fr:8443/%22&#34;&gt;https://vault.tp-authn.broken-by-design.fr:8443/&amp;quot;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;installation-de-la-forge-logicielle&#34;&gt;Installation de la forge logicielle&lt;/h1&gt;
&lt;p&gt;La forge logicielle est installée avec un conteneur. Ce conteneur dispose d&amp;rsquo;un
volume /data pour le stockage de la configuration et des données des
utilisateurs et utilisatrices.&lt;/p&gt;
&lt;p&gt;Nous utiliserons une base de données sqlite3 pour stocker les données. En
production, il est recommandé d&amp;rsquo;utiliser un gestionnaire de base de données
plus robuste, comme Postgresql ou MariaDB.&lt;/p&gt;
&lt;p&gt;Nous avons d&amp;rsquo;abord besoin de déclarer le nom de domaine qui sera utilisé
pendant ce TP pour joindre la forge.&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;(Action) Ajouter le nom de domaine git.tp-authn.broken-by-design.fr dans le fichier hosts, et le faire pointer vers 10.108.0.1&lt;/summary&gt;
  &lt;p&gt;Sur Linux et Mac, éditer le fichier /etc/hosts. Sur Windows, éditer le fichier
C:\Windows\system32\drivers\etc\hosts.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;10.108.0.1 git.tp-authn.broken-by-design.fr
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;

&lt;p&gt;Plus tard dans le TP, nous aurons besoin que Forgejo contacte le référentiel
d&amp;rsquo;identités. Comme ce dernier sera rendu accessible par Caddy, il nous faut
ajouter le certificat racine de Caddy à la liste des certificats de confiance
du conteneur Forgejo. Il faut également que le conteneur forgejo ait accès à un
réseau public.&lt;/p&gt;
&lt;p&gt;(Action) Créer un répertoire &lt;code&gt;forgejo&lt;/code&gt; à la racine du répertoire pour ce TP.&lt;/p&gt;
&lt;p&gt;(Action) Copier dans le répertoire forgejo le certificat racine de Caddy.&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;(Action) Créer un fichier &lt;code&gt;Containerfile&lt;/code&gt; ou &lt;code&gt;Dockerfile&lt;/code&gt; qui étend l&amp;rsquo;image officielle de Forgejo pour y ajouter le certificat de Caddy&lt;/summary&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;FROM codeberg.org/forgejo/forgejo:11
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;COPY caddy.crt /usr/local/share/ca-certificates/caddyca.crt
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;RUN update-ca-certificates
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Déclarer la forge logicielle dans le fichier compose&lt;/summary&gt;
  &lt;p&gt;Dans la section &lt;code&gt;volumes&lt;/code&gt; du fichier compose, ajouter :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  forgejo_data:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    driver: local
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Dans la section &lt;code&gt;networks&lt;/code&gt; du fichier compose, ajouter :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  forgejo_public:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    name: forgejo_public
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    internal: false
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Dans la section &lt;code&gt;services&lt;/code&gt; du fichier composer, ajouter :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  forgejo:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    build: forgejo/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    container_name: forgejo
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    restart: always
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    networks:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      - forgejo_public
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      - caddy_backend
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    volumes:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      forgejo_data:/data
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    environment:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      USER_UID: 1000
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      USER_GID: 1000
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      FORGEJO__server__DOMAIN: git.tp-authn.broken-by-design.fr
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      FORGEJO__server__ROOT_URL: &amp;#39;https://%(DOMAIN)s:8443/&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      FORGEJO__server__DISABLE_SSH: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      FORGEJO__database__DB_TYPE: sqlite3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      FORGEJO__admin__DEFAULT_EMAIL_NOTIFICATIONS: disabled
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      # La ligne suivante est OK car nous utilisons un réseau &amp;#34;interne&amp;#34; et dédié
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      FORGEJO__security__REVERSE_PROXY_TRUSTED_PROXIES: &amp;#39;*&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      FORGEJO__security__PASSWORD_HASH_ALGO: argon2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      FORGEJO__security__MIN_PASSWORD_LENGTH: 12
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      FORGEJO__security__PASSWORD_COMPLEXITY: lower,upper,digit,spec
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      FORGEJO__security__PASSWORD_CHECK_PWN: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    depends_on:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      - caddy
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Ajouter l&amp;rsquo;hôte virtuel pour forgejo dans Caddy à la fin du fichier caddy/Caddyfile&lt;/summary&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git.tp-authn.broken-by-design.fr:80 {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  redir https://git.tp-authn.broken-by-design.fr:8433{uri}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  log
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git.tp-authn.broken-by-design.fr:443 {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  reverse_proxy forgejo:3000
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  log
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Détruire, reconstruire et recréer les conteneurs&lt;/summary&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;podman compose -f podman-compose.yml down
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;podman compose -f podman-compose.yml build
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;podman compose -f podman-compose.yml up -d
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker compose -f docker-compose.yml down
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker compose -f docker-compose.yml build
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker compose -f docker-compose.yml up -d
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;

&lt;p&gt;(Action) Ouvrir &lt;a href=&#34;https://git.tp-authn.broken-by-design.fr:8443/&#34;&gt;https://git.tp-authn.broken-by-design.fr:8443/&lt;/a&gt; dans son
navigateur&lt;/p&gt;
&lt;p&gt;(Action) Terminer la procédure d&amp;rsquo;installation de Forgejo en configurant un
utilisateur administrateur et son mot de passe.&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;(Action) Ajouter une passkey pour le compte Administrateur du Forgejo&lt;/summary&gt;
  &lt;p&gt;Pour ajouter la passkey, aller dans la &amp;ldquo;Configuration&amp;rdquo; du compte Administrateur
de Forgejo, dans l&amp;rsquo;onglet &amp;ldquo;Sécurité&amp;rdquo;. Ensuite, dans la section &amp;ldquo;Clés de
sécurité&amp;rdquo;, taper le nom &amp;ldquo;Bitwarden&amp;rdquo; et cliquer sur Ajouter une clé de sécurité.
Dans la popup Bitwarden, sélectionner &amp;ldquo;Enregistrer la clé d&amp;rsquo;accès&amp;rdquo;.&lt;/p&gt;
&lt;/details&gt;

&lt;p&gt;(Action) Se déconnecter, et se reconnecter au compte administrateur, et
utiliser la passkey comme second facteur d&amp;rsquo;authentification.&lt;/p&gt;
&lt;h1 id=&#34;installation-dun-serveur-postgres-pour-le-référentiel-didentités&#34;&gt;Installation d&amp;rsquo;un serveur Postgres pour le référentiel d&amp;rsquo;identités&lt;/h1&gt;
&lt;p&gt;Keycloak utilise une base de données pour stocker les identités entre autres
informations.&lt;/p&gt;
&lt;p&gt;Nous allons donc installer un serveur Postgres sous la forme d&amp;rsquo;un conteneur, et
créer un réseau sur lequel Keycloak pourra le joindre.&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;(Action) Ajouter un serveur Postgres au fichier compose&lt;/summary&gt;
  &lt;p&gt;Dans la section &lt;code&gt;volumes&lt;/code&gt;, ajouter :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  psql_data:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    driver: local
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Dans la section &lt;code&gt;networks&lt;/code&gt;, ajouter :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  psql_backend:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    name: psql_backend
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    internal: true
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Dans la section &lt;code&gt;services&lt;/code&gt;, ajouter :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;psql&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;docker&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;io&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;postgres&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;17.5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;alpine&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;container_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;psql&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;restart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;always&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;volumes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;psql_data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lib&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;postgresql&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;networks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;psql_backend&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;environment&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;n&#34;&gt;PGDATA&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lib&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;postgresql&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pgdata&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;n&#34;&gt;POSTGRES_DB&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;keycloak&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;n&#34;&gt;POSTGRES_USER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;keycloak&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;n&#34;&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;keycloak&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Lancer le conteneur Postgres&lt;/summary&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;podman compose -f podman-compose.yml up psql
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ou&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker compose -f docker-compose.yml up psql
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;

&lt;h1 id=&#34;installation-du-référentiel-didentité&#34;&gt;Installation du référentiel d&amp;rsquo;identité&lt;/h1&gt;
&lt;p&gt;Le conteneur Keycloak est fourni sous la forme d&amp;rsquo;une image &amp;ldquo;non optimisée&amp;rdquo; et
qui ne sait pas se servir de Postgresql comme base de données par défaut. Il
est nécessaire &amp;ldquo;d&amp;rsquo;optimiser&amp;rdquo; l&amp;rsquo;image. En outre, Keycloak va avoir besoin de
parler avec Forgejo ; il lui faut donc ajouter le certificat racine dans sa
base de confiance. Contrairement à Forgejo, Keycloak n&amp;rsquo;utilise pas la base
système et utilise à la place un keystore propre à Java.&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;(Action) Ajouter l&amp;rsquo;hôte &lt;code&gt;idp.tp-authn.broken-by-design.fr&lt;/code&gt; dans le fichier hosts&lt;/summary&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;10.108.0.1 idp.tp-authn.broken-by-design.fr
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Ajouter l&amp;rsquo;hôte virtuel dans Caddy pour Keycloak&lt;/summary&gt;
  &lt;p&gt;À la fin du fichier caddy/Caddyfile, ajouter :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;idp.tp-authn.broken-by-design.fr:80 {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  redir https://idp.tp-authn.broken-by-design.fr:8433{uri}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  log
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;idp.tp-authn.broken-by-design.fr:443 {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  reverse_proxy keycloak:8080
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  log
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;

&lt;p&gt;(Action) Créer un répertoire &lt;code&gt;keycloak&lt;/code&gt; à la racine du répertoire du TP&lt;/p&gt;
&lt;p&gt;(Action) Copier dans le répertoire &lt;code&gt;keycloak&lt;/code&gt; le certificat de l&amp;rsquo;autorité de certification racine généré par Caddy&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;(Action) Créer un &lt;code&gt;Containerfile&lt;/code&gt; (ou &lt;code&gt;Dockerfile&lt;/code&gt;) dans le répertoire &lt;code&gt;keycloak&lt;/code&gt; pour optimiser keycloak pour Postgresql&lt;/summary&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;FROM&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;quay&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;io&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;keycloak&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;keycloak&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;latest&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;ENV&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;KC_DB&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;postgres&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;COPY&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;chmod&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0644&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;caddy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;crt&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;opt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;keycloak&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;conf&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;caddy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;crt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;RUN&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;keytool&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;trustcacerts&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;keystore&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;opt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;keycloak&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;conf&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;truststores&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cacerts&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;jks&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;noprompt&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;storepass&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;useless&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;opt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;keycloak&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;conf&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;caddy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;crt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;WORKDIR&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;opt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;keycloak&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;RUN&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;opt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;keycloak&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bin&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sh&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;build&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;FROM&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;quay&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;io&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;keycloak&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;keycloak&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;latest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;COPY&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;builder&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;opt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;keycloak&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;opt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;keycloak&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Ajouter un conteneur keycloak dans le fichier compose&lt;/summary&gt;
  &lt;p&gt;Dans la section &lt;code&gt;networks&lt;/code&gt;, ajouter :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  keycloak_public:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    name: keycloak_public
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    internal: false
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Dans la section &lt;code&gt;services&lt;/code&gt;, ajouter :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  keycloak:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    build: keycloak/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    container_name: keycloak
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    restart: always
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    networks:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      - keycloak_public
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      - caddy_backend
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      - psql_backend
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    command: start
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    environment:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      JAVA_OPTS: -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.err.encoding=UTF-8 -Dstdout.encoding=UTF-8 -Dstderr.encoding=UTF-8 -XX:+ExitOnOutOfMemoryError -Djava.security.egd=file:/dev/urandom -XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -XX:FlightRecorderOptions=stackdepth=512 -Xms64m -Xmx512m -Djavax.net.ssl.trustStore=/opt/keycloak/conf/truststores/cacerts.jks -Djavax.net.ssl.trustStorePassword=useless
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      KC_PROXY_HEADERS: xforwarded
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      KC_HTTP_ENABLED: &amp;#34;true&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      KC_DB: postgres
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      KC_DB_URL: jdbc:postgresql://psql/keycloak
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      KC_DB_USER: keycloak
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      KC_DB_PASSWORD: keycloak
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      KC_HOSTNAME: https://idp.tp-authn.broken-by-design.fr:8443/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      KEYCLOAK_ADMIN: admin
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      KEYCLOAK_ADMIN_PASSWORD: Bonjour1!tititoto
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    depends_on:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      - caddy
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      - psql
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Détruire, reconstruire et relancer les conteneurs&lt;/summary&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;podman compose -f podman-compose.yml down
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;podman compose -f podman-compose.yml build
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;podman compose -f podman-compose.yml up -d
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker compose -f docker-compose.yml down
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker compose -f docker-compose.yml build
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker compose -f docker-compose.yml up -d
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;

&lt;h1 id=&#34;configuration-du-référentiel-didentités&#34;&gt;Configuration du référentiel d&amp;rsquo;identités&lt;/h1&gt;
&lt;p&gt;Dans cette section, nous allons configurer Keycloak afin qu&amp;rsquo;il dispose d&amp;rsquo;un
domaine (&amp;quot;&lt;em&gt;realm&lt;/em&gt;&amp;rdquo;) dédié au réseau d&amp;rsquo;exploitation (par opposition au réseau et
au domaine d&amp;rsquo;administration). Dans ce domaine, nous allons créer un
utilisateur. Nous allons également déclarer un &amp;ldquo;client&amp;rdquo; OpenID Connect pour
Forgejo. Cette configuration client permettra à Forgejo de demander des
informations à Keycloak concernant les utilisateurs.&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;(Action) Se connecter sur &lt;a href=&#34;https://idp.tp-authn.broken-by-design.fr:8443/&#34;&gt;https://idp.tp-authn.broken-by-design.fr:8443/&lt;/a&gt;&lt;/summary&gt;
  &lt;p&gt;Utiliser le compte &amp;ldquo;admin&amp;rdquo; et le mot de passe &amp;ldquo;Bonjour1!tititoto&amp;rdquo;&lt;/p&gt;
&lt;/details&gt;

&lt;p&gt;(Action) Créer un nouveau domaine (&lt;em&gt;realm&lt;/em&gt;) nommé &amp;ldquo;TP&amp;rdquo; pour les comptes utilisateurs et utilisatrices d&amp;rsquo;exploitation&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;(Action) Collecter les informations pour l&amp;rsquo;ajout d&amp;rsquo;un nouveau client dans Forgejo.&lt;/summary&gt;
  &lt;p&gt;Pour cela, se connecter au compte administrateur, sélectionner &amp;ldquo;Administration
du site&amp;rdquo;, puis dans &amp;ldquo;Identité et accès&amp;rdquo;, sélectionner &amp;ldquo;Sources
d&amp;rsquo;authentification&amp;rdquo;. Ajouter une source d&amp;rsquo;authentification. Sélectionner le
type &amp;ldquo;OAuth2&amp;rdquo; et le fournisseur OAuth2 appelé &amp;ldquo;OpenID Connect&amp;rdquo;. Après avoir
saisir le nom de l&amp;rsquo;authentification &amp;ldquo;keycloak&amp;rdquo;, récupérer l&amp;rsquo;adresse conseillée
pour l&amp;rsquo;URL de rappel/redirection
(&lt;code&gt;https://git.tp-authn.broken-by-design.fr:8443/user/oauth2/keycloak/callback&lt;/code&gt;).&lt;/p&gt;
&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Sur Keycloak, créer un nouveau client OpenID Connect &lt;code&gt;forgejo&lt;/code&gt; dans le domaine &amp;amp;quote;TP&amp;amp;quote;.&lt;/summary&gt;
  &lt;p&gt;Dans le domaine &amp;ldquo;TP&amp;rdquo;, aller dans le menu &amp;ldquo;Clients&amp;rdquo;, et cliquer sur &amp;ldquo;Create
client&amp;rdquo;. Appeler le client &lt;code&gt;forgejo&lt;/code&gt;. Cliquer sur &amp;ldquo;Next&amp;rdquo;, puis sélectionner
uniquement le flux d&amp;rsquo;authentification &lt;code&gt;standard&lt;/code&gt;. Activer également
l&amp;rsquo;authentification du client, puis cliquer sur &amp;ldquo;Next&amp;rdquo;. Indiquer l&amp;rsquo;URL racine
&lt;code&gt;https://git.tp-authn.broken-by-design.fr:8443/&lt;/code&gt;, l&amp;rsquo;URL de rappel valide
&lt;code&gt;https://git.tp-authn.broken-by-design.fr:8443/user/oauth2/keycloak/callback&lt;/code&gt;.
Finalement, cliquer sur &amp;ldquo;Save&amp;rdquo;.&lt;/p&gt;
&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Récupérer le secret pour le client Forgejo.&lt;/summary&gt;
  &lt;p&gt;Se rendre dans l&amp;rsquo;onglet &amp;ldquo;Credentials&amp;rdquo; du client &lt;code&gt;forgejo&lt;/code&gt; et copier le &lt;code&gt;client secret&lt;/code&gt;.&lt;/p&gt;
&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Configurer Forgejo pour utiliser Keycloak&lt;/summary&gt;
  &lt;p&gt;Une fois &amp;ldquo;ajouter une source d&amp;rsquo;authentification&amp;rdquo; sélectionné, choisir le type
&amp;ldquo;OAuth2&amp;rdquo;, et le fournisseur &amp;ldquo;OpenID Connect&amp;rdquo;. Indiquer le nom de fournisseur
&lt;code&gt;keycloak&lt;/code&gt;, l&amp;rsquo;ID du client &lt;code&gt;forgejo&lt;/code&gt;, et le secret du client copié depuis
Keycloak. Indiquer également l&amp;rsquo;URL de découverte
&lt;code&gt;https://idp.tp-authn.broken-by-design.fr:8443/realms/TP/.well-known/openid-configuration&lt;/code&gt;.
Ajouter la source d&amp;rsquo;authentification.&lt;/p&gt;
&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Ajouter un utilisateur administrateur forgejo &lt;code&gt;admin&lt;/code&gt; dans le domaine TP&lt;/summary&gt;
  &lt;p&gt;Dans &amp;ldquo;Users&amp;rdquo;, sélectionner &amp;ldquo;Create new user&amp;rdquo;. Nommer l&amp;rsquo;utilisateur &lt;code&gt;admin&lt;/code&gt; et
créer l&amp;rsquo;utilisateur. Dans l&amp;rsquo;onglet &amp;ldquo;Credentials&amp;rdquo;, sélectionner &amp;ldquo;Set Password&amp;rdquo;
et définir un mot de passe pour l&amp;rsquo;utilisateur &lt;code&gt;admin&lt;/code&gt;. Utiliser
Bitwarden/Vaultwarden pour suggérer un bon mot de passe, et le sauvegarder.&lt;/p&gt;
&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Associer l&amp;rsquo;utilisateur administrateur de Forgejo à l&amp;rsquo;identité &lt;code&gt;admin&lt;/code&gt; du realm TP de Keycloak.&lt;/summary&gt;
  &lt;p&gt;Dans Forgejo, aller dans &amp;ldquo;Configuration&amp;rdquo; du profil utilisateur. Dans l&amp;rsquo;onglet
&amp;ldquo;Sécurité&amp;rdquo;, dans la section &amp;ldquo;Gérer les comptes liés&amp;rdquo;, sélectionner &amp;ldquo;Lier un
compte&amp;rdquo;, et sélectionner &amp;ldquo;keycloak&amp;rdquo; dans la liste déroulante qui est apparue.
S&amp;rsquo;authentifier au compte admin du realm TP. Compléter les champs demandés.&lt;/p&gt;
&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Tester l&amp;rsquo;authentification avec Keycloak sur Forgejo.&lt;/summary&gt;
  &lt;p&gt;Se déconnecter du compte administrateur de Forgejo. Se reconnecter, en cliquant
sur &amp;ldquo;Se connecter avec Keycloak&amp;rdquo;.&lt;/p&gt;
&lt;/details&gt;

&lt;h1 id=&#34;gérer-les-groupes-et-les-rôles-de-façon-centralisée&#34;&gt;Gérer les groupes et les rôles de façon centralisée&lt;/h1&gt;
&lt;p&gt;Dans cette partie du TP, nous allons créer des rôles et des groupes et les
assigner à nos utilisateurs &lt;code&gt;admin&lt;/code&gt; et un nouvel utilisateur &lt;code&gt;jean.dupont&lt;/code&gt;. Ces
droits seront ajoutés dans Keycloak et dans Forgejo. Ensuite nous configurerons
Forgejo pour qu&amp;rsquo;il utilise les informations récupérées grâce OpenID Connect
pour ajouter l&amp;rsquo;utilisateur &lt;code&gt;jean.dupont&lt;/code&gt; dans les bons groupes gérés par
Forgejo.&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;(Action) Créer dans Forgejo une organisation &amp;amp;quote;TP&amp;amp;quote;&lt;/summary&gt;
  &lt;p&gt;Cliquer sur le &amp;ldquo;+&amp;rdquo; en haut à droite, puis sélectionner &amp;ldquo;Nouvelle Organisation&amp;rdquo;.
Appeler l&amp;rsquo;organisation &amp;ldquo;TP&amp;rdquo; et cliquer sur &amp;ldquo;Créer une organisation&amp;rdquo;.&lt;/p&gt;
&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Créer dans l&amp;rsquo;organisation Forgejo &amp;amp;quote;TP&amp;amp;quote;, une équipe &lt;code&gt;mainteneurs&lt;/code&gt;, avec des droits en écriture.&lt;/summary&gt;
  &lt;p&gt;Une fois sur la page de l&amp;rsquo;organisation &amp;ldquo;TP&amp;rdquo;, sélectionner &amp;ldquo;Nouvelle équipe&amp;rdquo;.
Nommer l&amp;rsquo;équipe &lt;code&gt;mainteneurs&lt;/code&gt;, et sélectionner le niveau de privilège
&amp;ldquo;Ecriture&amp;rdquo; pour l&amp;rsquo;ensemble des actions possibles.&lt;/p&gt;
&lt;/details&gt;

&lt;p&gt;(Action) Créer dans l&amp;rsquo;organisation Forgejo &amp;ldquo;TP&amp;rdquo;, une équipe &lt;code&gt;contributeurs&lt;/code&gt;, avec des droits en lecture.&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;(Action) Ajouter au domaine TP de Keycloak des rôles &lt;code&gt;mainteneur&lt;/code&gt; et &lt;code&gt;contributeurs&lt;/code&gt;.&lt;/summary&gt;
  &lt;p&gt;Dans le domaine TP, sélectionner le menu &amp;ldquo;Realm Roles&amp;rdquo;, puis &amp;ldquo;Create role&amp;rdquo;.
Nommer les rôles et cliquer sur &amp;ldquo;Save&amp;rdquo;.&lt;/p&gt;
&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Ajouter au domaine TP de Keycloak des groupes &lt;code&gt;Mainteneurs du TP&lt;/code&gt; et &lt;code&gt;Contributeurs du TP&lt;/code&gt;.&lt;/summary&gt;
  &lt;p&gt;Dans le domaine TP, aller dans le menu &amp;ldquo;Groups&amp;rdquo;, puis cliquer sur &amp;ldquo;Create
Group&amp;rdquo;. Nommer le groupe, puis cliquer sur &amp;ldquo;Create&amp;rdquo;. Renouveller l&amp;rsquo;opération
pour le second groupe.&lt;/p&gt;
&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Assigner le rôle &lt;code&gt;mainteneur&lt;/code&gt; aux membres du groupe &lt;code&gt;Mainteneurs du TP&lt;/code&gt; et le rôle &lt;code&gt;contributeur&lt;/code&gt; aux membres du groupe &lt;code&gt;Contributeurs du TP&lt;/code&gt;.&lt;/summary&gt;
  &lt;p&gt;Pour cela, dans le domaine TP, dans le menu &amp;ldquo;Groups&amp;rdquo;, cliquer sur un groupe,
puis aller dans l&amp;rsquo;onglet &amp;ldquo;Role Mapping&amp;rdquo;, et cliquer sur &amp;ldquo;Assign Role&amp;rdquo;.
Sélectionner le rôle approprié, puis cliquer sur &amp;ldquo;Assign&amp;rdquo;. Renouveler
l&amp;rsquo;opération pour le second groupe.&lt;/p&gt;
&lt;/details&gt;

&lt;p&gt;(Action) Dans Keycloak, ajouter un utilisateur &lt;code&gt;jean.dupont&lt;/code&gt; et lui définir un
mot de passe avec Vaultwarden.&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;(Action) Ajouter &lt;code&gt;jean.dupont&lt;/code&gt; au groupe &lt;code&gt;Mainteneurs du TP&lt;/code&gt;.&lt;/summary&gt;
  &lt;p&gt;Pour cela, dans le domaine TP, dans le menu &amp;ldquo;Groups&amp;rdquo;, cliquer sur le groupe
&lt;code&gt;Mainteneurs du TP&lt;/code&gt;, puis aller dans l&amp;rsquo;onglet &amp;ldquo;Members&amp;rdquo;. Cliquer sur &amp;ldquo;Add
Member&amp;rdquo;, cocher l&amp;rsquo;utilisateur &lt;code&gt;jean.dupont&lt;/code&gt;, puis cliquer sur &amp;ldquo;Add&amp;rdquo;.&lt;/p&gt;
&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Configurer l&amp;rsquo;exposition des rôles au client &lt;code&gt;forgejo&lt;/code&gt;, afin de ne divulguer que la possession des rôles &lt;code&gt;mainteneur&lt;/code&gt; et &lt;code&gt;contributeur&lt;/code&gt; à ce client, sous une entrée &lt;code&gt;forgejo-roles&lt;/code&gt;.&lt;/summary&gt;
  &lt;p&gt;Dans le menu &amp;ldquo;Clients&amp;rdquo;, cliquer sur le client &lt;code&gt;forgejo&lt;/code&gt;. Ensuite, dans l&amp;rsquo;onglet
&amp;ldquo;Client Scopes&amp;rdquo;, cliquer sur l&amp;rsquo;entrée &lt;code&gt;forgejo-dedicated&lt;/code&gt;. Cliquer sur le
bouton &amp;ldquo;Add predefined mappers&amp;rdquo;. Cocher &amp;ldquo;realm roles&amp;rdquo;, puis cliquer sur &amp;ldquo;Add&amp;rdquo;.
Cliquer ensuite sur l&amp;rsquo;entrée &amp;ldquo;realm roles&amp;rdquo;, et remplacer la valeur dans &amp;ldquo;Token
Claim Name&amp;rdquo; par &lt;code&gt;forgejo-roles&lt;/code&gt;. Cocher également &amp;ldquo;Add to userinfo&amp;rdquo; et &amp;ldquo;Add to
ID Token&amp;rdquo;, puis cliquer sur &amp;ldquo;Save&amp;rdquo;. Ensuite, revenir sur la fenêtre
&amp;ldquo;forgejo-dedicated&amp;rdquo;, puis se rendre dans l&amp;rsquo;onglet &amp;ldquo;Scope&amp;rdquo;. Désactiver &amp;ldquo;Full
scope allowed&amp;rdquo;, puis cliquer que &amp;ldquo;Assign Role&amp;rdquo;, cocher les deux rôles
&lt;code&gt;mainteneur&lt;/code&gt; et &lt;code&gt;contributeur&lt;/code&gt; et cliquer sur &amp;ldquo;Assign&amp;rdquo;.&lt;/p&gt;
&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Configurer Forgejo pour tenir compte des rôles fournis par Keycloak.&lt;/summary&gt;
  &lt;p&gt;Dans &amp;ldquo;Administration du site&amp;rdquo;, dans le menu &amp;ldquo;Identités et accès&amp;rdquo;, puis &amp;ldquo;Sources
d&amp;rsquo;authentification&amp;rdquo;, cliquer sur &amp;ldquo;Editer&amp;rdquo; pour le fournisseur &amp;ldquo;keycloak&amp;rdquo;. Dans
le champ &amp;ldquo;Associe les groupes réclamés avec les équipes de l&amp;rsquo;organisation.
(Optionnel, nécessite un nom de réclamation)&amp;rdquo;, saisir le document JSON suivant
:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;{&amp;#34;mainteneur&amp;#34;: {&amp;#34;TP&amp;#34;: [&amp;#34;mainteneurs&amp;#34;]}, &amp;#34;contributeur&amp;#34;: {&amp;#34;TP&amp;#34;: [&amp;#34;contributeurs&amp;#34;]}}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Saisir également &lt;code&gt;forgejo-roles&lt;/code&gt; dans le champ &amp;ldquo;Réclamer le nom fournissant les
noms de groupe pour cette source. (facultatif)&amp;rdquo;, puis cliquer sur &amp;ldquo;Mettre à
jour la source d&amp;rsquo;authentification&amp;rdquo;.&lt;/p&gt;
&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Configurer Forgejo pour qu&amp;rsquo;il retire les membres des équipes lors de la synchronisation avec Keycloak&lt;/summary&gt;
  &lt;p&gt;Dans &amp;ldquo;Administration du site&amp;rdquo;, dans le menu &amp;ldquo;Identités et accès&amp;rdquo;, puis &amp;ldquo;Sources
d&amp;rsquo;authentification&amp;rdquo;, cliquer sur &amp;ldquo;Editer&amp;rdquo; pour le fournisseur &amp;ldquo;keycloak&amp;rdquo;.
Cocher la case &amp;ldquo;Supprimer les utilisateurs des équipes synchronisées si
l&amp;rsquo;utilisateur n&amp;rsquo;appartient pas au groupe correspondant&amp;rdquo;, puis cliquer sur
&amp;ldquo;Mettre à jour la source d&amp;rsquo;authentification&amp;rdquo;.&lt;/p&gt;
&lt;/details&gt;

&lt;p&gt;(Action) Constater qu&amp;rsquo;il n&amp;rsquo;y a aucun membre dans l&amp;rsquo;équipe &lt;code&gt;mainteneurs&lt;/code&gt; sur
Forgejo.&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;(Action) Se déconnecter de l&amp;rsquo;utilisateur &lt;code&gt;admin&lt;/code&gt; du realm TP.&lt;/summary&gt;
  &lt;p&gt;Se rendre à l&amp;rsquo;adresse
&lt;code&gt;https://idp.tp-authn.broken-by-design.fr:8443/realms/TP/account/&lt;/code&gt; et se
déconnecter.&lt;/p&gt;
&lt;/details&gt;

&lt;p&gt;(Action) Se connecter en tant que &lt;code&gt;jean.dupont&lt;/code&gt; sur Forgejo, en se connectant
avec Keycloak. Valider la création d&amp;rsquo;un nouveau compte. Constater que
l&amp;rsquo;utilisateur appartient à l&amp;rsquo;équipe &lt;code&gt;mainteneurs&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;(Action, Optionnel) Dans Keycloak, retirer &lt;code&gt;jean.dupont&lt;/code&gt; du groupe des
utilisateurs &amp;ldquo;Mainteneurs du TP&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;(Action) Se déconnecter du compte &lt;code&gt;jean.dupont&lt;/code&gt; sur Forgejo et sur Keycloak et
se reconnecter. Constater que l&amp;rsquo;utilisateur n&amp;rsquo;est plus membre de l&amp;rsquo;équipe
&lt;code&gt;mainteneurs&lt;/code&gt;.&lt;/p&gt;
&lt;h1 id=&#34;configurer-une-authentification-sans-mot-de-passe&#34;&gt;Configurer une authentification sans mot de passe&lt;/h1&gt;
&lt;p&gt;Dans cette partie du TP, nous allons améliorer la procédure d&amp;rsquo;authentification
sur Keycloak en rendant l&amp;rsquo;usage du mot de passe optionnel, voire en l&amp;rsquo;éliminant
totalement.&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;(Action) Créer une nouvelle procédure d&amp;rsquo;authentification à partir de celle préexistante &amp;amp;quote;Browser&amp;amp;quote;, ne permettant que l&amp;rsquo;authentification sans mot de passe avec une passkey, ou l&amp;rsquo;authentification avec mot de passe si l&amp;rsquo;attribut &amp;amp;quote;password-authn-allowed&amp;amp;quote; vaut &amp;amp;quote;true&amp;amp;quote;.&lt;/summary&gt;
  &lt;p&gt;Dans le domaine TP, cliquer sur &amp;ldquo;Authentication&amp;rdquo;. Dans l&amp;rsquo;onglet &amp;ldquo;Flows&amp;rdquo;, sur le
menu kebab au bout de la ligne &amp;ldquo;browser&amp;rdquo;, et sélectionner &amp;ldquo;Duplicate. Appeler
ce flow &amp;ldquo;Browser TP&amp;rdquo;. Cliquer sur &amp;ldquo;Browser TP&amp;rdquo;, puis supprimer toutes les
entrées en cliquant sur les icones poubelles.&lt;/p&gt;
&lt;p&gt;Cliquer ensuite sur &amp;ldquo;Add execution&amp;rdquo;, sélectionner &amp;ldquo;Cookie&amp;rdquo; et cliquer sur
&amp;ldquo;Add&amp;rdquo;. Dans la colonne &amp;ldquo;Requirement&amp;rdquo; de la ligne &amp;ldquo;Cookie&amp;rdquo;, sélectionner
&amp;ldquo;Alternative&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Cliquer ensuite sur &amp;ldquo;Add Subflow&amp;rdquo;, appeler ce flow &amp;ldquo;user active
authentication&amp;rdquo;, et conserver le &amp;ldquo;flow type&amp;rdquo; à la valeur &amp;ldquo;Generic&amp;rdquo;. Dans la
colonne &amp;ldquo;Requirement&amp;rdquo; de la ligne &amp;ldquo;user active authentication&amp;rdquo;, sélectionner
&amp;ldquo;Alternative&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Cliquer ensuite sur le &amp;ldquo;+&amp;rdquo; de la ligne &amp;ldquo;user active authentication&amp;rdquo;, puis sur
&amp;ldquo;Add execution&amp;rdquo;. Sélectionner &amp;ldquo;Username Form&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Cliquer ensuite sur le &amp;ldquo;+&amp;rdquo; de la ligne &amp;ldquo;user active authentication&amp;rdquo;, puis sur
&amp;ldquo;Add sub-flow&amp;rdquo;. Le nommer &amp;ldquo;required placeholder&amp;rdquo;, laisser le &amp;ldquo;flow type&amp;rdquo; à la
valeur &amp;ldquo;Generic&amp;rdquo;, puis cliquer sur &amp;ldquo;Add&amp;rdquo;. Dans la colonne &amp;ldquo;Requirement&amp;rdquo; de la
ligne &amp;ldquo;required placeholder&amp;rdquo;, sélectionner &amp;ldquo;Required&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Cliquer ensuite sur le &amp;ldquo;+&amp;rdquo; de la ligne &amp;ldquo;required placeholder&amp;rdquo;, puis sur &amp;ldquo;Add
sub-flow&amp;rdquo;. Le nommer &amp;ldquo;passwordless flow&amp;rdquo;, laisser le &amp;ldquo;flow type&amp;rdquo; à la valeur
&amp;ldquo;Generic&amp;rdquo;, puis cliquer sur &amp;ldquo;Add&amp;rdquo;. Dans la colonne &amp;ldquo;Requirement&amp;rdquo; de la ligne
&amp;ldquo;passwordless flow&amp;rdquo;, sélectionner &amp;ldquo;Alternative&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Cliquer ensuite sur le &amp;ldquo;+&amp;rdquo; de la ligne &amp;ldquo;required placeholder&amp;rdquo;, puis sur &amp;ldquo;Add
sub-flow&amp;rdquo;. Le nommer &amp;ldquo;passwordful flow&amp;rdquo;, laisser le &amp;ldquo;flow type&amp;rdquo; à la valeur
&amp;ldquo;Generic&amp;rdquo;, puis cliquer sur &amp;ldquo;Add&amp;rdquo;. Dans la colonne &amp;ldquo;Requirement&amp;rdquo; de la ligne
&amp;ldquo;passwordful flow&amp;rdquo;, sélectionner &amp;ldquo;Alternative&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Cliquer ensuite sur le &amp;ldquo;+&amp;rdquo; de la ligne &amp;ldquo;passwordless flow&amp;rdquo;, puis sur &amp;ldquo;Add
condition&amp;rdquo;. Sélectionner &amp;ldquo;Condition - user configured&amp;rdquo;, puis cliquer sur Add.
Dans la colonne &amp;ldquo;Requirement&amp;rdquo; de la ligne &amp;ldquo;Condition - user configured&amp;rdquo; que
l&amp;rsquo;on vient d&amp;rsquo;ajouter, sélectionner &amp;ldquo;Required&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Cliquer ensuite sur le &amp;ldquo;+&amp;rdquo; de la ligne &amp;ldquo;passwordless flow&amp;rdquo;, puis sur &amp;ldquo;Add
step&amp;rdquo;. Sélectionner &amp;ldquo;Webauthn Passwordless Authenticator&amp;rdquo;, puis cliquer sur
Add. Dans la colonne &amp;ldquo;Requirement&amp;rdquo; de la ligne &amp;ldquo;Webauthn Passwordless
Authenticator&amp;rdquo;, sélectionner &amp;ldquo;Required&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Cliquer ensuite sur le &amp;ldquo;+&amp;rdquo; de la ligne &amp;ldquo;passwordful flow&amp;rdquo;, puis sur &amp;ldquo;Add
subflow&amp;rdquo;. Le nommer &amp;ldquo;Conditional Flow - password allowed&amp;rdquo;, puis cliquer sur
Add. Dans la colonne &amp;ldquo;Requirement&amp;rdquo; de la ligne &amp;ldquo;Conditional Flow - password
allowed&amp;rdquo;, sélectionner &amp;ldquo;Conditional&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Cliquer ensuite sur le &amp;ldquo;+&amp;rdquo; de la ligne &amp;ldquo;Conditional Flow - password allowed&amp;rdquo;,
puis cliquer sur &amp;ldquo;Add condition&amp;rdquo;. Sélectionner &amp;ldquo;Condition - user attribute&amp;rdquo;,
puis cliquer sur Add. Dans la colonne &amp;ldquo;Requirement&amp;rdquo; de la ligne &amp;ldquo;Condition -
user attribute&amp;rdquo; que l&amp;rsquo;on vient d&amp;rsquo;ajouter, sélectionner &amp;ldquo;Required&amp;rdquo;. Cliquer
ensuite sur la roue crantée de la ligne &amp;ldquo;Condition - user attribute&amp;rdquo;. Saisir
dans le champ &amp;ldquo;Alias&amp;rdquo; la valeur &amp;ldquo;Authentification par mot de passe autorisée&amp;rdquo;,
dans le champ &amp;ldquo;Attribute name&amp;rdquo; la valeur &amp;ldquo;password-authn-allowed&amp;rdquo;, dans le
champ &amp;ldquo;Expected attribute value&amp;rdquo; la valeur &amp;ldquo;true&amp;rdquo;. Cocher &amp;ldquo;Include group
attributes&amp;rdquo;, puis cliquer sur &amp;ldquo;Save&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Cliquer ensuite sur le &amp;ldquo;+&amp;rdquo; de la ligne &amp;ldquo;Conditional Flow - password allowed&amp;rdquo;,
puis sur &amp;ldquo;Add step&amp;rdquo;. Sélectionner &amp;ldquo;Password Form&amp;rdquo;, puis cliquer sur &amp;ldquo;Add&amp;rdquo;. Dans
la colonne &amp;ldquo;Requirement&amp;rdquo;, sur la ligne &amp;ldquo;Password Form&amp;rdquo;, sélectionner
&amp;ldquo;Required&amp;rdquo;.&lt;/p&gt;
&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Assigner cette procédure au flux d&amp;rsquo;authentification &amp;amp;quote;Browser&amp;amp;quote;&lt;/summary&gt;
  &lt;p&gt;Dans la procédure &amp;ldquo;Browser TP&amp;rdquo;, cliquer sur &amp;ldquo;Action&amp;rdquo;, puis &amp;ldquo;Bind flow&amp;rdquo;.
Sélectionner &amp;ldquo;Browser flow&amp;rdquo;, puis &amp;ldquo;Save&amp;rdquo;.&lt;/p&gt;
&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Ajouter un groupe &lt;code&gt;Password allowed&lt;/code&gt; dans le domaine TP&lt;/summary&gt;
  &lt;p&gt;Cliquer sur le menu &amp;ldquo;Groups&amp;rdquo;, puis &amp;ldquo;Create Group&amp;rdquo;. Nommer le groupe, puis
cliquer sur &amp;ldquo;Create&amp;rdquo;.&lt;/p&gt;
&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Ajouter &lt;code&gt;jean.dupont&lt;/code&gt; et &lt;code&gt;admin&lt;/code&gt; en tant que membres du groupe &lt;code&gt;Password allowed&lt;/code&gt;.&lt;/summary&gt;
  &lt;p&gt;Cliquer sur le groupe &lt;code&gt;Password allowed&lt;/code&gt;. Dans l&amp;rsquo;onglet &amp;ldquo;Members&amp;rdquo;, cliquer sur
&amp;ldquo;Add member&amp;rdquo;. Cocher les deux utilisateurs et cliquer sur &amp;ldquo;Add&amp;rdquo;.&lt;/p&gt;
&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Ajouter un attribut &lt;code&gt;password-authn-allowed&lt;/code&gt; au groupe &lt;code&gt;Password allowed&lt;/code&gt;, avec la valeur &lt;code&gt;true&lt;/code&gt;.&lt;/summary&gt;
  &lt;p&gt;Cliquer sur le groupe &lt;code&gt;Password allowed&lt;/code&gt;. Dans l&amp;rsquo;onglet &amp;ldquo;Attributes&amp;rdquo;, cliquer
sur &amp;ldquo;Add attributes&amp;rdquo;. Saisir &lt;code&gt;password-authn-allowed&lt;/code&gt; dans le champ &amp;ldquo;key&amp;rdquo; et
&lt;code&gt;true&lt;/code&gt; dans le champ &amp;ldquo;Value&amp;rdquo;. Cliquer sur &amp;ldquo;Save&amp;rdquo;.&lt;/p&gt;
&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Configurer l&amp;rsquo;enregistrement obligatoire d&amp;rsquo;une passkey pour &lt;code&gt;admin&lt;/code&gt;&lt;/summary&gt;
  &lt;p&gt;Dans le menu &amp;ldquo;Users&amp;rdquo; du domaine TP, cliquer sur l&amp;rsquo;utilisateur &lt;code&gt;admin&lt;/code&gt;. Dans
&amp;ldquo;Required actions&amp;rdquo;, sélectionner &amp;ldquo;Webauthn Register Passwordless&amp;rdquo;. Cliquer sur
&amp;ldquo;Save&amp;rdquo;.&lt;/p&gt;
&lt;/details&gt;

&lt;p&gt;(Action) S&amp;rsquo;authentifier au compte &lt;code&gt;admin&lt;/code&gt; avec un mot de passe. Enregister une
passkey.&lt;/p&gt;
&lt;p&gt;(Action) Se déconnecter et se reconnecter à l&amp;rsquo;utilisateur &lt;code&gt;admin&lt;/code&gt;. Utiliser la passkey.&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;(Action) Retirer &lt;code&gt;admin&lt;/code&gt; du groupe &lt;code&gt;Password allowed&lt;/code&gt;&lt;/summary&gt;
  &lt;p&gt;Dans le menu &amp;ldquo;Groups&amp;rdquo; du domaine TP, cliquer sur le groupe &lt;code&gt;Password allowed&lt;/code&gt;,
puis cocher l&amp;rsquo;utilisateur &lt;code&gt;admin&lt;/code&gt; et cliquer sur &amp;ldquo;Leave&amp;rdquo;.&lt;/p&gt;
&lt;/details&gt;


&lt;details&gt;
  &lt;summary&gt;(Action) Retirer la passkey du compte &lt;code&gt;admin&lt;/code&gt;&lt;/summary&gt;
  &lt;p&gt;Dans le menu &amp;ldquo;Users&amp;rdquo; du domaine TP, cliquer sur l&amp;rsquo;utilisateur &lt;code&gt;admin&lt;/code&gt;. Dans
l&amp;rsquo;onglet &amp;ldquo;Credentials&amp;rdquo;, cliquer sur le menu kebab de la ligne Webauthn-password
less, et cliquer &amp;ldquo;Delete&amp;rdquo; et confirmer.&lt;/p&gt;
&lt;/details&gt;

&lt;p&gt;(Action) Essayer de se connecter au compte admin et constater une erreur.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.rfc-editor.org/rfc/rfc8555.html&#34;&gt;https://www.rfc-editor.org/rfc/rfc8555.html&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://caddyserver.com/docs/caddyfile&#34;&gt;https://caddyserver.com/docs/caddyfile&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
		</item>
		<item>
			<title>Panique morale face à l&#39;écriture inclusive en capacité de droit</title>
			<link>https://broken-by-design.fr/posts/ecriture-inclusive-droit/</link>
			<pubDate>Wed, 29 Nov 2023 00:00:00 +0000</pubDate>
			<guid isPermaLink="true">https://broken-by-design.fr/posts/ecriture-inclusive-droit/</guid>
			<description>&lt;p&gt;Celles et ceux qui me suivent savent certainement que j&amp;rsquo;ai récemment entrepris
de reprendre mes études, grâce au temps libéré en devenant freelance. Je me suis
donc inscrit en faculté de droit à l&amp;rsquo;Université de Paris 1, en capacité, ayant
raté la fenêtre pour les inscriptions en L1. J&amp;rsquo;effectue cette capacité au CNED,
afin de pouvoir bosser à mon rythme et au rythme de mes clients.&lt;/p&gt;
&lt;p&gt;Parmi les différents outils de communication, un groupe de discussion non
officiel existe sur Whatsapp, où des étudiants et étudiantes de capacité peuvent
échanger entre elles et eux, et également avec certaines personnes plus
expérimentées.&lt;/p&gt;
&lt;p&gt;Usant couramment de l&amp;rsquo;écriture inclusive, j&amp;rsquo;ai donc tout naturellement utilisé
ce sociolecte sur ces groupes de discussion, avant de me faire agresser
verbalement par un participant sur mon emploi de cette forme d&amp;rsquo;écriture : &amp;ldquo;ça ne
veut rien dire&amp;rdquo;, &amp;ldquo;les correcteurs ne vont pas te rater&amp;rdquo;, &amp;ldquo;blablabla&amp;rdquo;. S&amp;rsquo;en est
suivi le message suivant, retranscrit en toute légalité puisque posté sur un
groupe de discussion public (mais non listé) :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Bonsoir tout le monde, ici votre serviteur ! J&amp;rsquo;espère que vous allez bien. Un
simple rappel si vous utilisez l&amp;rsquo;écriture inclusive et/ou le point médian. Son
usage à l&amp;rsquo;Université est vivement déconseillé (dans vos copies mais également
vos échanges avec l&amp;rsquo;administration (sic) qui n&amp;rsquo;a pas le droit d&amp;rsquo;utiliser ce
langage d&amp;rsquo;ailleurs). Pour information la jurisprudence administrative a
censuré une délibération de l&amp;rsquo;Université de Grenoble qui utilisait ce langage
ET une proposition de loi vient d&amp;rsquo;être adoptée pour que soit mis un terme à
son usage dans l&amp;rsquo;administration (sic) (actuellement une circulaire) ainsi que
dans tout document officiel (contrat de travail, panneau, etc.). Aussi,
vraiment, n&amp;rsquo;utilisez pas ce langage dans vos copies, au risque de vous faire
saquer par votre correcteur et contrairement à ce que diront certains, vous ne
ferez pas les social justice warriors en contestant vos résultats, ça ne
marche pas comme ça. En fac de droit on parle français et on ne fait pas une
copie militante avec un langage sorti des théories fumantes des woke (sic) des
USA. C&amp;rsquo;est un simple conseil, libre à vous de vous faire votre propre
expérience.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Je propose de ne pas relever outre mesure la stupidité d&amp;rsquo;assigner l&amp;rsquo;écriture
inclusive aux &amp;ldquo;wokes des USA&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;D&amp;rsquo;une part, discréditer une information ou une pratique sur la base de son
origine est une partie intégrante de la cancel culture. Or, selon ses
détracteurs et détractrices, la cancel culture est l&amp;rsquo;apanage des Wokes ; preuve
est donc faite que la cancel culture est également utilisée pour cancel les
Wokes..! La belle ironie.&lt;/p&gt;
&lt;p&gt;D&amp;rsquo;autre part, attribuer l&amp;rsquo;écriture inclusive à des anglophones, dont la langue
est essentiellement non genrée relève du contreexploit intellectuel. La seule
variation récente de la langue sur ce sujet est la généralisation, notamment
dans les papiers scientifiques, de l&amp;rsquo;emploi de &amp;ldquo;she&amp;rdquo; (elle) ou du &amp;ldquo;they&amp;rdquo;
singulier (dont l&amp;rsquo;usage prédate les &amp;ldquo;Wokes&amp;rdquo; de plusieurs siècles) pour désigner
les personnes de genre inconnu ou non pertinent.&lt;/p&gt;
&lt;p&gt;Je passerai également sur la stupidité de déclarer &amp;ldquo;qu&amp;rsquo;en fac de droit on parle
français et on ne fait pas une copie militaire avec un langage [autre]&amp;rdquo;,
puisque le français ne se décrète pas. Il s&amp;rsquo;agit d&amp;rsquo;une langue (&lt;a href=&#34;https://en.wikipedia.org/wiki/Langue_and_parole#Langue&#34;&gt;et non d&amp;rsquo;un
langage&lt;/a&gt;) vivante,
appartenant à la francophonie, qui ne se limite pas à la France. Et c&amp;rsquo;est en
cela qu&amp;rsquo;il est totalement inepte que des pouvoirs politiques tentent d&amp;rsquo;en
imposer un usage. Je parle français ; juste pas &lt;a href=&#34;https://www.youtube.com/watch?v=gm8FKusSUUs&#34;&gt;le français de la République
française&lt;/a&gt;, et ce faisant, je lutte
contre l&amp;rsquo;emploi des langues comme outils d&amp;rsquo;oppression.&lt;/p&gt;
&lt;p&gt;Dans cet article, je vais apporter, après une description un peu plus formelle
de ce qu&amp;rsquo;est l&amp;rsquo;écriture inclusive, un éclairage sur les contrevérités énoncées
dans l&amp;rsquo;extrait précédent.&lt;/p&gt;
&lt;h1 id=&#34;définition-de-lécriture-inclusive&#34;&gt;Définition de l&amp;rsquo;écriture inclusive&lt;/h1&gt;
&lt;p&gt;L&amp;rsquo;objet de l&amp;rsquo;&lt;a href=&#34;https://fr.wikipedia.org/wiki/Langage_inclusif_en_fran%C3%A7ais&#34;&gt;écriture
inclusive&lt;/a&gt; en
français est de faire apparaitre dans la langue les femmes, &lt;a href=&#34;https://fr.wikipedia.org/wiki/Non-binarit%C3%A9&#34;&gt;les personnes sur
le spectre du genre&lt;/a&gt;, ou
&lt;a href=&#34;https://fr.wiktionary.org/wiki/agenre&#34;&gt;agenrée&lt;/a&gt;. En effet, le français, tel que
reconnu par la République française, utilise le masculin comme genre neutre. La
&lt;a href=&#34;https://www.youtube.com/watch?v=url1TFdHlSI&#34;&gt;communauté scientifique&lt;/a&gt; a
cependant pu établir que cette règle créée des biais dans les jugements et les
interprétations qui sont en défaveur des personnes dont le genre est ainsi
invisibilisé.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;écriture inclusive recouvre un ensemble de pratiques typographiques,
syntaxiques et grammaticales visant à faire apparaitre ces genres invisibilisés,
à commencer par le genre féminin.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;écriture inclusive est souvent réduite à l&amp;rsquo;usage du &lt;a href=&#34;https://fr.wikipedia.org/wiki/Point_m%C3%A9dian&#34;&gt;point
médian&lt;/a&gt; (comme dans &amp;ldquo;les
premier.ères arrivé.es seront les mieux servi.es&amp;rdquo;), aux pronoms neutres nouveaux
(comme &amp;ldquo;&lt;a href=&#34;https://fr.wiktionary.org/wiki/iel&#34;&gt;iel&lt;/a&gt;&amp;rdquo; et
&amp;ldquo;&lt;a href=&#34;https://dictionnaire.lerobert.com/definition/iel&#34;&gt;iels&lt;/a&gt;&amp;rdquo;), aux &lt;a href=&#34;https://fr.wikipedia.org/wiki/Langage_inclusif_en_fran%C3%A7ais#Pratiques&#34;&gt;flexions
neutres&lt;/a&gt;
(comme &amp;ldquo;-ae&amp;rdquo;), ou à l&amp;rsquo;&lt;a href=&#34;https://fr.wikipedia.org/wiki/R%C3%A8gle_de_proximit%C3%A9&#34;&gt;accord de
proximité&lt;/a&gt;. Ses
détracteurs et détractrices reprochent à l&amp;rsquo;emploi du point médian de rendre plus
difficiles la lecture, et l&amp;rsquo;oralisation de ces écrits. Malgré mon emploi du point
médian dans mes écrits, je conviens de la validité de ces reproches. J&amp;rsquo;argüerais
cependant que le français est une langue qui a été artificiellement complexifiée
en vue de séparer &amp;ldquo;&lt;a href=&#34;https://www.academie-francaise.fr/lorthographe-histoire-dune-longue-querelle&#34;&gt;les gens de lettres des ignorants et des simples
femmes&lt;/a&gt;&amp;rdquo;.
Ainsi, si nous voulions aller vers une langue plus simple à apprendre,
comprendre et lire, peut-être devrions nous en premier lieu la rendre
&lt;a href=&#34;https://fr.wikipedia.org/wiki/Transparence_orthographique&#34;&gt;transparente&lt;/a&gt;, à
l&amp;rsquo;instar de l&amp;rsquo;&lt;a href=&#34;https://fr.wikipedia.org/wiki/Esp%C3%A9ranto&#34;&gt;Espéranto&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Concernant l&amp;rsquo;emploi des pronoms neutres nouveaux (il en existe de plus anciens,
utilisés de tous et toutes, et auxquels on ne pense même plus sous cet angle,
nonobstant les &lt;a href=&#34;https://www.youtube.com/watch?v=tmLznjLR18A&#34;&gt;divagations de Brigitte Macron et de Jean-Michel
Blanquer&lt;/a&gt;), ces derniers sont dans
plusieurs &lt;a href=&#34;https://fr.wiktionary.org/wiki/iel&#34;&gt;dictionnaires&lt;/a&gt;
&lt;a href=&#34;https://dictionnaire.lerobert.com/definition/iel&#34;&gt;actuels&lt;/a&gt;. Le lecteur ou la
lectrice aura donc tôt fait d&amp;rsquo;en saisir le sens, tout comme il ou elle aura
certainement cherché le mot
&amp;ldquo;&lt;a href=&#34;https://fr.wikipedia.org/wiki/Sociolecte&#34;&gt;sociolecte&lt;/a&gt;&amp;rdquo; employé plus haut dans
ce texte, et qui fait partie du
&lt;a href=&#34;https://www.cnrtl.fr/definition/technolecte&#34;&gt;technolecte&lt;/a&gt; des sociolinguistes.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;écriture inclusive ne se limite cependant pas à ces pratiques. Ainsi, la
féminisation des noms communs, l&amp;rsquo;énumération, l&amp;rsquo;emploi de termes
&lt;a href=&#34;https://fr.wikipedia.org/wiki/Mot_%C3%A9pic%C3%A8ne&#34;&gt;épicènes&lt;/a&gt;, et l&amp;rsquo;évitement
de certaines &lt;a href=&#34;https://fr.wikipedia.org/wiki/Antonomase&#34;&gt;antonomases&lt;/a&gt; sont autant
de techniques d&amp;rsquo;écriture, bien moins remarquables et satisfaisant pourtant à
l&amp;rsquo;inclusivité.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;énumération consiste à lister les noms, dans leurs différentes formes genrées.
On peut citer comme exemples, le célèbre &amp;ldquo;Françaises, Français&amp;hellip;&amp;rdquo; au début des
discours présidentiels, ou la locution &amp;ldquo;le Premier ou la Première Ministre&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Les termes épicènes sont ceux dont &lt;a href=&#34;https://crir.ca/wp-content/uploads/2022/11/Mots-Cl%C3%A9s_Manuel_ecriture-2021.pdf&#34;&gt;la forme ne varie pas suivant que l&amp;rsquo;on se
réfère à un nom féminin ou
masculin&lt;/a&gt;,
comme c&amp;rsquo;est le cas, par exemple avec le mot &amp;ldquo;ministre&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Finalement, les antonomases comme &amp;ldquo;Homme&amp;rdquo;, comme dans &amp;ldquo;la Déclaration des Droits
de l&amp;rsquo;Homme et du Citoyen&amp;rdquo;, peuvent être simplement évitées, lorsque cela est
possible (i.e. quand on ne fait pas référence à un texte l&amp;rsquo;employant déjà&amp;hellip;).&lt;/p&gt;
&lt;p&gt;Comme nous le verrons dans l&amp;rsquo;analyse juridique qui suit, certaines de ces formes
sont rejetées par la loi de la République française, tandis que d&amp;rsquo;autres sont
requises.&lt;/p&gt;
&lt;h1 id=&#34;analyse-juridique&#34;&gt;Analyse juridique&lt;/h1&gt;
&lt;p&gt;Le message cité en début d&amp;rsquo;article évoque plusieurs éléments :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;une décision du tribunal de Grenoble concernant un acte administratif ayant
été annulé ;&lt;/li&gt;
&lt;li&gt;une proposition de loi, adoptée par le Sénat fin octobre 2023 ;&lt;/li&gt;
&lt;li&gt;une circulaire portant sur l&amp;rsquo;emploi de l&amp;rsquo;écriture inclusive dans
l&amp;rsquo;Administration.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Dans ce chapitre, nous verrons que les conclusions énoncées par l&amp;rsquo;auteur du
message cité sont trompeuses, fausses et incomplètes.&lt;/p&gt;
&lt;h2 id=&#34;décision-du-tribunal-de-grenoble&#34;&gt;Décision du tribunal de Grenoble&lt;/h2&gt;
&lt;p&gt;La &lt;a href=&#34;https://www.dalloz-actualite.fr/sites/dalloz-actualite.fr/files/resources/2023/05/ta_grenoble_11_mai_2023_ndeg2005367.pdf&#34;&gt;décision n°2005367 du tribunal administratif de
Grenoble&lt;/a&gt;
concerne une affaire dans laquelle un plaignant sollicite (notamment)
l&amp;rsquo;annulation d&amp;rsquo;une délibération de l&amp;rsquo;Université de Grenoble rédigée en utilisant
certaines techniques d&amp;rsquo;écriture inclusive, et notamment le point médian.&lt;/p&gt;
&lt;p&gt;Le tribunal a condamné l&amp;rsquo;Université de Grenoble et ainsi annulé la délibération
en cause. Les raisons avancées sont cependant particulièrement importantes. En
effet, ses dernières ont rapport avec la nécessité de clarté et
d&amp;rsquo;intelligibilité de la norme. Cette nécessité a valeur constitutionnelle. Elle
a été commentée par Louis le Foyer de Costil, spécialiste en droit public, dans
&lt;a href=&#34;https://www.marianne.net/societe/education/lecriture-inclusive-annulee-a-luniversite-de-grenoble-cette-decision-demeure-assez-fragile&#34;&gt;Marianne&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;D&amp;rsquo;une part, cette décision ne saurait faire jurisprudence quant à la
recevabilité d&amp;rsquo;une copie étudiante, puisque (fort heureusement) les copies
étudiantes ne sont pas la norme, et n&amp;rsquo;ont pas besoin de s&amp;rsquo;élever au niveau de la
qualité de la loi. En outre, des décisions passées ont débouté les plaignants ou
plaignantes souhaitant faire censurer des écrits inclusifs dans d&amp;rsquo;autres
contextes qu&amp;rsquo;un acte administratif. Ce fut notamment le cas &lt;a href=&#34;http://paris.tribunal-administratif.fr/content/download/211637/2022773/version/1/file/2206681_14032023.anon_compl.pdf&#34;&gt;le 14 mars
2023&lt;/a&gt;,
où le tribunal administratif de Paris a rejeté un recours sur l&amp;rsquo;usage du point
médian sur une plaque en hommage aux anciens présidents du conseil de Paris.&lt;/p&gt;
&lt;p&gt;D&amp;rsquo;autre part, comme le note une &lt;a href=&#34;https://www.senat.fr/ej/ej03/ej030.html&#34;&gt;étude
sénatoriale&lt;/a&gt; : &amp;ldquo;le principe de clarté
de la loi renvoie à l&amp;rsquo;exercice par le législateur de sa compétence, qu&amp;rsquo;il tient
de l&amp;rsquo;article 34 de la Constitution. Le Conseil constitutionnel a consacré ce
principe, avant de l&amp;rsquo;abandonner [&amp;hellip;], compte tenu des ambigüités fréquemment
relevées dans la doctrine&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;S&amp;rsquo;agissant d&amp;rsquo;un jugement en première instance, et étant le premier à juger ainsi
négativement de la clarté d&amp;rsquo;un acte administratif utilisant le point médian,
cette décision est relativement fragile et &amp;ldquo;il faudrait que ce jugement soit
confirmé par la cour administrative d’appel, par le Conseil d’État&amp;rdquo;, commente
Louis le Foyer de Costil.&lt;/p&gt;
&lt;h2 id=&#34;proposition-de-loi-sur-lécriture-inclusive&#34;&gt;Proposition de loi sur l&amp;rsquo;écriture inclusive&lt;/h2&gt;
&lt;p&gt;Les termes employés par l&amp;rsquo;auteur du message cité en début d&amp;rsquo;article concernant
&lt;a href=&#34;https://www.assemblee-nationale.fr/dyn/16/textes/l16b1816_proposition-loi#&#34;&gt;la proposition de loi sur l&amp;rsquo;écriture
inclusive&lt;/a&gt;
sont trompeurs. En effet, en choisissant de dire que la proposition de loi a été
adoptée, il entend ainsi faire croire que c&amp;rsquo;est le Parlement qui a adopté le
texte, à l&amp;rsquo;issue de la &lt;a href=&#34;https://www.senat.fr/connaitre-le-senat/role-et-fonctionnement/la-procedure-legislative.html&#34;&gt;procédure
législative&lt;/a&gt;.
Or, ce n&amp;rsquo;est pas le cas. Le texte a simplement été adopté en première lecture
par le Sénat, le 31 octobre 2023. Cette adoption n&amp;rsquo;a rien de surprenant étant
donné que &lt;a href=&#34;https://fr.wikipedia.org/wiki/S%C3%A9nat_(France)&#34;&gt;la couleur politique du Sénat est à droite depuis sa création sous la
Ve République&lt;/a&gt;, et que les
paniques morales sur la désacralisation de la langue sont un marronnier des
mouvements politiques de l&amp;rsquo;extrême centre, de la droite et de l&amp;rsquo;extrême droite.
Le texte n&amp;rsquo;a cependant pas terminé son parcours législatif et doit encore être
étudié par l&amp;rsquo;Assemblée Nationale qui aura le loisir de voter divers amendements,
y compris des &lt;a href=&#34;https://www.assemblee-nationale.fr/dyn/synthese/fonctionnement-assemblee-nationale/travail-legislatif/l-exercice-du-droit-d-amendement&#34;&gt;amendements de
suppression&lt;/a&gt;.
La responsabilité du gouvernement ne pourra également pas être engagée sur ce
texte, compte tenu qu&amp;rsquo;il s&amp;rsquo;agit d&amp;rsquo;un &lt;a href=&#34;https://www.conseil-constitutionnel.fr/le-bloc-de-constitutionnalite/texte-integral-de-la-constitution-du-4-octobre-1958-en-vigueur#article_49&#34;&gt;texte
social&lt;/a&gt;
et que &lt;a href=&#34;https://www.lemonde.fr/politique/article/2023/11/17/le-rn-espere-priver-l-executif-d-un-nouveau-49-3-et-saisit-le-conseil-constitutionnel_6200674_823448.html&#34;&gt;le Gouvernement a déjà utilisé le
49.3&lt;/a&gt;
lors la session parlementaire en cours.&lt;/p&gt;
&lt;h2 id=&#34;circulaire-sur-lécriture-inclusive&#34;&gt;Circulaire sur l&amp;rsquo;écriture inclusive&lt;/h2&gt;
&lt;p&gt;La &lt;a href=&#34;https://www.legifrance.gouv.fr/jorf/id/JORFTEXT000036068906&#34;&gt;circulaire du 17 novembre
2017&lt;/a&gt; est &amp;ldquo;relative
aux règles de féminisation et de rédaction des textes publiés au Journal
officiel de la République française&amp;rdquo;. Ici encore, l&amp;rsquo;auteur du message cité
trompe délibérément son auditoire en laissant entendre que sa portée s&amp;rsquo;applique
également aux écrits des étudiants et des étudiantes. Pourtant le nom de la
circulaire indique bien qu&amp;rsquo;elle se limite au Journal officiel.&lt;/p&gt;
&lt;p&gt;Cette circulaire est cependant référencée dans le &lt;a href=&#34;https://www.education.gouv.fr/bo/21/Hebdo18/MENB2114203C.htm&#34;&gt;bulletin officiel de
l&amp;rsquo;éducation nationale, de la jeunesse et des sports, du 5 mai
2021&lt;/a&gt;. Ce
bulletin, rédigé par Jean-Michel Blanquer, encadre l&amp;rsquo;emploi de l&amp;rsquo;écriture
inclusive dans les actes et usages administratifs, et dans le cadre de
l&amp;rsquo;enseignement. Il convient néanmoins de noter que ce bulletin, fortement chargé
politiquement, use du &lt;a href=&#34;https://fr.wikipedia.org/wiki/G%C3%A9n%C3%A9ralisation_abusive&#34;&gt;sophisme de la généralisation
abusive&lt;/a&gt;, en
tentant de pourfendre l&amp;rsquo;écriture inclusive d&amp;rsquo;une main, tout en en promouvant
(inconsciemment) son usage d&amp;rsquo;une autre, dans un exercice d&amp;rsquo;équilibrisme absurde,
démontrant la parfaite stupidité de son auteur.&lt;/p&gt;
&lt;p&gt;En effet, ce bulletin &amp;ldquo;proscrit le recours à l&amp;rsquo;écriture dite &lt;em&gt;inclusive&lt;/em&gt;, qui
utilise notamment le point médian pour faire apparaitre simultanément les formes
féminines et masculines d&amp;rsquo;un mot employé au masculin lorsque celui-ci est
utilisé dans un sens générique&amp;rdquo;. Simultanément, le bulletin prescrit &amp;ldquo;de
recourir à des formulations telles que &lt;em&gt;le candidat ou la candidate&lt;/em&gt; afin de ne
pas marquer de préférence de genre, ou à des formules telles que &lt;em&gt;les
inspecteurs et les inspectrices de l&amp;rsquo;éducation nationale&lt;/em&gt; pour rappeler la place
des femmes dans toutes les fonctions&amp;rdquo;. Or cette formulation est une pratique
d&amp;rsquo;écriture inclusive, nommée énumération, et qui a été présentée plus haut dans
ce document.&lt;/p&gt;
&lt;p&gt;En conséquence, non seulement l&amp;rsquo;écriture inclusive n&amp;rsquo;est pas proscrite sous
toutes ses formes dans les copies des étudiants et des étudiantes de
l&amp;rsquo;Université, mais elle n&amp;rsquo;est pas non plus &lt;em&gt;proscrite&lt;/em&gt;, mais au contraire
&lt;em&gt;prescrite&lt;/em&gt; par le ministère par l&amp;rsquo;entremise de cette circulaire et de ce
bulletin.&lt;/p&gt;
&lt;p&gt;Pour résumer, si vous souhaitez être certain ou certaines, évitez le point
médian, mais vous pouvez utiliser sans problème les termes épicènes,
l&amp;rsquo;énumération, et l&amp;rsquo;évitement des antonomases discriminantes. Si vous utilisez le
point médian et que vous êtes pénalisés ou pénalisées lors de la notation, un
recours sera possible, car il n&amp;rsquo;existe pas de jurisprudence à ce sujet.&lt;/p&gt;
&lt;p&gt;Finalement, faites attention aux arguments d&amp;rsquo;autorité, en particulier quand ces
derniers sont donnés mâtinés d&amp;rsquo;idéologie.&lt;/p&gt;
</description>
		</item>
		<item>
			<title>Refusez de donner les contacts de vos managers aux recruteurs !</title>
			<link>https://broken-by-design.fr/notes/contact-manager/</link>
			<pubDate>Sun, 23 Apr 2023 00:00:00 +0000</pubDate>
			<guid isPermaLink="true">https://broken-by-design.fr/notes/contact-manager/</guid>
			<description>&lt;p&gt;Donner/Demander les contacts de précédents managers est immoral et injuste.&lt;/p&gt;
&lt;p&gt;Voici pourquoi :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;une des raisons du départ du salarié ou de la salariée peut être due à des tensions avec le ou la manager (pouvant aller jusqu&amp;rsquo;au harcèlement). Demander le contact du ou de la manager accroit l&amp;rsquo;influence de ce dernier ou cette dernière sur la vie du salarié ou de la salariée au delà de la relation de travail initiale, et peut étendre et prolonger le harcèlement de l&amp;rsquo;employé.e à toute sa future carrière professionnelle.&lt;/li&gt;
&lt;li&gt;un.e employé.e peut avoir commis des actes par le passé qui sont de nature à pouvoir lui être reprochés. Néanmoins, ce dernier ou cette dernière bénéficie de plusieurs droits fondamentaux : le droit à l&amp;rsquo;oubli et le droit à se défendre. Au cours de sa vie, une personne change et évolue. Si en droit commun, les crimes peuvent être prescrits, les mauvaises aventures entre managers et employé.es devraient également pouvoir se prescrire, d&amp;rsquo;autant plus rapidement qu&amp;rsquo;elles ne relèvent pas du pénal. L&amp;rsquo;employé.e peut avoir changé, appris de son erreur, s&amp;rsquo;être construit autour de cette mauvaise aventure et être devenu.e un.e. meilleur.e employé.e. Pour autant, le/la manager de l&amp;rsquo;époque n&amp;rsquo;en saura possiblement rien, et pourra nuire à la carrière de l&amp;rsquo;employé.e malgré ses efforts. En outre, il est rarement offert au candidat ou à la candidate de donner sa version des faits lorsqu&amp;rsquo;un.e manager décide de donner un avis négatif. Là aussi, en droit commun, l&amp;rsquo;accusé.e dispose d&amp;rsquo;un droit à se défendre ; droit qu&amp;rsquo;ignorent les recruteurs et recruteuses, comme si la parole des managers étaient au dessus de celle des candidat.es, leur position hiérarchique dans l&amp;rsquo;entreprise en faisant des individu.e.s plus fiables de manière innée.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;En tant que membres d&amp;rsquo;un secteur d&amp;rsquo;activité connaissant le plein emploi, nous, spécialistes en cybersécurité, ressources rares courtisées par les employeurs, avons le devoir moral de refuser fermement ces exigences de la part des recruteurs et recruteuses, par solidarité pour celles et ceux qui souffrent de ce type de situations. Faisons cesser ces abus ! Donnons le droit aux gens d&amp;rsquo;évoluer ! Rendons leur la liberté de s&amp;rsquo;être trompé.es sans entacher l&amp;rsquo;ensemble de leur carrière ! Faisons cesser ce classisme qui érige les managers en juges unilatéraux des bonnes conduites.&lt;/p&gt;
</description>
		</item>
		<item>
			<title>Protocole d&#39;autorisation par &#34;double anonymat&#34; pour la vérification d&#39;âge respectueuse de la vie privée</title>
			<link>https://broken-by-design.fr/posts/proto-authz-porn/</link>
			<pubDate>Thu, 23 Feb 2023 00:11:00 +0000</pubDate>
			<guid isPermaLink="true">https://broken-by-design.fr/posts/proto-authz-porn/</guid>
			<description>&lt;p&gt;Cet article effectue une analyse comparative du protocole d&amp;rsquo;autorisation
d&amp;rsquo;accès à des sites requérant une vérification d&amp;rsquo;âge proposé par le LINC
(Laboratoire d&amp;rsquo;innovation numérique de la CNIL), dit en &amp;ldquo;double anonymat&amp;rdquo;, et
de Privacy Pass, un protocole similaire développé par l&amp;rsquo;IETF (Internet
Engineering Task Force), avec la contribution de Google, Apple, Cloudflare,
Fastly, LIC, Brave Software, The Tor Project, et Mozilla.&lt;/p&gt;
&lt;p&gt;Ces deux protocoles sont génériques et n&amp;rsquo;ont rien de spécifique avec la
vérification d&amp;rsquo;âge. Leur objectif est de prouver à un tiers qu&amp;rsquo;un utilisateur
remplit un certain critère, sans révéler à ce tiers qui est exactement cet
utilisateur parmi un groupe d&amp;rsquo;individus. Ainsi, bien que le protocole proposé
par le LINC soit actuellement popularisé dans le cadre du contrôle d&amp;rsquo;accès aux
sites pornographiques, celui-ci ne se limite pas à ce cas d&amp;rsquo;usage, et d&amp;rsquo;autres
sont possibles (âge, genre, classe de niveaux de revenu, statut de vaccination,
etc.) et certains sont même déjà évoqués sur le site du LINC&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Par exemple, nous pouvons imaginer que cela fonctionne par grand palier selon
la législation : 13 ans, 15 ans, 16 ans et 18 ans.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Dans cet article, nous verrons que le protocole proposé par le LINC comporte
plusieurs risques pour la vie privée des utilisateurs. Parmi ces derniers, il
est notamment question de fuite de données potentiellement caractérisables
comme des données de santé, et de la capacité de l&amp;rsquo;État ou de son représentant à
désanonymiser les utilisateurs en cas de collusion de plusieurs parties, de
manière plus ou moins discrète.&lt;/p&gt;
&lt;p&gt;Cet article est délibérément très technique et s&amp;rsquo;adresse à un public averti et
formé à la cryptographie applicative et à la sécurité des protocoles réseau. La
conclusion de l&amp;rsquo;article devrait être intelligible pour la plupart des lecteurs,
mais elle n&amp;rsquo;aurait aucune valeur scientifique et technique sans le charabia qui
la précède. Si vous êtes journaliste, faites-vous assister par un spécialiste
de confiance pour vérifier mes dires avant de les reprendre.&lt;/p&gt;
&lt;p&gt;Finalement, cet article ne couvre pas les nombreux moyens de contournement de
la mesure technique souhaitée par le gouvernement français, au rang desquels
les VPN. L&amp;rsquo;objectif est de discuter des mérites et des défauts des protocoles
d&amp;rsquo;autorisation. Il est fait l&amp;rsquo;hypothèse (évidemment fantasque) que le monde
entier a déployé cette méthode d&amp;rsquo;autorisation, ou qu&amp;rsquo;il n&amp;rsquo;est pas possible
d&amp;rsquo;échapper à ce contrôle d&amp;rsquo;aucune manière que ce soit. Bienvenue en enfer.&lt;/p&gt;
&lt;h2 id=&#34;description-informelle-du-protocole-du-linc&#34;&gt;Description informelle du protocole du LINC&lt;/h2&gt;
&lt;p&gt;Il n&amp;rsquo;existe à ce jour pas de papier scientifique ou &lt;em&gt;whitepaper&lt;/em&gt; effectuant une
description formelle du protocole proposé. Il existe cependant un article
publié sur le site du LINC&lt;sup id=&#34;fnref1:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;, et le code source d&amp;rsquo;un
démonstrateur&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;. Ces deux ressources sont assez anciennes,
puisqu&amp;rsquo;elles ont été publiées en juin 2022, sans changement depuis lors. Si des
évolutions ont eu lieu entre temps, ces dernières ne sont pas encore rendues
publiques.&lt;/p&gt;
&lt;h3 id=&#34;description-informelle-des-acteurs&#34;&gt;Description informelle des acteurs&lt;/h3&gt;
&lt;p&gt;Pour résumer ce qui est indiqué dans ces ressources, le protocole du LINC est
composé de cinq acteurs ou types d&amp;rsquo;acteurs :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;l&amp;rsquo;utilisateur et son navigateur (appelé Client dans le reste de cet article) ;&lt;/li&gt;
&lt;li&gt;le site requérant une vérification de l&amp;rsquo;âge du Client (appelé Origin dans le reste de
l&amp;rsquo;article, pour faciliter la comparaison avec Privacy Pass ;&lt;/li&gt;
&lt;li&gt;des tiers certificateurs (appelés Issuers dans le reste de l&amp;rsquo;article) ;&lt;/li&gt;
&lt;li&gt;l&amp;rsquo;Autorité qui maintient à jour une liste de tiers certificateurs de confiance ;&lt;/li&gt;
&lt;li&gt;l&amp;rsquo;ouvreur (appelé Opener dans le reste de l&amp;rsquo;article) qui peut désanonymiser
un tiers certificateur à partir d&amp;rsquo;une signature (nous reviendrons sur ce
point).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Il convient de noter que l&amp;rsquo;Autorité et l&amp;rsquo;Opener sont des rôles pouvant être
assumés par une unique entité ou des entités distinctes. Il est fait
l&amp;rsquo;hypothèse que l&amp;rsquo;Autorité et l&amp;rsquo;Opener sont des entités étatiques ou mandatées
par l&amp;rsquo;État français.&lt;/p&gt;
&lt;p&gt;Si les termes Origin, Client, Issuer, Autorité et Opener semblent trop
abstraits, il semble acceptable de les remplacer mentalement dans le reste de
cet article de la façon suivante, tant qu&amp;rsquo;il reste clair à l&amp;rsquo;esprit de chacun
qu&amp;rsquo;il ne s&amp;rsquo;agit que d&amp;rsquo;exemples :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Client : l&amp;rsquo;utilisateur ; vous, moi ;&lt;/li&gt;
&lt;li&gt;Origin : un site pornographique, un débit de boisson, un site de jeu
d&amp;rsquo;argent, un site de réservation pour un évènement (concerts, etc.) ;&lt;/li&gt;
&lt;li&gt;Issuer : le site des Impôts ;&lt;/li&gt;
&lt;li&gt;Autorité : l&amp;rsquo;État français ;&lt;/li&gt;
&lt;li&gt;Opener : l&amp;rsquo;État français.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;description-informelle-des-échanges&#34;&gt;Description informelle des échanges&lt;/h3&gt;
&lt;p&gt;Pour consulter un site dont l&amp;rsquo;accès est restreint (noté Origin), celui-ci
signale au Client, s&amp;rsquo;il n&amp;rsquo;est pas authentifié à l&amp;rsquo;aide d&amp;rsquo;un compte précédemment
créé sur ce site, qu&amp;rsquo;une vérification du critère d&amp;rsquo;accès est requise. Pour
cela, l&amp;rsquo;Origin fournit un &amp;ldquo;challenge&amp;rdquo;. Ce challenge consiste en des données
permettant à l&amp;rsquo;Origin de vérifier, à l&amp;rsquo;issue des différents échanges, que
l&amp;rsquo;autorisation d&amp;rsquo;accès délivrée a bien été émise pour cette Origin, et nul
autre. Il contient également des métadonnées sur la nature du critère qui doit
être contrôlé à propos du Client (p. ex. son âge supérieur à 18 ans).&lt;/p&gt;
&lt;p&gt;Le Client télécharge ce challenge, puis se connecte auprès d&amp;rsquo;un Issuer et lui
envoie le challenge. Cet Issuer vérifie si le Client remplit le critère. Par
exemple, si c&amp;rsquo;est le site des Impôts, il vérifie à l&amp;rsquo;aide des informations
d&amp;rsquo;état civil, si l&amp;rsquo;utilisateur est majeur. Dans le cas où le Client remplit le
critère, l&amp;rsquo;Issuer effectue une opération cryptographique sur le challenge, et
renvoie au Client le résultat de cette opération, que nous appellerons preuve.&lt;/p&gt;
&lt;p&gt;Le Client télécharge cette preuve, puis il se connecte à nouveau à l&amp;rsquo;Origin et
lui envoie la preuve délivrée par l&amp;rsquo;Issuer. L&amp;rsquo;Origin vérifie la validité de
cette preuve grâce à des opérations cryptographiques, vérifie que cette preuve
est bien fournie pour le challenge qu&amp;rsquo;il avait initialement fourni à
l&amp;rsquo;utilisateur et vérifie que l&amp;rsquo;Issuer sélectionné par le Client a toujours la
confiance de l&amp;rsquo;Autorité. Si ces conditions sont réunies, alors l&amp;rsquo;Origin accorde
au Client l&amp;rsquo;accès à son service.&lt;/p&gt;
&lt;h3 id=&#34;description-des-propriétés-de-sécurité&#34;&gt;Description des propriétés de sécurité&lt;/h3&gt;
&lt;p&gt;Le protocole du LINC est affublé du qualificatif de &amp;ldquo;double anonymat&amp;rdquo;, car :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;l&amp;rsquo;identité du Client, bien que connue et vérifiée par l&amp;rsquo;Issuer, reste
inconnue de l&amp;rsquo;Origin. L&amp;rsquo;Origin n&amp;rsquo;a connaissance que du fait que l&amp;rsquo;utilisateur
remplit ou non le critère d&amp;rsquo;admission.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;l&amp;rsquo;identité de l&amp;rsquo;Issuer reste inconnue de l&amp;rsquo;Origin. En effet, les mécanismes
cryptographiques mis en jeu par le protocole permettent à l&amp;rsquo;Origin de vérifier
les preuves et de vérifier que l&amp;rsquo;Issuer a toujours la confiance de l&amp;rsquo;Autorité,
sans jamais apprendre l&amp;rsquo;identité de l&amp;rsquo;Issuer.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ce protocole vise donc à se défier des Origin, et à contrôler leur mécanisme
d&amp;rsquo;autorisation d&amp;rsquo;accès en les privant de toute information d&amp;rsquo;identification.&lt;/p&gt;
&lt;p&gt;En outre, ce protocole vise à ce que l&amp;rsquo;Issuer ne puisse discerner l&amp;rsquo;Origin que
cherche à visiter le Client.&lt;/p&gt;
&lt;p&gt;Protéger l&amp;rsquo;identité du Client semble une évidence, étant donné qu&amp;rsquo;avant la mise
en place de ce type de contrôle d&amp;rsquo;accès, l&amp;rsquo;Origin ignorait tout de l&amp;rsquo;identité
du Client.&lt;/p&gt;
&lt;p&gt;Protéger l&amp;rsquo;identité de l&amp;rsquo;Issuer semble un peu plus surprenant. Cela permet
néanmoins de limiter les risques que l&amp;rsquo;Origin apprenne des informations à
propos de l&amp;rsquo;identité du Client. Par exemple, si le Client utilise le site des
Impôts pour obtenir l&amp;rsquo;autorisation, alors l&amp;rsquo;Origin apprend que le Client est
imposable (c&amp;rsquo;est-à-dire &amp;ldquo;potentiellement monétisable&amp;rdquo;) en plus de connaitre le
critère de majorité.&lt;/p&gt;
&lt;p&gt;Il convient de noter que la propriété d&amp;rsquo;anonymat de l&amp;rsquo;Issuer n&amp;rsquo;est pas limitée
à l&amp;rsquo;Origin. En effet, avec les mécanismes cryptographiques mis en oeuvre par le
protocole du LINC, il n&amp;rsquo;est possible pour personne d&amp;rsquo;autre que l&amp;rsquo;Opener de
savoir qui est l&amp;rsquo;Issuer. Cela peut paraitre étonnant de prime abord, puisque
l&amp;rsquo;utilisateur sait bien auprès de quel organisme il s&amp;rsquo;est authentifié pour
obtenir la preuve de son admissibilité au critère. Il s&amp;rsquo;agit ici d&amp;rsquo;une
subtilité du protocole : l&amp;rsquo;Issuer n&amp;rsquo;est en réalité pas un organisme unique,
mais une clé cryptographique détenue par un organisme. Rien ne permet de
garantir à qui que ce soit qu&amp;rsquo;un organisme ne possède qu&amp;rsquo;une et une seule clé
cryptographique. Pour le dire plus simplement, un organisme peut incarner
simultanément plusieurs Issuers à l&amp;rsquo;insu de tous·tes. Nous reviendrons sur ce
point lors de l&amp;rsquo;analyse des défauts de ce protocole.&lt;/p&gt;
&lt;h3 id=&#34;description-des-mécanismes-cryptographiques-mis-en-oeuvre&#34;&gt;Description des mécanismes cryptographiques mis en oeuvre&lt;/h3&gt;
&lt;p&gt;Ces informations sont majoritairement tirées du démonstrateur publié sur
Github&lt;sup id=&#34;fnref1:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;Origin génère un challenge comprenant deux informations publiques et une
privée. Les informations publiques sont un nonce, et un critère d&amp;rsquo;âge.
L&amp;rsquo;information privée est la durée de validité du challenge.&lt;/p&gt;
&lt;p&gt;Le Client transmet le challenge tel quel à l&amp;rsquo;Issuer sans aucune modification.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;Issuer effectue une &amp;ldquo;signature&amp;rdquo; grâce à la bibliothèque PBC &lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;, et génère
ainsi une preuve à divulgation nulle de connaissance de sa connaissance de sa
clé privée. Il convient de noter que cette clé privée fait partie d&amp;rsquo;un schéma
de signature de groupe&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;, dont le domaine de confiance est géré par
l&amp;rsquo;Autorité. La seule connaissance de la clé publique du groupe est suffisante
pour vérifier la preuve émise par cette clé privée. Une fois cette preuve
créée, elle est envoyée au Client.&lt;/p&gt;
&lt;p&gt;Le Client transmet tel quel à l&amp;rsquo;Origin la preuve, sans aucune modification.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;Origin vérifie que la preuve porte bien sur le challenge/nonce qu&amp;rsquo;il a
initialement délivré à ce Client. Il vérifie que le challenge n&amp;rsquo;a pas expiré.
Il vérifie ensuite la validité de la preuve, grâce à la clé publique de
l&amp;rsquo;Autorité. Il vérifie également dans une liste de révocation fournie par
l&amp;rsquo;Autorité que la clé privée ayant créé la preuve n&amp;rsquo;a pas été révoquée du
domaine de confiance.&lt;/p&gt;
&lt;h2 id=&#34;description-de-privacy-pass&#34;&gt;Description de Privacy Pass&lt;/h2&gt;
&lt;p&gt;Privacy Pass est un protocole d&amp;rsquo;autorisation d&amp;rsquo;accès préservant la vie privée
du Client développé par l&amp;rsquo;IETF. Ce protocole a été initialement proposé, en
2017, par Cloudflare dans un objectif de limitation du nombre de CAPTCHA
présentés aux Clients naviguant sur des sites protégés par Cloudflare depuis le
réseau d&amp;rsquo;anonymisation Tor. Il a depuis été spécifié sous la forme d&amp;rsquo;Internet
Drafts dont certains sont en passe d&amp;rsquo;être adoptés en tant que RFC. Il convient
donc de noter que les éléments évoqués ci-dessous sont contemporains aux
versions en cours d&amp;rsquo;études par le groupe de travail Privacy Pass WG&lt;sup id=&#34;fnref:5&#34;&gt;&lt;a href=&#34;#fn:5&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Privacy Pass est un protocole générique de vérification de critères, bien qu&amp;rsquo;à
l&amp;rsquo;origine, le critère vérifié par Cloudflare soit limité à &amp;ldquo;l&amp;rsquo;intelligence
humaine&amp;rdquo;, ou plus spécifique à la capacité à résoudre un puzzle sensément
insoluble par les intelligences artificielles actuelles.&lt;/p&gt;
&lt;p&gt;Il convient de noter qu&amp;rsquo;il existe deux méthodes de génération des jetons
d&amp;rsquo;autorisation d&amp;rsquo;accès avec Privacy Pass. L&amp;rsquo;un repose sur un VOPRF (Verifiable
Oblivious Pseudo Random Function)&lt;sup id=&#34;fnref:6&#34;&gt;&lt;a href=&#34;#fn:6&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;6&lt;/a&gt;&lt;/sup&gt; et des vérifications avec une clé privée.
L&amp;rsquo;autre utilise des signatures et des vérifications à clé publique. Dans le
cadre de cet article, nous n&amp;rsquo;étudierons que la version avec des signatures et
vérifications à clé publique, afin de rester dans un cadre relativement
comparable au protocole proposé par le LINC.&lt;/p&gt;
&lt;h3 id=&#34;description-des-acteurs-de-privacy-pass&#34;&gt;Description des acteurs de Privacy Pass&lt;/h3&gt;
&lt;p&gt;Privacy Pass est composé de quatre rôles :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Client : l&amp;rsquo;utilisateur et son navigateur ;&lt;/li&gt;
&lt;li&gt;Origin : le site web requérant la vérification du critère ;&lt;/li&gt;
&lt;li&gt;Attester : une entité en charge de vérifier le remplissage du critère par le
Client ;&lt;/li&gt;
&lt;li&gt;Issuer : l&amp;rsquo;entité délivrant la preuve admissible par l&amp;rsquo;Origin que le Client
remplit un certain critère, selon l&amp;rsquo;Attester.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Il existe de nombreuses variations dans l&amp;rsquo;architecture de Privacy Pass. Chaque
rôle peut être incarné par des entités distinctes ou plusieurs rôles peuvent
l&amp;rsquo;être par une seule entité. Ainsi les combinaisons de rôle suivantes sont
spécifiées :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Origin + Attester + Issuer ;&lt;/li&gt;
&lt;li&gt;Origin + Issuer ;&lt;/li&gt;
&lt;li&gt;Attester + Issuer.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;description-des-échanges&#34;&gt;Description des échanges&lt;/h3&gt;
&lt;p&gt;Lorsqu&amp;rsquo;un Client tente d&amp;rsquo;accéder à une Origin requérant un critère spécifique,
l&amp;rsquo;Origin renvoie un ou plusieurs challenges.&lt;/p&gt;
&lt;p&gt;Chaque challenge est composé des informations suivantes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;un type de jeton d&amp;rsquo;autorisation acceptable (en vue de permettre l&amp;rsquo;agilité
cryptographique) ;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;le nom d&amp;rsquo;un issuer pouvant répondre à ce challenge ;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;optionnellement, une information de contexte, sous la forme d&amp;rsquo;une valeur
opaque de 32 octets, permettant de restreindre le contexte d&amp;rsquo;utilisation du
jeton d&amp;rsquo;autorisation ;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;optionnellement, le nom de l&amp;rsquo;Origin ayant produit ce challenge.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;L&amp;rsquo;information de contexte permet notamment de limiter l&amp;rsquo;utilisation à une
Origin particulière, sans pour autant divulguer le nom de cette Origin auprès
de l&amp;rsquo;Issuer. Elle permet aussi d&amp;rsquo;encoder des restrictions comme l&amp;rsquo;adresse IP
depuis laquelle sera autorisée la présentation du jeton d&amp;rsquo;autorisation d&amp;rsquo;accès,
ou encore la durée de validité du challenge.&lt;/p&gt;
&lt;p&gt;Le Client choisit l&amp;rsquo;un des challenges, et contacte un Attester qui est en
relation avec l&amp;rsquo;Issuer spécifié dans le challenge sélectionné. L&amp;rsquo;Attester
vérifie si le critère est vérifié par le Client. Si tel est le cas, l&amp;rsquo;Attester
témoignera de cela auprès de l&amp;rsquo;Issuer. Si l&amp;rsquo;Attester n&amp;rsquo;est pas Issuer, alors il
faudra qu&amp;rsquo;une mise en relation des deux rôles soit effectuée, soit par
l&amp;rsquo;intermédiaire du Client qui contactera l&amp;rsquo;Issuer avec une attestation signée
par l&amp;rsquo;Attester, soit l&amp;rsquo;Attester contactera directement l&amp;rsquo;Issuer.&lt;/p&gt;
&lt;p&gt;Que ce soit le Client ou l&amp;rsquo;Attester qui contacte l&amp;rsquo;Issuer, dans tous les cas,
le Client devra fournir des informations additionnelles à destination de
l&amp;rsquo;Issuer :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;le type de jeton d&amp;rsquo;autorisation acceptable par l&amp;rsquo;Origin et par lui-même ;&lt;/li&gt;
&lt;li&gt;l&amp;rsquo;identifiant tronqué à un octet de la biclé que l&amp;rsquo;Issuer doit utiliser pour
générer le jeton d&amp;rsquo;autorisation ;&lt;/li&gt;
&lt;li&gt;une valeur opaque.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;L&amp;rsquo;identifiant de la biclé que l&amp;rsquo;Issuer doit utiliser pour générer le jeton
d&amp;rsquo;autorisation est le condensat SHA-256 de la clé publique de l&amp;rsquo;Issuer au
format SubjectPublicKeyInfo encodée en DER.&lt;/p&gt;
&lt;p&gt;La valeur opaque est le résultat d&amp;rsquo;une opération de masquage (&lt;em&gt;blinding&lt;/em&gt;) du
condensat du challenge et d&amp;rsquo;un nonce généré par le Client, et de diverses autres
métadonnées protocolaires.&lt;/p&gt;
&lt;p&gt;Le Client peut envoyer plusieurs requêtes à l&amp;rsquo;Issuer (éventuellement par
l&amp;rsquo;entremise de l&amp;rsquo;Attester) pour une même attestation, afin de pouvoir obtenir
plusieurs jetons pour une seule vérification du critère. Pour chaque requête,
il sera nécessaire que le nonce du client soit distinct.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;Issuer vérifie qu&amp;rsquo;une attestation a été fournie par l&amp;rsquo;Attester et effectue la
signature cryptographique de la valeur opaque qu&amp;rsquo;il a reçue.&lt;/p&gt;
&lt;p&gt;Le Client récupère la/les valeur(s) signée(s) et la/les démasque (&lt;em&gt;unblind&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;Le Client envoie ensuite à l&amp;rsquo;Origin le nonce, la signature démasquée, le
condensat du challenge et diverses métadonnées.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;Origin vérifie alors la signature démasquée contre les différentes données
reçues, grâce à la clé publique associée à l&amp;rsquo;Issuer que le Client a choisi. Si
la signature est bonne, alors l&amp;rsquo;accès est accordé.&lt;/p&gt;
&lt;h3 id=&#34;description-des-propriétés-de-sécurité-1&#34;&gt;Description des propriétés de sécurité&lt;/h3&gt;
&lt;p&gt;Privacy Pass offre une protection raisonnable (mais pas absolue) sur l&amp;rsquo;identité du
Client.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;Origin ne peut connaitre l&amp;rsquo;identité du Client, et ce même en cas de
collusion avec l&amp;rsquo;Issuer. Cela est assuré par le mécanisme de masquage, dont
seul le Client connait la clé de démasquage et qui rend virtuellement
impossible toute connexion entre la requête du Client à l&amp;rsquo;Issuer et celle qu&amp;rsquo;il
effectue auprès de l&amp;rsquo;Origin.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;Origin apprend néanmoins quel Issuer a émis la signature, et il peut donc
inférer certaines informations sur l&amp;rsquo;Attester, si tous les Attesters ne sont
pas accrédités par tous les Issuers. Et en connaissant/suspectant quel Attester
a été utilisé, l&amp;rsquo;Origin peut alors inférer une information sur le Client. Pour
reprendre l&amp;rsquo;exemple donné pour le protocole du LINC, si l&amp;rsquo;Attester est le
service des Impôts, et que l&amp;rsquo;Issuer n&amp;rsquo;a comme seul Attester ce dernier,
alors en sachant que cet Issuer a reçu une attestation du service des
Impôts, alors il sait que le Client est imposable.&lt;/p&gt;
&lt;p&gt;Privacy Pass prévoit également que le Client puisse vérifier la signature grâce
à la clé publique de l&amp;rsquo;Issuer. Cette vérification de signature doit être
couplée à la vérification en ligne&lt;sup id=&#34;fnref:7&#34;&gt;&lt;a href=&#34;#fn:7&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;7&lt;/a&gt;&lt;/sup&gt; que la clé publique qu&amp;rsquo;il
connait et utilise pour vérifier la signature est la même que celle à laquelle
tous les autres Clients qui auraient recours à cet Issuer, auraient utilisée.
Ces deux vérifications permettent de contrecarrer une attaque dite par
partitionnement de l&amp;rsquo;ensemble anonyme (&lt;em&gt;anonymity set partitionning&lt;/em&gt;). En effet,
sans elles, le Client pourrait avoir reçu une signature effectuée avec une clé
privée qui ne serait utilisée par l&amp;rsquo;Issuer que pour certains Clients. Ces
Clients ne feraient alors plus partie de l&amp;rsquo;ensemble anonyme global, vérifié par
la clé publique commune, mais d&amp;rsquo;un sous-ensemble, distinguable, vérifiable
uniquement par une clé publique distincte.&lt;/p&gt;
&lt;p&gt;Finalement, la révocation d&amp;rsquo;un Issuer ne s&amp;rsquo;effectue pas de manière centralisée ;
chaque Origin doit individuellement retirer de sa liste de confiance les
Issuers qui ne sont plus de confiance.&lt;/p&gt;
&lt;p&gt;Il existe de nombreuses variantes et options dans Privacy Pass, et il ne s&amp;rsquo;agit
ici que d&amp;rsquo;un portrait partiel, afin des fins de comparaison avec le protocole
du LINC. S&amp;rsquo;il devait il y avoir de nouveaux points de comparaison, à l&amp;rsquo;aune
d&amp;rsquo;une mise à jour des spécifications de l&amp;rsquo;un ou l&amp;rsquo;autre des protocoles, ou si
un oubli c&amp;rsquo;était glissé dans cet article, ce dernier sera mis à jour dès que
l&amp;rsquo;auteur en aura connaissance.&lt;/p&gt;
&lt;h3 id=&#34;description-des-mécanismes-cryptographiques-mis-en-oeuvre-1&#34;&gt;Description des mécanismes cryptographiques mis en oeuvre&lt;/h3&gt;
&lt;p&gt;Privacy Pass est conçu de manière à être agile vis-à-vis de ses mécanismes
cryptographiques. Cette agilité est encodée grâce aux indicateurs de types de
jetons qui ont été évoqués à plusieurs reprises dans la section précédente.&lt;/p&gt;
&lt;p&gt;À l&amp;rsquo;heure où cet article est écrit, il n&amp;rsquo;existe que deux types de jetons :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;0x0001 : VOPRF&lt;sup id=&#34;fnref1:6&#34;&gt;&lt;a href=&#34;#fn:6&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;6&lt;/a&gt;&lt;/sup&gt; (P-384, SHA-384)&lt;/li&gt;
&lt;li&gt;0x0002 : Blind RSA&lt;sup id=&#34;fnref:8&#34;&gt;&lt;a href=&#34;#fn:8&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;8&lt;/a&gt;&lt;/sup&gt; (2048 bit)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;considérations-de-sécurité-et-de-vie-privée&#34;&gt;Considérations de sécurité et de vie privée&lt;/h2&gt;
&lt;p&gt;Après cette longue présentation des deux protocoles, il est proposé de procéder
à l&amp;rsquo;analyse comparative de ces derniers.&lt;/p&gt;
&lt;h3 id=&#34;lien-entre-identité-du-client-et-session-sur-le-site-de-lorigin&#34;&gt;Lien entre identité du Client et session sur le site de l&amp;rsquo;Origin&lt;/h3&gt;
&lt;h4 id=&#34;adresse-ip-de-lutilisateur&#34;&gt;Adresse IP de l&amp;rsquo;utilisateur&lt;/h4&gt;
&lt;p&gt;Le protocole du LINC est un protocole interactif. Pour chaque demande d&amp;rsquo;accès
devant être autorisée, le Client doit contacter un Issuer afin d&amp;rsquo;obtenir une
preuve que le critère est rempli.&lt;/p&gt;
&lt;p&gt;À l&amp;rsquo;inverse, Privacy Pass est un protocole qui peut être interactif ou non. Il
est ainsi possible de demander à un Issuer implémentant Privacy Pass de
multiples jetons d&amp;rsquo;autorisation pour un même challenge. Le Client n&amp;rsquo;est alors
pas obligé de rentrer en contact avec l&amp;rsquo;Attester ou l&amp;rsquo;Issuer à chaque accès à
l&amp;rsquo;Origin, puisqu&amp;rsquo;il peut être en mesure de disposer de certains jetons
&amp;ldquo;d&amp;rsquo;avance&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;La nécessité d&amp;rsquo;interactivité du protocole dit en &amp;ldquo;double anonymat&amp;rdquo; fait que le
Client se présentera probablement à l&amp;rsquo;Issuer et à l&amp;rsquo;Origin avec la même adresse
IP. Si cette dernière n&amp;rsquo;est pas partagée avec une large portion de l&amp;rsquo;ensemble
anonyme (&lt;em&gt;anonymity set&lt;/em&gt;), alors il sera possible de déduire l&amp;rsquo;identité de
l&amp;rsquo;utilisateur et ses habitudes de consommation en cas de collusion de l&amp;rsquo;Issuer
et de l&amp;rsquo;Origin.&lt;/p&gt;
&lt;p&gt;Avec Privacy Pass en mode interactif, le problème est identique. Néanmoins, en
mode non interactif, le Client a l&amp;rsquo;opportunité de moduler son adresse IP, par
exemple grâce à un VPN, pour l&amp;rsquo;unique moment où il collectera l&amp;rsquo;ensemble de ses
jetons d&amp;rsquo;autorisation.&lt;/p&gt;
&lt;h4 id=&#34;challenge&#34;&gt;Challenge&lt;/h4&gt;
&lt;p&gt;Avec le protocole du LINC, le challenge fourni par l&amp;rsquo;Origin est transmis
verbatim à l&amp;rsquo;Issuer. En conséquence, la collusion des deux entités permet
d&amp;rsquo;associer aisément l&amp;rsquo;identité d&amp;rsquo;un Client à une activité sur une session sur
l&amp;rsquo;Origin par simple journalisation puis comparaison des challenges émis et
reçus.&lt;/p&gt;
&lt;p&gt;En outre, même sans collusion, il est possible que l&amp;rsquo;Issuer puisse découvrir
quelle Origin est visitée par le Client grâce à des motifs discernables dans le
challenge. Par exemple, dans le démonstrateur développé par le LINC, le
challenge est simplement la date du serveur. Il suffira alors de
quelques requêtes par quelques Clients pour réussir à discerner l&amp;rsquo;heure exacte
d&amp;rsquo;un serveur après gommage statistique des latences des requêtes. L&amp;rsquo;Issuer sera
ensuite capable d&amp;rsquo;identifier de manière totalement passive quel site est
consulté par quel Client sur la simple base de l&amp;rsquo;information volontairement
transmise par le Client. Même si le challenge était un nombre aléatoire, il
pourrait être possible d&amp;rsquo;identifier l&amp;rsquo;Origin si l&amp;rsquo;Origin n&amp;rsquo;utilise pas un
générateur de nombres aléatoires cryptographiquement sûr. En effet, après un
certain nombre de requêtes, il serait possible de retrouver l&amp;rsquo;état du
générateur de nombres aléatoires, et d&amp;rsquo;ainsi distinguer plusieurs Origin de
manière passive&lt;sup id=&#34;fnref:9&#34;&gt;&lt;a href=&#34;#fn:9&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;9&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Avec Privacy Pass, comme le challenge émis par l&amp;rsquo;Origin est intégré dans une
requête dont le contenu est masqué avant d&amp;rsquo;être envoyée à l&amp;rsquo;Issuer, il n&amp;rsquo;est
pas possible de faire ce lien, même en cas de collusion de l&amp;rsquo;Origin et de
l&amp;rsquo;Issuer. Le Client participe activement au protocole et se défie de l&amp;rsquo;Origin
et de l&amp;rsquo;Issuer.&lt;/p&gt;
&lt;h4 id=&#34;preuve&#34;&gt;Preuve&lt;/h4&gt;
&lt;p&gt;Avec le protocole du LINC, la preuve à divulgation nulle de connaissance émise
par l&amp;rsquo;Issuer est transmise verbatim à l&amp;rsquo;Origin. Comme pour le challenge dans la
section précédente, il est possible de relier l&amp;rsquo;identité du Client à une session
sur l&amp;rsquo;Origin grâce à cette valeur commune.&lt;/p&gt;
&lt;p&gt;Avec Privacy Pass, comme dans la section précédente, le démasquage de la
réponse de l&amp;rsquo;Issuer permet de créer une rupture entre les données connues de
l&amp;rsquo;Issuer et celles connues de l&amp;rsquo;Origin. En conséquence, il n&amp;rsquo;est pas possible
de relier l&amp;rsquo;identité du Client à une session sur l&amp;rsquo;Origin par ce biais. Le
client participe activement au protocole et se défie de l&amp;rsquo;Origin et de
l&amp;rsquo;Issuer.&lt;/p&gt;
&lt;h4 id=&#34;partitionnement-de-lensemble-anonyme&#34;&gt;Partitionnement de l&amp;rsquo;ensemble anonyme&lt;/h4&gt;
&lt;p&gt;Le protocole du LINC prévoit que seul l&amp;rsquo;Opener puisse être en mesure de
recouvrer quel Issuer a émis une preuve donnée. Cette propriété est délibérée
et constitue l&amp;rsquo;un des deux &amp;ldquo;anonymats&amp;rdquo; de ce protocole dit à &amp;ldquo;double anonymat&amp;rdquo;.
Elle est implémentée grâce à l&amp;rsquo;emploi d&amp;rsquo;un mécanisme de signature
cryptographique de groupe&lt;sup id=&#34;fnref1:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;, et elle vise notamment à ce que l&amp;rsquo;Origin
ne puisse distinguer l&amp;rsquo;Issuer.&lt;/p&gt;
&lt;p&gt;Hélas, l&amp;rsquo;Origin n&amp;rsquo;est pas le seul acteur à ne pouvoir distinguer quel Issuer et
plus précisément quelle clé privée d&amp;rsquo;Issuer a été utilisée pour générer une
preuve. Les Clients ne le peuvent pas non plus.&lt;/p&gt;
&lt;p&gt;Ainsi, dans le cas où l&amp;rsquo;Autorité et l&amp;rsquo;Issuer sont malveillants, il est possible
qu&amp;rsquo;un sous-ensemble de l&amp;rsquo;ensemble anonyme (c.-à-d. certains Clients) voie ses
preuves générées à l&amp;rsquo;aide de clés privées spécifiques. Ces preuves sont
indistinguables de toutes les autres preuves, sauf pour l&amp;rsquo;Opener qui sera en
mesure de singulariser les Clients ayant présenté à l&amp;rsquo;Origin ces preuves. Il ne
semble pas improbable, dans le cas où l&amp;rsquo;Opener est l&amp;rsquo;État français qu&amp;rsquo;une
perquisition des serveurs de l&amp;rsquo;Origin permet d&amp;rsquo;obtenir des journaux
applicatifs contenant ces preuves et leur association à des sessions de
navigation.&lt;/p&gt;
&lt;p&gt;Privacy Pass, de son côté, peut également mettre en oeuvre des attaques par
partitionnement de l&amp;rsquo;ensemble anonyme, notamment en incitant le Client à recourir
à plusieurs Issuers tour à tour. Dans le cas où le Client se conforme à ces
incitations, il est alors possible de partitionner l&amp;rsquo;ensemble anonyme en plaçant
le Client à l&amp;rsquo;intersection des ensembles des Clients étant capables ou
incapables d&amp;rsquo;obtenir des jetons d&amp;rsquo;autorisation de certains Issuers. Par
exemple, un Client pourrait être identifié dans un sous-ensemble anonyme dont
ses membres peuvent prouver leur âge grâce à leur banque, et à la sécurité
sociale, et jamais via le service des Impôts. Ce sous-ensemble pourrait ainsi
correspondre aux jeunes encore rattachés au foyer fiscal de leurs
parents/tuteurs. Bien que Privacy Pass spécifie un moyen d&amp;rsquo;inciter les Clients
à fournir des jetons d&amp;rsquo;autorisation provenant de tel ou tel Issuer plutôt que
d&amp;rsquo;autres, le choix revient au logiciel mis en oeuvre par l&amp;rsquo;utilisateur de
suivre cette incitation ou non. Il est donc possible que certains logiciels
implémentant Privacy Pass ne soient pas concernés par cette attaque.&lt;/p&gt;
&lt;h3 id=&#34;futilité-de-linteractivité-comme-méthode-de-prévention-du-marché-noir&#34;&gt;Futilité de l&amp;rsquo;interactivité comme méthode de prévention du marché noir&lt;/h3&gt;
&lt;p&gt;Le protocole du LINC doit et Privacy Pass peut fonctionner en mode interactif.
Ce mode de fonctionnement oblige le Client à obtenir une preuve ou un jeton
d&amp;rsquo;autorisation frais auprès d&amp;rsquo;un Issuer à chaque accès à une Origin. Cette
obligation signifie que les Issuers seront en mesure de reconnaitre des
habitudes de consommation. Dans le cas des sites pornographiques, ce mode est
dangereux puisqu&amp;rsquo;une personne ayant développé une addiction à la
pornographie pourra être identifiée comme telle par un Issuer qui
lui remettrait des dizaines des preuves/jetons d&amp;rsquo;autorisation par jour. Or, les
addictions sont des informations de santé&lt;sup id=&#34;fnref:10&#34;&gt;&lt;a href=&#34;#fn:10&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;10&lt;/a&gt;&lt;/sup&gt; &lt;sup id=&#34;fnref:11&#34;&gt;&lt;a href=&#34;#fn:11&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;11&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Un des risques perçus par le mode non interactif où le Client est autorisé à
demander plusieurs preuves/jetons d&amp;rsquo;autorisation pour un unique challenge est
la création d&amp;rsquo;un marché noir des preuves/jetons d&amp;rsquo;autorisation. En effet, un
Client disposant de plusieurs jetons pourrait distribuer ou vendre ces derniers
sans que l&amp;rsquo;Origin ne puisse distinguer si la preuve a bien été produite pour le
Client qui la lui présente.&lt;/p&gt;
&lt;p&gt;D&amp;rsquo;une part, il existe une contremesure assez simple, et qui est même
recommandée dans la spécification de Privacy Pass : relier le challenge à un
attribut de la connexion entre le Client et l&amp;rsquo;Origin : l&amp;rsquo;adresse IP du Client
ou l&amp;rsquo;identifiant de la connexion TLS &lt;sup id=&#34;fnref:12&#34;&gt;&lt;a href=&#34;#fn:12&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;12&lt;/a&gt;&lt;/sup&gt; (Transport Layer Security).&lt;/p&gt;
&lt;p&gt;Une telle contremesure permettrait de passer en mode non interactif, tout en
contrecarrant l&amp;rsquo;essentiel des risques liés au marché noir.&lt;/p&gt;
&lt;p&gt;Ensuite, en admettant que la preuve/le jeton d&amp;rsquo;autorisation soit bien présenté
à l&amp;rsquo;Origin par le Client l&amp;rsquo;ayant demandé à l&amp;rsquo;Issuer, la première chose que fera
l&amp;rsquo;Origin après vérification de l&amp;rsquo;authenticité de ce jeton sera de créer une
session HTTP classique dans laquelle il sera noté que ce Client est autorisé à
accéder au contenu du site. La plupart des sites n&amp;rsquo;appliquent pas de politique
de sécurité associant fortement une session HTTP à une session TLS. Un
utilisateur malveillant pourra alors revendre non pas son jeton d&amp;rsquo;autorisation,
mais son identifiant de session HTTP. Cette technique de partage de sessions
HTTP par la divulgation de l&amp;rsquo;identifiant de session est bien connu des
auditeurs en sécurité, qui la connaisse sous le nom de Session
Fixation&lt;sup id=&#34;fnref:13&#34;&gt;&lt;a href=&#34;#fn:13&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;13&lt;/a&gt;&lt;/sup&gt;. Un tel partage pourrait même être aisément automatisé à
grande échelle grâce à une extension navigateur.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;usage du mode interactif pour le protocole proposé par le LINC dans le cadre de
la demande de restriction d&amp;rsquo;accès aux sites pornographiques par le gouvernement
français n&amp;rsquo;est donc pas pertinent, et constitue au mieux un choix mal informé.&lt;/p&gt;
&lt;h3 id=&#34;problème-de-la-double-dépense&#34;&gt;Problème de la double dépense&lt;/h3&gt;
&lt;p&gt;Le problème de double dépense survient lorsqu&amp;rsquo;une même preuve ou un même jeton
d&amp;rsquo;autorisation peut être utilisé sur plusieurs Origin, alors que le protocole
souhaiterait voir la preuve/le jeton consommé et ne plus être réutilisable.&lt;/p&gt;
&lt;p&gt;Il existe de nombreuses manières de résoudre ce problème de double dépense.
L&amp;rsquo;une d&amp;rsquo;entre elles, la plus simple théoriquement et bien souvent la plus
difficile à implémenter dans la pratique, est la conception d&amp;rsquo;un registre
commun à l&amp;rsquo;ensemble des Origin. Ces dernières inscriraient au registre commun
les jetons qu&amp;rsquo;elles auraient dépensés, après avoir consulté ce dernier pour
s&amp;rsquo;assurer qu&amp;rsquo;une autre Origin ne l&amp;rsquo;aurait déjà fait. Hélas, cette méthode peut
présenter des problèmes de vie privée, puisque ce registre devrait être
largement consultable et contiendrait indirectement des statistiques de
fréquentation des sites (une donnée métier sensible).&lt;/p&gt;
&lt;p&gt;Une autre méthode tient dans la génération de challenges aléatoires, dont la
probabilité de collision avec un autre challenge émis par une autre Origin
serait négligeable. C&amp;rsquo;est la méthode recommandée par la spécification de
Privacy Pass.&lt;/p&gt;
&lt;p&gt;De manière étrange, dans le démonstrateur proposé par le LINC, le challenge
n&amp;rsquo;est pas aléatoire, mais est la sortie d&amp;rsquo;une fonction monotonique : l&amp;rsquo;heure du
serveur. L&amp;rsquo;heure ne peut constituer un bon moyen de prévention contre la double
dépense, puisque le même challenge peut être alors émis par plusieurs Origin.
Il s&amp;rsquo;agit surement d&amp;rsquo;une facilité utilisée par le développeur dans le cadre du
démonstrateur. Dans une implémentation réelle, il serait néanmoins nécessaire
de prévenir la double dépense à l&amp;rsquo;aide d&amp;rsquo;un challenge généré à l&amp;rsquo;aide d&amp;rsquo;un
générateur de nombres aléatoires cryptographiquement sûr.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Dans cet article, nous avons étudié deux technologies pouvant être utilisées à
des fins de contrôle d&amp;rsquo;accès en fonction de critères vérifiés par des tiers.
Ces technologies prétendent pouvoir prouver à un tiers qu&amp;rsquo;un utilisateur
remplit ces critères sans dévoiler d&amp;rsquo;informations personnelles. Les critères
peuvent être variés, et sont extensibles : seuil d&amp;rsquo;âge, genre, niveaux de
revenu, statut de santé, etc.&lt;/p&gt;
&lt;p&gt;Privacy Pass, un protocole spécifié par un consortium informel sous l&amp;rsquo;égide de
l&amp;rsquo;IETF, remplit cet objectif, sur le papier et dans certaines conditions
d&amp;rsquo;implémentation.&lt;/p&gt;
&lt;p&gt;De son côté, le protocole du LINC dit en &amp;ldquo;double anonymat&amp;rdquo; échoue maintes fois
à protéger l&amp;rsquo;identité de l&amp;rsquo;individu, par erreur de conception ou sous la
contrainte du cahier des charges du commanditaire. Cela est dû notamment à
l&amp;rsquo;interactivité du protocole, et au rôle passif de l&amp;rsquo;utilisateur lors des
échanges.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;interactivité permet de relier nominativement l&amp;rsquo;utilisateur à une session sur
le site qu&amp;rsquo;il souhaite consulter, et fuite ses fréquences de consultation, ce
qui peut être une donnée de santé dans le cas d&amp;rsquo;une addiction (au jeu, à la
pornographie, à l&amp;rsquo;alcool, etc.). Outre son aspect nocif pour la vie privée de
l&amp;rsquo;utilisateur, cette interactivité se révèle totalement futile dans le combat
contre l&amp;rsquo;émergence de marchés noirs de jetons d&amp;rsquo;autorisation permettant
l&amp;rsquo;accès à des personnes ne remplissant pas les critères.&lt;/p&gt;
&lt;p&gt;La passivité de l&amp;rsquo;utilisateur dans les échanges, quant à elle, permet de relier
également l&amp;rsquo;identité de l&amp;rsquo;utilisateur à sa session sur le site visité, et donc
potentiellement à ses préférences sexuelles. Elle permet également aux
organismes attestant que l&amp;rsquo;utilisateur remplit un critère donné d&amp;rsquo;apprendre,
dans certaines conditions, quel site est visité.&lt;/p&gt;
&lt;p&gt;Finalement, il peut être intéressant de noter que le démonstrateur du LINC
comporte une fragilité d&amp;rsquo;implémentation qui permet d&amp;rsquo;utiliser les jetons
d&amp;rsquo;autorisations d&amp;rsquo;accès plusieurs fois, sur plusieurs sites distincts.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://linc.cnil.fr/fr/demonstrateur-du-mecanisme-de-verification-de-lage-respectueux-de-la-vie-privee&#34;&gt;https://linc.cnil.fr/fr/demonstrateur-du-mecanisme-de-verification-de-lage-respectueux-de-la-vie-privee&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref1:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/LINCnil/SigGroup&#34;&gt;https://github.com/LINCnil/SigGroup&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref1:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://crypto.stanford.edu/pbc/&#34;&gt;https://crypto.stanford.edu/pbc/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://fr.wikipedia.org/wiki/Signature_de_groupe&#34;&gt;https://fr.wikipedia.org/wiki/Signature_de_groupe&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref1:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:5&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://datatracker.ietf.org/wg/privacypass/documents/&#34;&gt;https://datatracker.ietf.org/wg/privacypass/documents/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:5&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:6&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-voprf-21&#34;&gt;https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-voprf-21&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:6&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref1:6&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:7&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://datatracker.ietf.org/doc/draft-ietf-privacypass-key-consistency/&#34;&gt;https://datatracker.ietf.org/doc/draft-ietf-privacypass-key-consistency/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:7&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:8&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures-11&#34;&gt;https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-rsa-blind-signatures-11&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:8&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:9&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Linear-feedback_shift_register#Uses_in_cryptography&#34;&gt;https://en.wikipedia.org/wiki/Linear-feedback_shift_register#Uses_in_cryptography&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:9&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:10&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.inserm.fr/dossier/addictions/&#34;&gt;https://www.inserm.fr/dossier/addictions/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:10&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:11&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://fr.wikipedia.org/wiki/D%C3%A9pendance_%C3%A0_la_pornographie#ICD-11_(classification_de_l&#39;OMS)&#34;&gt;https://fr.wikipedia.org/wiki/D%C3%A9pendance_%C3%A0_la_pornographie#ICD-11_(classification_de_l&#39;OMS)&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:11&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:12&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.ietf.org/archive/id/draft-ietf-privacypass-auth-scheme-08.html#name-redemption-context-construc&#34;&gt;https://www.ietf.org/archive/id/draft-ietf-privacypass-auth-scheme-08.html#name-redemption-context-construc&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:12&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:13&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org//wiki/Session_fixation&#34;&gt;https://en.wikipedia.org//wiki/Session_fixation&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:13&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
		</item>
		<item>
			<title>Secure Boot: this is not the protection we are looking for</title>
			<link>https://broken-by-design.fr/posts/secure-boot-not/</link>
			<pubDate>Wed, 30 Nov 2022 00:00:00 +0000</pubDate>
			<guid isPermaLink="true">https://broken-by-design.fr/posts/secure-boot-not/</guid>
			<description>&lt;p&gt;Before being a technology, secure boot is an English expression. But, what does
it mean to boot securely? What are we trying to achieve and to protect?&lt;/p&gt;
&lt;p&gt;First, we want user data protection from a secure system. User data is really
any piece of data a user might display or edit, including the obvious office
documents but also configuration files, databases, downloaded files, log files,
user commands, etc. These data must be protected in confidentiality. For this,
the system must ensure that these data are protected at rest, when the system
is shutdown. However, this is not enough, since access from unauthorized
software could leak the data, for instance over the network or by copying it on
an external removable drive. Hence, a secure system should only run authorized
software.&lt;/p&gt;
&lt;h2 id=&#34;secure-boot-the-technology&#34;&gt;Secure Boot, the technology&lt;/h2&gt;
&lt;p&gt;Secure Boot&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; helps running only authorized software on a machine. It
does so by bootstrapping the security of the system at boot time, by verifying
signatures on various software components, before giving way to other
technologies to keep the system secure, later on. Secure boot works by
authorizing only select executables to be run. Authorized executables are
signed using public cryptography, and the keys used to verify those signatures
are stored securely in UEFI &amp;ldquo;databases&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;UEFI is the successor of the now nearly defunct BIOS. It is an interface
between the operating system and the manufacturer platform, a firmware, that
runs very early on most modern systems. The platform is responsible of, among
many other things, executing the bootloader (for instance, Grub or
systemd-boot). Generally, the bootloader then starts an operating system. In
the case of GNU/Systemd/Linux, the bootloader runs the Linux kernel, which
shuts down all UEFI Boot Services, before dropping its privileges and then
doing &amp;ldquo;Linux stuff&amp;rdquo; (like starting the userland part of the operating system).
This privilege drop is very important because this is what ensures that no code
past that point is able to tamper with the UEFI sensitive information,
including UEFI variables, which contains sensitive data.&lt;/p&gt;
&lt;p&gt;Secure Boot aims at securing &amp;ldquo;everything&amp;rdquo; that is executed prior to that
privilege drop. Once the privileges are drop, Secure Boot is done and it is up
to the operating system to extend that integrity/authenticity protection and
ensure that only authorized software is run. Most Linux distros do not even try
to do it, although there are notable exceptions (Chrome OS, Android, just to
name a few). If we run one of the distros that do not leverage technologies
such as dm-verity, fs-verity (with signatures) or Linux IMA (Integrity
Management Architecture), then Secure Boot protected the boot integrity for
basically nothing, because the security chain is broken by the operating
system, and user data is at risk from possibly any tainted userland executable.&lt;/p&gt;
&lt;p&gt;Nevertheless, ANSSI, the French Infosec Agency recommends in its GNU/Linux
security guide&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; to enable Secure Boot (R3) for all systems
requiring medium security level (level 2 out of 4, 1 being the minimal
requirements and 4 being for highly secure systems). Meanwhile, using a Unified
Kernel Image to bundle the Linux kernel with a initramfs into a single
executable that can be verified by Secure Boot is only recommended&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; for
highly secure systems (security level 4 out of 4). No recommendation is ever
done about using one of the aforementioned integrity features to ensure
operating system integrity.&lt;/p&gt;
&lt;p&gt;Interestingly, a poll on the fediverse&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt; revealed that 89% of the
respondants thinks that Secure Boot is necessary for intermediate security
level, and 45% even think that it should be a minimum requirement.&lt;/p&gt;
&lt;p&gt;This article is a strong push-back against ANSSI &amp;ldquo;recommendation&amp;rdquo;, and it
attempts to prove that it is not only useless but incoherent and misleading.&lt;/p&gt;
&lt;h2 id=&#34;signature-verification-and-default-public-keys&#34;&gt;Signature verification and default public keys&lt;/h2&gt;
&lt;p&gt;Secure boot relies on a set of public keys to verify authorized software
authenticity. By default, most vendors ship Microsoft public keys. These keys
sign all Microsoft Windows version, of course, but to avoid a monopoly, other
executables were signed. The list is ought to be short (and unfortunately, it
is not) because with each signature and authorized software, the attack surface
grows and the probability of a vulnerability raises. Several were already found
in the recent past (e.g. CVE-2020-10713&lt;sup id=&#34;fnref:5&#34;&gt;&lt;a href=&#34;#fn:5&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;,
CVE-2022-34301&lt;sup id=&#34;fnref:6&#34;&gt;&lt;a href=&#34;#fn:6&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;6&lt;/a&gt;&lt;/sup&gt;, CVE-2022-34302&lt;sup id=&#34;fnref:7&#34;&gt;&lt;a href=&#34;#fn:7&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;7&lt;/a&gt;&lt;/sup&gt;,
CVE-2022-34303&lt;sup id=&#34;fnref:8&#34;&gt;&lt;a href=&#34;#fn:8&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;8&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;For this reason, many software still require that Secure Boot be deactivated,
including firmware updates by some manufacturers, including
Intel&lt;sup id=&#34;fnref:9&#34;&gt;&lt;a href=&#34;#fn:9&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;9&lt;/a&gt;&lt;/sup&gt; or Lenovo&lt;sup id=&#34;fnref:10&#34;&gt;&lt;a href=&#34;#fn:10&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;10&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Grub and the kernels are not directly authorized by Microsoft, as it would
require for each and every single version to be signed individually by
Microsoft. Instead, a binary called Shim&lt;sup id=&#34;fnref:11&#34;&gt;&lt;a href=&#34;#fn:11&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;11&lt;/a&gt;&lt;/sup&gt; was developed. This rather
small, auditable, innocuous-looking program is signed by Microsoft. Its role is
basically that of a trojan horse (or a security pivot, depending on the way you
look at it). Indeed, its only purpose is to cryptographically verify the
authenticity of any executable. However, this time, the list of public keys
used to verify these executables is not directly under the control of
Microsoft. These public keys are either built in Shim itself or stored in a EFI
variable serving as a database.&lt;/p&gt;
&lt;p&gt;Additionally, shim public key list can be altered by any user able to prove
&amp;ldquo;presence&amp;rdquo;. This is the case of any user using the local console or using a BMC
for remote console access. Once a new public key enrolled, all executables
verifiable by that key can run in the UEFI privileged mode, and for instance
create a persistent backdoor in the bootstrapping code of the machine.&lt;/p&gt;
&lt;p&gt;If this was not enough, users able to prove &amp;ldquo;presence&amp;rdquo; can also disable shim
verification of authorized software. This means that shim can be used to have
the system believe that Secure Boot was used to bootstrap security, while
untrusted code was ultimately run within the UEFI privileged mode.&lt;/p&gt;
&lt;p&gt;Hence, thanks to shim, just about any signed or unsigned, trusted or untrusted
executable can be validated by proxy by Secure Boot using Microsoft keys.&lt;/p&gt;
&lt;p&gt;And this conclusion signs (pun intended) the second incoherence in ANSSI
recommendations. Indeed, they recommend replacing Microsoft keys by our own set
of keys only for highly secure security level (R4). This means that all systems
with intermediate (2/4) and enhanced (3/4) security levels will have the false
sense of security of running Secure Boot while exposing themselves to attackers
capable of proving &amp;ldquo;presence&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;For what it is worth, shim does provide a way secure all operations, including
disabling verification or enrolling new keys by setting a password on shim&amp;rsquo;s
MOK (Machine Owner Keys) Manager&lt;sup id=&#34;fnref:12&#34;&gt;&lt;a href=&#34;#fn:12&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;12&lt;/a&gt;&lt;/sup&gt;. However, the feature is mostly
unused because no Linux distro enables it (it requires user interaction during
the boot procedure) and system administrators often mistake the MOK Manager
password, which secures the access to the MOK Manager as a whole, with the
password that is asked when running mokutil commands (including &lt;code&gt;--import&lt;/code&gt; and
&lt;code&gt;--disable-verification&lt;/code&gt;), which is just a password used to confirm the will of
the user in the MOK Manager. The author of this article failed to find a single
tutorial or article discussing the necessity of setting a MOK Manager for a
Secure Boot. ANSSI also failed to recommend that. Most interestingly, setting a
MOK Manager password is recommended even for Windows administrators that have
no intention of ever running Linux, because MOK Manager is one of
the executables signed by the Microsoft keys.&lt;/p&gt;
&lt;h2 id=&#34;using-our-own-set-of-secure-boot-keys-pk-and-kek&#34;&gt;Using our own set of Secure Boot keys (PK and KEK)&lt;/h2&gt;
&lt;p&gt;Since replacing the Microsoft keys and signing only authorized binaries (i.e.
our own Unified Kernel Image and specifically not shim) is an option, why not
do that? It just requires that the system administrators replace the Secure
Boot keys. The question of who controls the private key and the signature
process is entirely up to whether the signed executable is altered or not by
the system administrator. Distros could ship public keys and Unified Kernel
Images instead of relying on Shim. If we run our own kernel, as recommended by
ANSSI (R15 to R27), then we need to handle the private key and the signature
process ourselves.&lt;/p&gt;
&lt;p&gt;With a Unified Kernel Image signed and verified by Secure Boot, we are now sure
that only our code is executed, and we can safely ask for the user passphrase
to unlock the LUKS container. This way, user data is protected at rest, and
accessed only by authorized software. Cool. Except it is not.&lt;/p&gt;
&lt;p&gt;First, as mentioned earlier, the only thing that we verified is that the
Unified Kernel Image is authentic. That kernel must then verify the operating
system to ensure that only verified software is run. This requires
cryptographic verification of every single executable (binaries, scripts and
executable configuration files (because&amp;hellip; yeah&amp;hellip; that&amp;rsquo;s a thing)) in the
operating system. This can be achieved if we, at minimum, do the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;use a read-only filesystem for our partitions containing executable code,
enforced using dm-verity, or fs-verity with file signature or Linux IMA, or
something similar;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;use the noexec mount option on data partitions;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;modify command interpreters to ensure they do not execute scripts from mount
points with noexec nor from STDIN;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;prevent writable memory from ever getting executed, by patching the kernel;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ensure that no executable configuration file is writable.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Welcome in Wonderland, Alice.&lt;/p&gt;
&lt;p&gt;Ok, but let&amp;rsquo;s assume we go down that rabbit hole&amp;hellip; are we secure yet?&lt;/p&gt;
&lt;p&gt;No. No, we are not.&lt;/p&gt;
&lt;p&gt;Because there is no way of telling if our Secure Boot implementation is tainted
by an attacker or not. Indeed, someone could have flashed our UEFI firmware
before we enabled Secure Boot. Or they could have disabled it, flashed and
reenabled it, if we did not have a UEFI administration password at some point.
Or they could have abused shim when we were using the default keys to flash
UEFI.&lt;/p&gt;
&lt;h2 id=&#34;nirvana-fallacy-much&#34;&gt;Nirvana Fallacy much?&lt;/h2&gt;
&lt;p&gt;So, if Secure Boot is not a good answer, especially against an attacker capable
of physical access or remote access through a BMC, what is? Is there a better
solution?&lt;/p&gt;
&lt;p&gt;Well, to the best of the author knowledge, there is one: using a TPM. Using a
TPM will not necessarily prevent an attacker from tainting the firmware. It
will not necessarily prevent booting untrusted and unverified executables. What
a TPM can give us is the ability to unseal a LUKS passphrase and get access to
user data if and only if the cryptographically verified right version of UEFI
firmware, Unified Kernel Image and operating system image have been booted.
This is based on PCR policies, that ties the sealed passphrase to a particular
signed set of executables measured by the TPM. This approach ensures user data
confidentiality at rest and the authenticity of the executables that are on
disk during boot. Of course, it does not prevent executing writable memory, nor
user data flagged as executable, including scripts, and executable
configuration files. And of course, having a signed set of policies means
handling a private key and designing a signature procedure. There is no free
lunch. Sorry.&lt;/p&gt;
&lt;p&gt;However, using a TPM offers the same security level against attackers with
physical access, attackers with remote access through a BMC, and a rogue system
administrator, and that is something that Secure Boot cannot brag about.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;So there you have it: recommending idly Secure Boot for all systems requiring
intermediate security level accomplishes nothing, except maybe giving more work
to system administrators that are recompiling their kernel, while offering
exactly no measurable security against many threats if UEFI Administrative
password and MOK Manager passwords are not set. This is especially true for
laptop systems where physical access cannot be prevented for obvious reasons.
For servers in colocation, the risk of physical access is not null. And finally
for many servers, the risk of a rogue employee somewhere in the supply chain,
or the maintenance chain cannot be easily ruled out.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://uefi.org/specs/access&#34;&gt;UEFI Specifications&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;no English version yet. &lt;a href=&#34;https://www.ssi.gouv.fr/uploads/2019/02/fr_np_linux_configuration-v2.0.pdf&#34;&gt;French version&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;&amp;ldquo;Protect command line parameters and initramfs with Secure Boot&amp;rdquo;&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://infosec.exchange/@x_cli/109348532363333158&#34;&gt;Mastodon poll&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:5&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-10713&#34;&gt;CVE-2020-10713&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:5&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:6&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-34301&#34;&gt;CVE-2022-34301&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:6&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:7&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-34302&#34;&gt;CVE-2022-34302&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:7&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:8&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-34303&#34;&gt;CVE-2022-34303&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:8&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:9&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.intel.com/content/dam/support/us/en/documents/mini-pcs/UEFI-Flash-BIOS-Update-Instructions.pdf&#34;&gt;Intel UEFI Flash BIOS Update Instruction&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:9&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:10&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://support.lenovo.com/us/en/solutions/ht118103-flash-bios-with-uefi-tool-ideacentre-stick-300&#34;&gt;Lenovo flash BIOS with UEFI tool&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:10&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:11&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/rhboot/shim&#34;&gt;shim source code&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:11&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:12&#34;&gt;
&lt;p&gt;The command is &lt;code&gt;mokutil --password&lt;/code&gt;. Please consider using it.&amp;#160;&lt;a href=&#34;#fnref:12&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
		</item>
		<item>
			<title>Building a Debian rootfs from an unprivileged user with debootstrap</title>
			<link>https://broken-by-design.fr/posts/debootscrap/</link>
			<pubDate>Thu, 08 Sep 2022 18:00:00 +0200</pubDate>
			<guid isPermaLink="true">https://broken-by-design.fr/posts/debootscrap/</guid>
			<description>&lt;p&gt;At Gatewatcher&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;, we put efforts in making our building system reproducible
and working offline, so that we can reduce the risk of supply chain attacks.
Some efforts are also made so that our building system run with as few
privileges as possible.&lt;/p&gt;
&lt;p&gt;One of the few things we were still running as a privileged user recently was
the build of our initial Debian root filesystem, for our base system and for our
containers.&lt;/p&gt;
&lt;p&gt;Indeed, the official Debian Docker container from Docker Hub was not generated
in a way that we can consider secure for our need. It basically downloads a blob
from a web server, does no verification whatsoever of that blob and ships it as
the root filesystem&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;. Even though the root filesystem they are using
can be rebuilt in a reproducible way, downloading the result from Internet
without verifying it against the expected hash is sort of missing the point of
reproducible builds. Also, debuerreotype uses &lt;code&gt;debootstrap&lt;/code&gt;, which is
problematic in itself, as explained hereafter.&lt;/p&gt;
&lt;p&gt;To create such root filesystem, multiple tools are provided by the Debian team,
among which &lt;code&gt;debootstrap&lt;/code&gt;, and &lt;code&gt;multistrap&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Multistrap has not been updated in many years&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;, and suffers from
some limitations that were show-stoppers for us, but it is capable to create
root filesystems from an unprivileged user without hacks.&lt;/p&gt;
&lt;p&gt;On the other hand, deboostrap is not really friendly with the idea of building a
system from an unprivileged user.&lt;/p&gt;
&lt;p&gt;First of, there is a check to ensure we are running it with UID 0&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;.
This can be bypassed in several documented ways, including using &lt;code&gt;fakeroot&lt;/code&gt;,
which overloads some libc calls, using &lt;code&gt;LD_PRELOAD&lt;/code&gt;. An other, less hacky, way
is to run the program in a user namespace.&lt;/p&gt;
&lt;p&gt;Unfortunately, this is not sufficient to run &lt;code&gt;debootstrap&lt;/code&gt;, since it performs
another check consisting of trying to create a &amp;ldquo;/dev/null&amp;rdquo; node&lt;sup id=&#34;fnref:5&#34;&gt;&lt;a href=&#34;#fn:5&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;.
This is more problematic since nodes cannot be created from a user namespace, as
this would create a easy way of escaping the namespace.&lt;/p&gt;
&lt;p&gt;As it seems, though, there is a way to build an unprivileged Debian root
filesystem that is even built into deboostrap, using the installation variant
&amp;ldquo;fakechroot&amp;rdquo;. Alternate code paths exist in deboostrap when this variant is
selected that side-step some checks, and fake some calls. This variant also adds
a check to ensure this variant is run only if the &lt;code&gt;fakechroot&lt;/code&gt; utility is in
use. Therefore, you are expected to run debootstap as followed, as documented in
the &lt;code&gt;fakechroot&lt;/code&gt; manpage:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# apt update &amp;amp;&amp;amp; apt install -y debootstrap fakeroot fakechroot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ fakechroot fakeroot debootstrap --variant&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;fakechroot bullseye &lt;span class=&#34;nv&#34;&gt;$HOME&lt;/span&gt;/rootfs
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;fakechroot&lt;/code&gt; works by overloading some functions with &lt;code&gt;LD_PRELOAD&lt;/code&gt;, and has some
documented limitations regarding symlinks. As it happens, these limitations
include rewrites of absolute symlinks, by prefixing them with the path of the
faked chroot. As a result, within the chroot, you will find links that are
broken when actually chrooting, such as when you would use that directory
hierarchy as a root filesystem on a container or a virtual machine.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;fakechroot&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ readlink /path/to/my/chroot/usr/sbin/telinit
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/path/to/my/chroot/bin/systemctl
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Without &lt;code&gt;fakechroot&lt;/code&gt; (this is what you want to see, in a normal system):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ readlink /path/to/my/chroot/usr/sbin/telinit
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/bin/systemctl
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After some verifications, we decided that it was safe to fake the use of
&lt;code&gt;fakechroot&lt;/code&gt;, while using the &amp;ldquo;fakechroot&amp;rdquo; installation variant. For this, we
set the environment variable &lt;code&gt;FAKECHROOT&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt;, which fakechroot is
supposed to set and which is controlled by &lt;code&gt;debootstrap&lt;/code&gt; to authorize the use of
the &amp;ldquo;fakechroot&amp;rdquo; variant. And it worked.&lt;/p&gt;
&lt;p&gt;So to build a working root filesystem from an unprivileged user, we are now
doing the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ podman unshare
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# FAKECHROOT=true debootstrap --variant=fakechroot bullseye chroot/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# tar -C chroot/ --exclude=dev/* -czf ./chroot.tgz .&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# exit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ cat &lt;span class=&#34;s&#34;&gt;&amp;lt;&amp;lt;EOF &amp;gt; Containerfile
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;FROM scratch
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;ADD chroot.tgz .
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;CMD [&amp;#34;/bin/bash&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ podman build -f Containerfile
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This series of commands builds a Debian container from an unprivileged user.
More work needs to be done to achieve offline reproducible builds, of course,
but none require hacks like this, thankfully.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.gatewatcher.com/&#34;&gt;https://www.gatewatcher.com/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/debuerreotype/docker-debian-artifacts/blob/master/download.sh#L7&#34;&gt;https://github.com/debuerreotype/docker-debian-artifacts/blob/master/download.sh#L7&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://browse.dgit.debian.org/multistrap.git/log/&#34;&gt;https://browse.dgit.debian.org/multistrap.git/log/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://salsa.debian.org/installer-team/debootstrap/-/blob/90747310f8722ca7e3b6a13af3f0c0e76cf7dd74/debootstrap#L605&#34;&gt;https://salsa.debian.org/installer-team/debootstrap/-/blob/90747310f8722ca7e3b6a13af3f0c0e76cf7dd74/debootstrap#L605&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:5&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://salsa.debian.org/installer-team/debootstrap/-/blob/90747310f8722ca7e3b6a13af3f0c0e76cf7dd74/functions#L1664&#34;&gt;https://salsa.debian.org/installer-team/debootstrap/-/blob/90747310f8722ca7e3b6a13af3f0c0e76cf7dd74/functions#L1664&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:5&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
		</item>
		<item>
			<title>On votes, and Indieweb forums</title>
			<link>https://broken-by-design.fr/notes/votes/</link>
			<pubDate>Thu, 16 Jun 2022 00:00:00 +0000</pubDate>
			<guid isPermaLink="true">https://broken-by-design.fr/notes/votes/</guid>
			<description>&lt;p&gt;In reply to &lt;a href=&#34;https://seirdy.one/notes/2022/06/14/better-vote-enabled-forums/&#34;&gt;https://seirdy.one/notes/2022/06/14/better-vote-enabled-forums/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Context: &lt;a href=&#34;https://lemmy.ml/post/307399&#34;&gt;https://lemmy.ml/post/307399&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Reddit and Lemmy supports upvotes and downvotes. This system is meant to allow good content to bubble up and bad content to sink. The goal is for people to self administer a filter bubble instead of relying on an opaque AI to sort content for the users, based on their inferred preferences.&lt;/p&gt;
&lt;p&gt;Lemmy offers alternative sorting algorithms, some of which are not based on votes. This allows people to be able to dig up links, threads and comments that do not score well.&lt;/p&gt;
&lt;p&gt;Downvotes are often used as a cheap way to signify a disagreement. They can be frustrating because the author of a post might feel bad without having a clear explanation about the disagreement. Downvotes can also be misused, e.g. for harassment campaigns and brigading.&lt;/p&gt;
&lt;p&gt;Upvotes can also be assimilated to &amp;ldquo;likes&amp;rdquo;, which may signify agreement. Likes are well-known to be addictive, and some people become dependant of them, to the point of &amp;ldquo;living for social validation&amp;rdquo; at the cost of their own well-being. The &lt;a href=&#34;https://www.youtube.com/playlist?list=PLv1KZC6gJTFnOvSLchy-SHfp5UD-zrISt&#34;&gt;&amp;ldquo;Infernet&amp;rdquo; series&lt;/a&gt; by the French media &amp;ldquo;&lt;a href=&#34;https://www.blast-info.fr/&#34;&gt;Blast, le souffle de l&amp;rsquo;info&lt;/a&gt;&amp;rdquo; documents several cases.&lt;/p&gt;
&lt;p&gt;Overall, votes (both up and down) can have a negative impact, at least on some users.&lt;/p&gt;
&lt;p&gt;My understanding of your suggestion is that votes shall only be casted as part of a comment meeting a set of criteria for minimal quality. Automated screening are often gamified and are generally not well accepted by users. Also, I would argue that upvotes marking agreement will have a difficult time meeting the minimal quality criteria: agreement needs less words/clauses to be expressed than disagreement that would need to be supported by arguments.&lt;/p&gt;
&lt;p&gt;Thus, I think that a system where votes can only be casted with comments would almost only have downvotes in practice. It feels like votes would therefore be redundant and that this system would be better off relying on another criterion than votes to sort content displayed by the forum/link aggregator. Someone suggested &lt;a href=&#34;https://infosec.exchange/@x_cli/108435182950317450&#34;&gt;other engagement criteria&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Regarding the overall quality of posts in the system you present, I would agree that following the IndieWeb/POSSE philosophy could reduce the amount of low quality content since the author&amp;rsquo;s reputation would be directly impacted by the fact that their low quality content would be hosted on their own site.
However, I would argue that user tracing and linkability would be increased, which can be an severe issue, especially for people expressing dissident opinions.&lt;/p&gt;
&lt;p&gt;Regarding the use of a chat room for content creation, I suppose this is a mostly a question of habits and preferences. I do not like chat rooms because I find it difficult to track threads and comments and I prefer using a git send-email workflow with a good MUA, much like we do for code reviews at $WORK.&lt;/p&gt;
</description>
		</item>
		<item>
			<title>Displaying Password Policy before Password Change</title>
			<link>https://broken-by-design.fr/notes/display-password-policy/</link>
			<pubDate>Thu, 26 May 2022 16:30:00 +0000</pubDate>
			<guid isPermaLink="true">https://broken-by-design.fr/notes/display-password-policy/</guid>
			<description>&lt;p&gt;On a multi-user system, one may not trust users to choose strong passwords.
Thus, one can setup up a password policy. On linux systems using &lt;!-- raw HTML omitted --&gt;PAM&lt;!-- raw HTML omitted --&gt;, this can be done with
&lt;code&gt;pam_cracklib&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;While &lt;code&gt;pam_cracklib&lt;/code&gt; does an excellent job, with many options, it does not have
an option to display the current password policy to the user prior to a
password change. Indeed, this could be tedious because of the localization.&lt;/p&gt;
&lt;p&gt;Displaying the policy is crucial, especially for users with expired passwords
that must change them upon logging, because they can&amp;rsquo;t have access to the
system to learn the policy before changing their passwords. This often results
in frustrated users trying to &amp;ldquo;discover&amp;rdquo; the policy by trials and errors.&lt;/p&gt;
&lt;p&gt;Sadly, most sysadmins I met forget to display that policy, or just do not know
how to do it.&lt;/p&gt;
&lt;p&gt;One response is to use &lt;code&gt;pam_echo&lt;/code&gt;. This module displays on screen the content
of a file and it can do so in all four PAM phases (account, auth, password, and
session). With &lt;code&gt;pam_echo&lt;/code&gt;, system administrators can just write down in the
natural language of their users what the password policy is, and display it
using a well-positioned call to &lt;code&gt;pam_echo&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For instance, on my debian system, I edited /etc/pam.d/common-password and I
added just before the line about &lt;code&gt;pam_unix&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;password optional pam_echo.so file=/etc/password_policy
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
		</item>
		<item>
			<title>Why is it better to sign commits with SSH than OpenPGP?</title>
			<link>https://broken-by-design.fr/notes/ssh-vs-openpgp-signing/</link>
			<pubDate>Thu, 26 May 2022 11:00:00 +0000</pubDate>
			<guid isPermaLink="true">https://broken-by-design.fr/notes/ssh-vs-openpgp-signing/</guid>
			<description>&lt;p&gt;The OpenPGP format was designed in the 90&amp;rsquo;s and never really changed since
then. It was documented in
&lt;a href=&#34;https://datatracker.ietf.org/doc/html/rfc4880&#34;&gt;RFC4880&lt;/a&gt; in 2008.
Unfortunately, in the 90&amp;rsquo;s, people had really no good understanding of crypto
yet, and the choices made were poor. Envelope design is poor. Some crypto
algorithms are clearly outdated. Some default options are plain wrong.&lt;/p&gt;
&lt;p&gt;Have you ever noticed that so many crypto attacks target OpenPGP and GnuPG?
That&amp;rsquo;s not a surprise: it&amp;rsquo;s a popular crypto solution and it&amp;rsquo;s a relatively
easy target, comparatively to some other mainstream crypto implementations. The
Go langage maintainers even deprecated the OpenPGP implementation in their
crypto standard library because they think &lt;a href=&#34;https://github.com/golang/go/issues/44226&#34;&gt;OpenPGP is
&lt;em&gt;dangerous&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;OpenPGP is incompatible with &lt;a href=&#34;https://golang.org/design/cryptography-principles&#34;&gt;Go Cryptography
Principles&lt;/a&gt;,
it&amp;rsquo;s complex, fragile, and unsafe, and using it exposes applications to a
dangerous ecosystem.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Basically, I would say that the only thing that OpenPGP has for itself is the
deployed infrastructure. Or has it? Web of trust is mostly dead, since
keyservers are out-of-service. And OpenPGP adoption was never really that high
to begin with.&lt;/p&gt;
&lt;p&gt;SSH keys are much more widely deployed and used than OpenPGP keys. The format
is dead simple, and the crypto implementation from OpenSSH is up-to-date.&lt;/p&gt;
&lt;p&gt;I am very happy that git made SSH signing possible; it means I can delete my
OpenPGP keys for good. I just hope linux distros will make the switch soon, to
a more modern crypto approach: ssh signing or minisign.&lt;/p&gt;
</description>
		</item>
		<item>
			<title>Secure large file decryption using Linux, Go and Nacl</title>
			<link>https://broken-by-design.fr/posts/large-file-decrypt-en/</link>
			<pubDate>Tue, 11 Jan 2022 00:00:00 +0000</pubDate>
			<guid isPermaLink="true">https://broken-by-design.fr/posts/large-file-decrypt-en/</guid>
			<description>&lt;p&gt;It is often said that you should not create your own cryptographic algorithm. That in cryptography, one should not be original; that security is in the beaten track, and in particular those which are beaten by cryptographers. What is often forgotten is that using cryptography is also perilous. In this article we will discuss how to handle large files when decrypting, and how to do it securely on a Linux system. This article will be illustrated with Go code.&lt;/p&gt;
&lt;h2 id=&#34;what-is-a-large-file-and-how-is-it-different-from-small-files&#34;&gt;What is a &amp;ldquo;large file&amp;rdquo; and how is it different from &amp;ldquo;small files&amp;rdquo;?&lt;/h2&gt;
&lt;p&gt;A small file is anything that is reasonable to store in RAM, in its entirety. RAM is a sanctuary where a program can store information. This sanctuary offers a relatively strong guarantee of isolation from interference from other tasks/processes.&lt;/p&gt;
&lt;p&gt;Conversely, a large file is a file that cannot be stored in its entirety in the RAM of the system that will decrypt it. Therefore, interferences can occur. They are of several kinds.&lt;/p&gt;
&lt;h3 id=&#34;modifications-of-the-encrypted-data&#34;&gt;Modifications of the encrypted data&lt;/h3&gt;
&lt;p&gt;The first problem is that the encrypted data can be modified by an external program. Indeed, as soon as a file is visible in a directory, any program running with the necessary privileges can open a file descriptor on this file. Thanks to this file descriptor, it is then possible to modify the file. This includes programs running with the same privileges as the program that is in charge of decryption.&lt;/p&gt;
&lt;p&gt;This is not necessarily a problem. The state of the art in applied cryptography is to use authenticated encryption. This type of encryption verifies the cryptographic integrity of the encrypted content, while it decrypts it. Some algorithms and encryption modes, such as AES-GCM or AES-OCB, perform these operations in &amp;ldquo;one pass&amp;rdquo;. That is to say that the authenticity check is performed as the decryption proceeds and an authenticity verdict is given at the end of the decryption. Alas, not all encryption modes are one-pass; thus AES-CCM, for example, will first perform an integrity check (first pass) and then perform decryption (second pass) if the data was initially determined to be authentic. Unfortunately, an attacker is then able to alter the data between the first and second pass. The decrypted content is then declared authentic, even though it has been altered.&lt;/p&gt;
&lt;p&gt;Consequently, when a one-pass decryption mode is not used, it is necessary to use a private copy of the data, either in RAM or by other system tricks that will be detailed later in this document.&lt;/p&gt;
&lt;h3 id=&#34;early-use-of-data-whose-authenticity-is-not-yet-assured&#34;&gt;Early use of data whose authenticity is not yet assured&lt;/h3&gt;
&lt;p&gt;When the decrypted data is too large to be stored in RAM, it is necessary to write it to disk. Unfortunately, security problems can occur during this passage on disk.&lt;/p&gt;
&lt;p&gt;The list of these problems cannot be exhaustive, but it is possible to think of certain software that would use the data in an anticipated way. Indeed, some software monitors the contents of a folder with &lt;a href=&#34;https://man7.org/linux/man-pages/man7/inotify.7.html&#34;&gt;inotify(7)&lt;/a&gt; ; this is the case of most file explorers.&lt;/p&gt;
&lt;p&gt;This early reading can result in incorrect interpretations of the file. This is not the most unfortunate consequence, however. In the case of one-pass encryption, or integrity checking after decryption (see the OpenPGP section of this document), it is possible that the file containing the decrypted file contains malicious code added by an attacker who corrupted the encrypted document. It is indeed very important to understand that encryption alone is not sufficient to guarantee the integrity of a data, and that it is necessary to use an integrity pattern, and to verify it, before using the decrypted file. If the decrypted data is used before the authenticity verdict is given, then it is possible to exploit a vulnerability with a non-authentic document.&lt;/p&gt;
&lt;p&gt;Therefore, it is essential that the decrypted data remains private until the authenticity verdict is received. When it is stored in RAM, this is easy, but when it must be stored on disk, in the case of large files, then it is necessary to exploit some defensive strategies, discussed later in this document.&lt;/p&gt;
&lt;h2 id=&#34;size-reduction-by-fragmentation&#34;&gt;Size reduction by fragmentation&lt;/h2&gt;
&lt;p&gt;One possible strategy for encrypting/decrypting a large file may be to break it up into chunks that will fit in RAM.&lt;/p&gt;
&lt;p&gt;It might be tempting to look at encryption modes used for encrypting large amounts of data, like XTS. In a nutshell, XTS performs encryption/decryption using a single key, but it uses an encryption process that is &amp;ldquo;tweaked&amp;rdquo; to each logical unit. XTS is often used for disk encryption, and in this case the logical unit is the disk &amp;ldquo;sector&amp;rdquo;. Under Linux, it is possible to use XTS with dm-crypt and its LUKS overlay.&lt;/p&gt;
&lt;p&gt;XTS presents a rather interesting advantage for disk encryption. Indeed, the tweak for each logical unit is an intrinsic information about the disk: the position of the sector on the disk. This subtlety means that it is not necessary to store additional data (the tweak) for each sector. So there is no storage expense for encryption related data!&lt;/p&gt;
&lt;p&gt;Unfortunately, XTS offers limited integrity protection. Of course, if you take an encrypted sector and move it to another sector on the disk, the tweek of the algorithm will be incorrect. Indeed, if a sector is to be decrypted as sector X, and we try to decrypt it as sector Y, then the tweak will be incorrect, and the decryption will be meaningless. However, XTS does not protect against replacing sector X with an earlier version of sector X, for example.&lt;/p&gt;
&lt;p&gt;Moreover, by splitting the disk into encrypted sectors, each with a different tweak, there is no protection against truncation. If one takes a disk of size X and copies it to a disk of size Y, with Y &amp;lt; X, the cryptographic algorithm will not detect that data is missing.&lt;/p&gt;
&lt;p&gt;From the errors or constraints of disk encryption modes, several lessons can be learned. If the data to be encrypted/decrypted is too large to be stored in RAM, and the solution is to split it into chunks, then care must be taken to ensure that the integrity of the chunks is strong.&lt;/p&gt;
&lt;p&gt;This integrity must ensure that :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;each section cannot be modified individually, even by replacement with a section of another encrypted message of comparable size;&lt;/li&gt;
&lt;li&gt;the order of the sections cannot be modified;&lt;/li&gt;
&lt;li&gt;it is not possible to add or remove sections without the entire large file being considered invalid.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Problem number 1 can be easily solved by using a separate encryption/decryption key per encrypted file, in combination with an algorithm and encryption mode that results in an authenticated encryption, such as AES-GCM.&lt;/p&gt;
&lt;p&gt;Problem 2 can be easily solved by adding a counter to each encrypted data block. This represents a storage overhead that can be paid for when we are talking about file encryption and not disk encryption.&lt;/p&gt;
&lt;p&gt;It might be possible to create a tweakable encryption mode that is also authenticated, for example by combining XTS and an HMAC. Alas, the consequence would be that the cryptographic operations would be in two passes (XTS then HMAC), which is a potentially unnecessary computational overhead if a better solution is available (and it is; see below :)).&lt;/p&gt;
&lt;p&gt;Furthermore, XTS + HMAC would not protect against issue 3). Indeed, to counter 3), one method is to add the expected amount of chunks in the metadata of the encrypted file. This amount should be protected in integrity. This method is not original; it is used in the &lt;a href=&#34;https://en.wikipedia.org/wiki/Merkle%E2%80%93Damg%C3%A5rd_construction&#34;&gt;Merkle-Damgård cryptographic construction&lt;/a&gt;, and is used in particular by the SHA hash algorithms.&lt;/p&gt;
&lt;p&gt;All these additions are as many ways to make mistakes when performing the encryption and decryption steps. However, as stated in the chapter of this article, going off the beaten track is often synonymous with vulnerability.&lt;/p&gt;
&lt;p&gt;Therefore, it would be better not to reinvent the wheel, and to use well-known cryptographic mechanisms and libraries to solve our large file problem.&lt;/p&gt;
&lt;h2 id=&#34;cryptographic-libraries&#34;&gt;Cryptographic libraries&lt;/h2&gt;
&lt;p&gt;In Go, there are various high-level cryptographic libraries that are frequently used. Here I will talk about OpenPGP, which is problematic, and NACL, which is to be preferred.&lt;/p&gt;
&lt;h3 id=&#34;openpgp&#34;&gt;OpenPGP&lt;/h3&gt;
&lt;p&gt;OpenPGP is a fairly &lt;a href=&#34;https://www.rfc-editor.org/rfc/rfc4880.txt&#34;&gt;old encryption standard&lt;/a&gt;. Its main implementation is GnuPG, and it continues to be the hobby of some misguided technicians. Yes, I&amp;rsquo;m thinking in particular of you Linux distributions.&lt;/p&gt;
&lt;p&gt;These harsh words against this format are however deserved. OpenPGP is a museum of horrors, full of antiquated mechanisms, and cryptographic constructs from the infancy of authenticated encryption. Also, and not least, its implementers seem to have a passion for bad API ideas. In fact, the author of this article discovered &lt;a href=&#34;https://www.ssi.gouv.fr/uploads/2015/05/format-Oracles-on-OpenPGP.pdf&#34;&gt;problems in most OpenPGP implementations in 2015&lt;/a&gt;, and some, in 2022, are still vulnerable to these findings&amp;hellip; including GnuPG.&lt;/p&gt;
&lt;p&gt;In Go, unsurprisingly, the OpenPGP implementation also contains some bad ideas. The package has even been &lt;a href=&#34;https://github.com/golang/go/issues/44226&#34;&gt;frozen and deprecated&lt;/a&gt;, with the comment that it is not desirable for Go developers to use OpenPGP, as this format is &amp;ldquo;complex, fragile, and unsafe, and using it exposes applications to a dangerous ecosystem&amp;rdquo;. To make the point, we will study one of its problems.&lt;/p&gt;
&lt;p&gt;While it is true that it is fairly universal for data sources to implement &lt;a href=&#34;https://pkg.go.dev/io#Reader&#34;&gt;io.Reader&lt;/a&gt;, it is possible to question the relevance of this choice for an encrypted data source whose integrity can only be verified after a complete pass.&lt;/p&gt;
&lt;p&gt;One might expect the OpenPGP container &lt;a href=&#34;https://pkg.go.dev/golang.org/x/crypto/openpgp#MessageDetails&#34;&gt;openpgp.MessageDetails&lt;/a&gt; to perform this check on its own when instantiated with &lt;a href=&#34;https://pkg.go.dev/golang.org/x/crypto/openpgp#ReadMessage&#34;&gt;openpgp.ReadMessage&lt;/a&gt;. This would be quite consistent with the &lt;code&gt;encoding/gzip&lt;/code&gt; API whose &lt;a href=&#34;https://pkg.go.dev/compress/gzip#NewReader&#34;&gt;NewReader&lt;/a&gt; function returns an error if there are no &amp;ldquo;magic&amp;rdquo; bytes at the beginning of the read. Alas, as said before, OpenPGP is a museum of horrors, and it is not possible to check the integrity of the encrypted document; it is necessary to decrypt the entire encrypted document first, to finally recover an integrity tag. Indeed, with the OpenPGP standard, the integrity tab (a simple SHA-1 of the cleartext) is part of the encrypted data, and is suffixed to the cleartext. This approach is called &lt;a href=&#34;https://en.wikipedia.org/wiki/Authenticated_encryption#MAC-then-Encrypt_(MtE)&#34;&gt;MAC-then-encrypt&lt;/a&gt; and is decried by the cryptographic community.&lt;/p&gt;
&lt;p&gt;Although the &lt;code&gt;io.Reader&lt;/code&gt; of &lt;code&gt;openpgp.MessageDetails&lt;/code&gt; is stored in the aptly named &lt;code&gt;UnverifiedBody&lt;/code&gt; field, it is extremely tempting for a developer to plug it into another &lt;code&gt;io.Reader&lt;/code&gt;, like a series of decorators, and forget or discover too late that the message was not genuine!&lt;/p&gt;
&lt;h3 id=&#34;nacl&#34;&gt;NACL&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://pkg.go.dev/golang.org/x/crypto/nacl&#34;&gt;NACL&lt;/a&gt; is an excellent cryptographic library, whose well-designed API allows only the most stubborn of idiots to make mistakes in its use. There are some command line tools to exploit it or its fork &lt;a href=&#34;https://github.com/jedisct1/libsodium&#34;&gt;libsodium&lt;/a&gt;. One of them is the excellent &lt;a href=&#34;https://github.com/jedisct1/minisign&#34;&gt;minisign&lt;/a&gt; utility, by Frank Denis. The author of this article highly recommends minisign as a replacement for OpenPGP for signing documents!&lt;/p&gt;
&lt;p&gt;There are implementations of minisign in Go, such as &lt;a href=&#34;https://github.com/jedisct1/go-minisign&#34;&gt;go-minisign&lt;/a&gt;, which unfortunately suffers from the same problem of handling large files that we are dealing with in this article. Fortunately it is possible to use go-minisign even for large files by using the tricks presented in this article, below.&lt;/p&gt;
&lt;p&gt;Coming back to NACL, the &lt;a href=&#34;https://pkg.go.dev/golang.org/x/crypto@v0.0.0-20211215153901-e495a2d5b3d3/nacl/box#Seal&#34;&gt;box.Seal&lt;/a&gt; and &lt;a href=&#34;https://pkg.go.dev/golang.org/x/crypto@v0.0.0-20211215153901-e495a2d5b3d3/nacl/box#Open&#34;&gt;box.Open&lt;/a&gt; functions have the particularity of not reading from an &lt;code&gt;io.Reader&lt;/code&gt; and not writing to an &lt;code&gt;io.Writer&lt;/code&gt;. So they do not fall into the crude trap at the bottom of which we find OpenPGP. These functions use byte slices. This could look like a blocking point. This article aims precisely at proposing a solution to circumvent this particularity, while offering a correct level of security.&lt;/p&gt;
&lt;h2 id=&#34;system-tips-and-tricks-to-the-rescue&#34;&gt;System tips and tricks to the rescue&lt;/h2&gt;
&lt;h3 id=&#34;control-the-release-of-data&#34;&gt;Control the release of data&lt;/h3&gt;
&lt;p&gt;As seen at the beginning of this article, it is important to control when the decrypted data is released; until the data is complete and verified, the working copy of the data must remain private. Since we are dealing with large files, which do not fit in RAM, it is necessary to store the working copy on the file system, while ensuring that no other process or task can access it. To do this, it is possible to use anonymous files.&lt;/p&gt;
&lt;p&gt;Anonymous files are files that are stored on the file system without any links to them. By link, here, it is necessary to understand link in the sense &amp;ldquo;entry in a directory&amp;rdquo;: a hardlink. These files are created by specifying the &lt;code&gt;O_TMPFILE&lt;/code&gt; option to syscall &lt;a href=&#34;https://man7.org/linux/man-pages/man2/open.2.html&#34;&gt;open(2)&lt;/a&gt;. Any byte written to such a file is actually stored on the file system, via the file descriptor returned by open(2) and known only to the program that created it (and to the processes that will be poking around in /proc&amp;hellip; but they are looking for trouble ;)). It is therefore a private copy of the decrypted file. When the file is complete and its content verified, it is then possible to publish it through different ways.&lt;/p&gt;
&lt;p&gt;One way to publish the file in a not very elegant way is simply to create a new file, without the &lt;code&gt;O_TMPFILE&lt;/code&gt; option, and then to copy the contents of the decrypted file into this new file which is accessible by the other processes. The file descriptor can then be closed, and the anonymous file will be automatically freed. This method is expensive and has the drawback of doubling the disk size needed to store the decrypted file, at least temporarily, until the file descriptor of the anonymous file is closed.&lt;/p&gt;
&lt;p&gt;A more elegant way, which takes advantage of a feature that is not always available, is to use &lt;a href=&#34;https://man7.org/linux/man-pages/man2/ioctl_ficlone.2.html&#34;&gt;FICLONE&lt;/a&gt; of the syscall &lt;a href=&#34;https://man7.org/linux/man-pages/man2/ioctl.2.html&#34;&gt;ioctl(2)&lt;/a&gt;. &lt;code&gt;FICLONE&lt;/code&gt; uses the copy-on-write (COW) functionality of some file systems, such as &lt;a href=&#34;https://btrfs.wiki.kernel.org/index.php/Main_Page&#34;&gt;btrfs&lt;/a&gt;. With this syscall, it is possible to open a file with a hardlink and then request that the named file be a snapshot of the anonymous file. The two files will then share the same blocks of data on the file system, until one of them changes a block. But in this case, there will be no subsequent writing to the anonymous file after this call to ioctl(2). So this is simply a trick to link to the contents of the anonymous file, and thus publish it. The only drawback of this approach is that you have to use a file system that is compatible with &lt;code&gt;FICLONE&lt;/code&gt;, and this is not the case with ext4, which is usually the default file system of Linux distrubutions.&lt;/p&gt;
&lt;p&gt;Finally, there is a third method, also elegant, which does not take advantage of a particular feature of some file systems. Unfortunately, it requires certain system privileges to do so: &lt;a href=&#34;https://man7.org/linux/man-pages/man7/capabilities.7.html&#34;&gt;CAP_DAC_READ_SEARCH&lt;/a&gt;. &lt;code&gt;CAP_DAC_READ_SEARCH&lt;/code&gt; bypasses this file system protection, which is unfortunate, because it is also the privilege required to call the &lt;a href=&#34;https://man7.org/linux/man-pages/man2/linkat.2.html&#34;&gt;linkat(2)&lt;/a&gt; syscall, with the &lt;code&gt;AT_EMPTY_PATH&lt;/code&gt; option. This syscall together with this option allows the creation of a link from a file descriptor. It allows giving a name to our anonymous file, once it is complete. It may be acceptable to give &lt;code&gt;CAP_DAC_READ_SEARCH&lt;/code&gt; to our process, if it is running in a chroot in which this permission does not allow the program to gain or keep undue access to system resources. This solution is therefore probably acceptable under certain conditions, which must however be well controlled.&lt;/p&gt;
&lt;h2 id=&#34;decrypting-a-large-file-in-virtual-memory&#34;&gt;Decrypting a large file in virtual memory&lt;/h2&gt;
&lt;p&gt;Not everything that is in virtual memory is necessarily physical memory. Thus, it is possible to obtain a Go slice containing the contents of a file, without it being copied into RAM. In the same way, it is possible to write in a slice, which is not stored in RAM, thanks to a syscall: &lt;a href=&#34;https://man7.org/linux/man-pages/man2/mmap.2.html&#34;&gt;mmap(2)&lt;/a&gt;. So we can call &lt;code&gt;box.Seal&lt;/code&gt; and &lt;code&gt;box.Open&lt;/code&gt; on such slices, and the result will have been computed without the content of the files being stored in RAM!&lt;/p&gt;
&lt;p&gt;Unfortunately, things are never that &amp;ldquo;simple&amp;rdquo;. There are some additional subtleties required when performing this write operation to a slice pointing to a file placed in virtual memory with mmap(2). Firstly, it is necessary that the destination file is the right size before calling mmap(2). To do this, a sparse file can be created, using the &lt;a href=&#34;https://man7.org/linux/man-pages/man1/fallocate.1.html&#34;&gt;fallocate(2)&lt;/a&gt; syscall. Then, once the writing to the slice is done, it is necessary to call the &lt;a href=&#34;https://man7.org/linux/man-pages/man2/msync.2.html&#34;&gt;msync(2)&lt;/a&gt; syscall in order to force the transfer of data from the virtual memory to the file, before making the call to munmap(2), to free the slice created by mmap(2).&lt;/p&gt;
&lt;p&gt;Similarly, mmap(2) should used for the encrypted file, but there are some subtleties here as well. In particular, it is better to work on a private copy of the file, rather than one that can be altered by an external source. Indeed, the behavior is not specified if an external program truncates the file after it has been passed to mmap(2).&lt;/p&gt;
&lt;p&gt;Finally, when passing the slice receiving the decrypted data to &lt;code&gt;box.Open&lt;/code&gt;, one must pass this slice with [:0], in order to keep the capacity of the slice equal to the size of the file, but to force its length to 0. By doing this, &lt;code&gt;box.Open&lt;/code&gt; will not proceed to reallocations of the array underlying the slice. It is indeed very important to use this trick, in order to continue working in the virtual memory returned by mmap(2) and not to end up working accidentally in RAM.&lt;/p&gt;
&lt;h2 id=&#34;bringing-it-all-together-in-a-coherent-program&#34;&gt;Bringing it all together in a coherent program&lt;/h2&gt;
&lt;p&gt;To summarize everything that has been discussed in this article:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;when dealing with a large file, it is better to use Linux efficiently than to risk creating vulnerabilities by trying to truncate the file;&lt;/li&gt;
&lt;li&gt;it is important to always work with private copies of the data, both the encrypted and decrypted content;&lt;/li&gt;
&lt;li&gt;it is necessary to have control over the publication of the decrypted content, in particular to ensure that the content has integrity and is complete before making it available to third-party applications.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To accomplish these goals, it is possible to use the Linux syscalls mmap(2), fallocate(2), msync(2), and ioctl(2) or linkat(2).&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/X-Cli/large-file-decrypt&#34;&gt;This git repository&lt;/a&gt; contains a library using all these elements to encrypt and decrypt a large file in a secure way.&lt;/p&gt;</description>
		</item>
		<item>
			<title>Déchiffrement sécurisé de gros fichiers en Go</title>
			<link>https://broken-by-design.fr/posts/large-file-decrypt/</link>
			<pubDate>Mon, 10 Jan 2022 00:00:00 +0000</pubDate>
			<guid isPermaLink="true">https://broken-by-design.fr/posts/large-file-decrypt/</guid>
			<description>&lt;p&gt;L&amp;rsquo;on dit souvent qu&amp;rsquo;il ne faut pas créer son propre algorithme cryptographique. Qu&amp;rsquo;en cryptographie, il ne faut pas faire preuve d&amp;rsquo;originalité ; que la sécurité est dans les sentiers battus, et en particulier ceux qui le sont par les cryptographes. Ce qu&amp;rsquo;on oublie souvent de dire, c&amp;rsquo;est qu&amp;rsquo;utiliser la cryptographie est aussi périlleux. Dans cet article, nous allons discuter du traitement des gros fichiers lors du déchiffrement, et de comment le faire de manière sécurisée sur un système Linux. Cet article sera illustré par du code Go.&lt;/p&gt;
&lt;h2 id=&#34;quest-ce-quun-gros-fichier-et-en-quoi-cela-est-il-différent-des-petits-fichiers-&#34;&gt;Qu&amp;rsquo;est ce qu&amp;rsquo;un &amp;ldquo;gros fichier&amp;rdquo; et en quoi cela est-il différent des &amp;ldquo;petits fichiers&amp;rdquo; ?&lt;/h2&gt;
&lt;p&gt;Un petit fichier est tout ce qu&amp;rsquo;il est raisonnable de stocker en RAM, en intégralité. La RAM est un espace sanctuarisé où un programme peut stocker de l&amp;rsquo;information. Cette sanctuarisation offre avec une garantie relativement forte d&amp;rsquo;isolation contre les interférences provenant d&amp;rsquo;autres tâches/processus.&lt;/p&gt;
&lt;p&gt;À l&amp;rsquo;inverse, un gros fichier est un fichier qui ne peut être stocké dans son intégralité dans la RAM du système qui va le déchiffrer. Dès lors des interférences peuvent survenir. Elles sont de plusieurs ordres.&lt;/p&gt;
&lt;h3 id=&#34;les-modifications-de-la-donnée-chiffrée&#34;&gt;Les modifications de la donnée chiffrée&lt;/h3&gt;
&lt;p&gt;Le premier problème est que la donnée chiffrée peut être modifiée par un programme externe. En effet, dès lors qu&amp;rsquo;un fichier est présent dans un répertoire, tout programme tournant avec les privilèges nécessaires peut ouvrir un descripteur de fichiers (&lt;em&gt;file descriptor&lt;/em&gt;) sur ce fichier. Grâce à ce descripteur de fichiers, il est alors possible de modifier le fichier. Cela inclut les programmes tournant avec le même niveau de privilèges que le programme qui est en charge du déchiffrement.&lt;/p&gt;
&lt;p&gt;Ce n&amp;rsquo;est pas forcément un problème. L&amp;rsquo;état de l&amp;rsquo;art en matière de cryptographie appliquée est d&amp;rsquo;utiliser du chiffrement authentifié. Ce type de chiffrement vérifie l&amp;rsquo;intégrité cryptographique du contenu chiffré, en même temps qu&amp;rsquo;il le déchiffre. Certains algorithmes et modes de chiffrement, comme AES-GCM ou AES-OCB, effectuent ces opérations en &amp;ldquo;une passe&amp;rdquo;. C&amp;rsquo;est-à-dire que la vérification de l&amp;rsquo;authenticité est effectuée au fur et à mesure du déchiffrement et un verdict d&amp;rsquo;authenticité est donné à la fin du déchiffrement. Hélas, tous les modes de chiffrement ne sont pas en une passe ; ainsi AES-CCM, par exemple, va d&amp;rsquo;abord effectuer une vérification en intégrité, puis effectuer le déchiffrement si la donnée a initialement été déterminée comme authentique. Hélas, un attaquant est alors en mesure d&amp;rsquo;altérer la donnée entre la première et la deuxième passe. Le contenu déchiffré est alors déclaré authentique, alors que ce dernier a été modifié.&lt;/p&gt;
&lt;p&gt;En conséquence, lorsqu&amp;rsquo;un mode de déchiffrement en une passe n&amp;rsquo;est pas employé, il est nécessaire d&amp;rsquo;utiliser une copie privée de la donnée, que ce soit en RAM ou par d&amp;rsquo;autres astuces systèmes qui seront détaillées ultérieurement dans ce document.&lt;/p&gt;
&lt;h3 id=&#34;utilisation-anticipée-dune-donnée-dont-lauthenticité-nest-pas-encore-assurée&#34;&gt;Utilisation anticipée d&amp;rsquo;une donnée dont l&amp;rsquo;authenticité n&amp;rsquo;est pas encore assurée&lt;/h3&gt;
&lt;p&gt;Lorsque les données déchiffrées sont trop grandes pour être contenues en RAM, il est nécessaire de les écrire sur disque. Hélas, des problèmes de sécurité peuvent survenir lors de ce passage sur disque.&lt;/p&gt;
&lt;p&gt;La liste de ces problèmes ne saurait être exhaustive, mais il est possible de penser notamment à certains logiciels qui utiliseraient la donnée de manière anticipée. En effet, certains logiciels surveillent le contenu d&amp;rsquo;un dossier avec &lt;a href=&#34;https://man7.org/linux/man-pages/man7/inotify.7.html&#34;&gt;inotify(7)&lt;/a&gt; ; c&amp;rsquo;est le cas de la plupart des explorateurs de fichiers.&lt;/p&gt;
&lt;p&gt;Cette lecture anticipée peut résulter en des interprétations incorrectes du fichier. Ce n&amp;rsquo;est cependant pas la conséquence la plus funeste. Dans le cas d&amp;rsquo;un chiffrement en une passe, ou d&amp;rsquo;une vérification d&amp;rsquo;intégrité effectuée après le déchiffrement (c.f. la section de ce document relative à OpenPGP), il est possible que le fichier contenant le déchiffré intègre du code malveillant ajouté par un attaquant ayant corrompu le document chiffré. Il est, en effet, capital de comprendre que le chiffrement seul n&amp;rsquo;est pas suffisant pour garantir l&amp;rsquo;intégrité d&amp;rsquo;une donnée, et qu&amp;rsquo;il est nécessaire d&amp;rsquo;utiliser un motif d&amp;rsquo;intégrité, et de le vérifier, avant de faire usage du déchiffré.
S&amp;rsquo;il est fait usage de la donnée déchiffrée avant que le verdict d&amp;rsquo;authenticité ne soit rendu, alors il est possible d&amp;rsquo;exploiter une vulnérabilité avec un document non-authentique.&lt;/p&gt;
&lt;p&gt;En conséquence, il est indispensable que le déchiffré reste privé, jusqu&amp;rsquo;à réception du verdict d&amp;rsquo;authenticité. Lorsqu&amp;rsquo;il est stocké en RAM, c&amp;rsquo;est chose aisée, mais lorsqu&amp;rsquo;il doit être stocké sur le disque, dans le cas des gros fichiers, alors il est nécessaire d&amp;rsquo;exploiter quelques stratégies défensives, discutées plus bas dans ce document.&lt;/p&gt;
&lt;h2 id=&#34;réduction-de-la-taille-par-fragmentation&#34;&gt;Réduction de la taille par fragmentation&lt;/h2&gt;
&lt;p&gt;Une stratégie possible pour chiffrer/déchiffrer un gros fichier peut être de le découper en tronçons qui tiendront en RAM.&lt;/p&gt;
&lt;p&gt;Il pourrait être tentant de regarder du côté des modes de chiffrement utilisés pour le chiffrement de vastes quantité de données, comme XTS. En quelques mots, XTS effectue un chiffrement/déchiffrement à l&amp;rsquo;aide d&amp;rsquo;une unique clé, mais d&amp;rsquo;un procédé de chiffrement qui est ajusté (&amp;ldquo;tweaked&amp;rdquo;) à chaque unité logique. XTS est souvent employé pour le chiffrement de disques, et dans ce cas, l&amp;rsquo;unité logique est le &amp;ldquo;secteur&amp;rdquo; du disque. Sous Linux, il est possible de faire usage de XTS notamment avec dm-crypt et sa surcouche LUKS.&lt;/p&gt;
&lt;p&gt;XTS présente un avantage assez intéressant pour le chiffrement de disques. En effet, l&amp;rsquo;élément qui permet de paramétrer l&amp;rsquo;ajustement (tweak) pour chaque unité logique est une donnée extérieure et intrinsèque du disque : la position du secteur sur le disque. Cette subtilité fait qu&amp;rsquo;il n&amp;rsquo;est pas nécessaire de stocker une donnée supplémentaire (les paramètres d&amp;rsquo;ajustement) pour chaque secteur. Il n&amp;rsquo;y a donc pas de dépense de stockage pour des données liées au chiffrement !&lt;/p&gt;
&lt;p&gt;Hélas, XTS offre une protection en intégrité limitée. Certes, si l&amp;rsquo;on prend un secteur chiffré et qu&amp;rsquo;on le déplace dans un autre secteur du disque, les paramètres d&amp;rsquo;ajustement de l&amp;rsquo;algorithme vont être incorrects. En effet, si un secteur doit être déchiffré en tant que secteur X, et qu&amp;rsquo;on tente de le déchiffrer en tant que secteur Y, alors les paramètres de l&amp;rsquo;algorithme seront incorrects, et le déchiffré n&amp;rsquo;aura aucun sens. Cependant XTS ne protège pas contre le remplacement du secteur X par une version antérieure du secteur X, par exemple.&lt;/p&gt;
&lt;p&gt;En outre, en découpant le disque en secteurs chiffrés, chacun avec un paramètre différent, il n&amp;rsquo;existe pas de protection contre la troncature. Si l&amp;rsquo;on prend un disque de taille X et qu&amp;rsquo;on le copie sur un disque de taille Y, avec Y &amp;lt; X, l&amp;rsquo;algorithme cryptographique ne détectera pas qu&amp;rsquo;il manque de la donnée.&lt;/p&gt;
&lt;p&gt;Des erreurs ou contraintes des modes de chiffrement de disques, plusieurs leçons peuvent être tirées. Si l&amp;rsquo;on dispose d&amp;rsquo;une donnée à chiffrer/déchiffrer qui est trop grande pour être stockée en RAM, et que la solution envisagée est de découper cette donnée en tronçon, alors il faut veiller à mettre en place une intégrité forte des tronçons.&lt;/p&gt;
&lt;p&gt;Cette intégrité doit assurer que :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;chaque tronçon ne peut être modifié individuellement, même par remplacement avec un tronçon d&amp;rsquo;un autre message chiffré de taille comparable ;&lt;/li&gt;
&lt;li&gt;l&amp;rsquo;ordre des tronçons ne peut être modifié ;&lt;/li&gt;
&lt;li&gt;il n&amp;rsquo;est pas possible d&amp;rsquo;ajouter ou de retirer des tronçons sans que l&amp;rsquo;ensemble du gros fichier ne soit considéré comme invalide.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;La problématique numéro 1 peut être aisément résolue en utilisant une clé de chiffrement/déchiffrement distincte par fichier chiffré, en combinaison avec un algorithme et un mode de chiffrement qui permette d&amp;rsquo;obtenir un chiffré authentifié, comme AES-GCM.&lt;/p&gt;
&lt;p&gt;La problématique 2 peut être aisément résolue en ajoutant un compteur à chaque bloc de données chiffré. Cela représente un surcoût de stockage qu&amp;rsquo;il est possible de payer quand on parle de chiffrement de fichiers et non de chiffrement de disques.&lt;/p&gt;
&lt;p&gt;Il pourrait être envisageable de créer un mode de chiffrement ajustable qui soit également authentifié, par exemple en combinant XTS et un HMAC. Hélas, la conséquence serait que les opérations cryptographiques seraient en deux passes (XTS puis HMAC), ce qui représente un surcoût potentiellement inutile si une meilleure solution est disponible (et c&amp;rsquo;est le cas ; voir ci-dessous :)).&lt;/p&gt;
&lt;p&gt;En outre, XTS + HMAC ne protègerait pas contre la problématique 3). En effet, pour protéger contre cette dernière, une méthode est d&amp;rsquo;ajouter la quantité de tronçons attendue en meta-données du fichier. Cette quantité devrait être protégée en intégrité. Cette méthode n&amp;rsquo;est pas originale ; elle est utilisée dans la construction cryptographique &lt;a href=&#34;https://en.wikipedia.org/wiki/Merkle%E2%80%93Damg%C3%A5rd_construction&#34;&gt;Merkle-Damgård&lt;/a&gt;, et est employée notamment par les algorithmes de hachage SHA.&lt;/p&gt;
&lt;p&gt;Tous ces ajouts sont autant de manière de se tromper lorsqu&amp;rsquo;on réalise les étapes de chiffrement et de déchiffrement. Or, comme dit en chapô de cet article, sortir des sentiers battus est souvent synonyme de vulnérabilité.&lt;/p&gt;
&lt;p&gt;Dès lors, il serait préférable de ne pas réinventer la roue, et d&amp;rsquo;employer des mécanismes et des bibliothèques cryptographiques bien connues pour résoudre notre problématique de gros fichiers.&lt;/p&gt;
&lt;h2 id=&#34;les-bibliothèques-cryptographiques&#34;&gt;Les bibliothèques cryptographiques&lt;/h2&gt;
&lt;p&gt;En Go, il existe diverses bibliothèques cryptographiques haut-niveau qui sont fréquemment employées. Je vais ici parler d&amp;rsquo;OpenPGP, qui est problématique, et de NACL, qu&amp;rsquo;il convient de préférer.&lt;/p&gt;
&lt;h3 id=&#34;openpgp&#34;&gt;OpenPGP&lt;/h3&gt;
&lt;p&gt;OpenPGP est un &lt;a href=&#34;https://www.rfc-editor.org/rfc/rfc4880.txt&#34;&gt;standard de chiffrement assez ancien&lt;/a&gt;. Son implémentation principale est GnuPG, et il continue d&amp;rsquo;être la marotte de certains techniciens bien mal avisés. Oui, je pense notamment à vous, les distributions Linux.&lt;/p&gt;
&lt;p&gt;Ces mots durs contre ce format sont cependant mérités. OpenPGP est un musée des horreurs, remplis de mécanismes vétustes, et de constructions cryptographiques datant des balbutiements du chiffrement authentifié. Également, et non des moindres, ses implémenteurs semblent avoir une passion pour les mauvaises idées en matière d&amp;rsquo;API. L&amp;rsquo;auteur de cet article a d&amp;rsquo;ailleurs découvert &lt;a href=&#34;https://www.ssi.gouv.fr/uploads/2015/05/format-Oracles-on-OpenPGP.pdf&#34;&gt;en 2015 des problèmes dans la plupart des implémentations d&amp;rsquo;OpenPGP&lt;/a&gt;, et certaines, en 2022, sont toujours vulnérables à ces découvertes&amp;hellip; dont GnuPG.&lt;/p&gt;
&lt;p&gt;En Go, sans surprise, l&amp;rsquo;implémentation d&amp;rsquo;OpenPGP contient elle aussi de mauvaises idées. Le package a même été &lt;a href=&#34;https://github.com/golang/go/issues/44226&#34;&gt;gêlé et déprécié&lt;/a&gt;, avec le commentaire qu&amp;rsquo;il n&amp;rsquo;est pas souhaitable que les développeurs Go emploient OpenPGP, ce format étant &amp;ldquo;fragile, complexe, non sûr, et [&amp;hellip;] son usage expose les développeurs à un écosystème dangereux&amp;rdquo;. Pour enfoncer le clou, nous allons procéder à une étude de l&amp;rsquo;une de ses problématiques.&lt;/p&gt;
&lt;p&gt;S&amp;rsquo;il est vrai qu&amp;rsquo;il est assez universel que des sources de données implémentent &lt;a href=&#34;https://pkg.go.dev/io#Reader&#34;&gt;io.Reader&lt;/a&gt;, il est possible de s&amp;rsquo;interroger sur la pertinence de ce choix pour une source de données chiffrée dont l&amp;rsquo;intégrité ne peut être vérifiée qu&amp;rsquo;après une passe complète.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;on pourrait alors s&amp;rsquo;attendre à ce que le containeur OpenPGP &lt;a href=&#34;https://pkg.go.dev/golang.org/x/crypto/openpgp#MessageDetails&#34;&gt;openpgp.MessageDetails&lt;/a&gt; effectue cette vérification de lui-même lors de son instanciation avec &lt;a href=&#34;https://pkg.go.dev/golang.org/x/crypto/openpgp#ReadMessage&#34;&gt;openpgp.ReadMessage&lt;/a&gt;. Cela serait assez cohérent avec l&amp;rsquo;API de encoding/gzip dont la fonction &lt;a href=&#34;https://pkg.go.dev/compress/gzip#NewReader&#34;&gt;NewReader&lt;/a&gt; renvoie une erreur en l&amp;rsquo;absence d&amp;rsquo;octets &amp;ldquo;magiques&amp;rdquo; en début de lecture. Hélas, comme dit précemment, OpenPGP est un musée des horreurs, et il n&amp;rsquo;est pas possible de vérifier l&amp;rsquo;intégrité du chiffré ; il est nécessaire de déchiffrer l&amp;rsquo;intégralité du document chiffré, pour récupérer enfin un motif d&amp;rsquo;intégrité. En effet, avec le standard OpenPGP, le motif d&amp;rsquo;intégrité (un simple SHA-1 du clair) fait partie des données chiffrées, et est suffixé au clair. Cette approche est appelée &lt;a href=&#34;https://en.wikipedia.org/wiki/Authenticated_encryption#MAC-then-Encrypt_(MtE)&#34;&gt;MAC-then-encrypt&lt;/a&gt; et est décriée par la communauté cryptographique.&lt;/p&gt;
&lt;p&gt;Bien que le io.Reader de openpgp.MessageDetails soit stocké dans le bien-nommé champ UnverifiedBody, il est extrêmement tentant pour un développeur de le &amp;ldquo;brancher&amp;rdquo; dans un autre io.Reader, à la manière d&amp;rsquo;une série de décorateurs, et d&amp;rsquo;oublier ou de découvrir trop tard que le message n&amp;rsquo;était pas intègre !&lt;/p&gt;
&lt;h3 id=&#34;nacl&#34;&gt;NACL&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://pkg.go.dev/golang.org/x/crypto/nacl&#34;&gt;NACL&lt;/a&gt; est une excellente bibliothèque cryptographique, dont l&amp;rsquo;API, bien conçue, ne permet qu&amp;rsquo;aux plus entêtés des idiots de se tromper dans son emploi. Il existe quelques outils en ligne de commande pour l&amp;rsquo;exploiter, elle ou sa variante (&lt;em&gt;fork&lt;/em&gt;) &lt;a href=&#34;https://github.com/jedisct1/libsodium&#34;&gt;libsodium&lt;/a&gt;. On peut notamment citer l&amp;rsquo;excellent utilitaire &lt;a href=&#34;https://github.com/jedisct1/minisign&#34;&gt;minisign&lt;/a&gt;, par Frank Denis. L&amp;rsquo;auteur de cet article recommande vivement minisign comme remplacement à OpenPGP pour la signature de documents !&lt;/p&gt;
&lt;p&gt;Il existe des implémentations de minisign en Go, dont &lt;a href=&#34;https://github.com/jedisct1/go-minisign&#34;&gt;go-minisign&lt;/a&gt;, qui hélas souffre du même problème de gestion des gros fichiers qui nous occupe dans cet article. Fort heureusement il est possible d&amp;rsquo;exploiter go-minisign y compris pour des gros fichiers en utilisant les astuces qui sont présentées dans le présent article, plus bas.&lt;/p&gt;
&lt;p&gt;Pour en revenir à NACL, les fonctions &lt;a href=&#34;https://pkg.go.dev/golang.org/x/crypto@v0.0.0-20211215153901-e495a2d5b3d3/nacl/box#Seal&#34;&gt;box.Seal&lt;/a&gt; et &lt;a href=&#34;https://pkg.go.dev/golang.org/x/crypto@v0.0.0-20211215153901-e495a2d5b3d3/nacl/box#Open&#34;&gt;box.Open&lt;/a&gt; ont pour particularité de ne pas recevoir d&amp;rsquo;io.Reader et d&amp;rsquo;écrire dans des io.Writer. Elles ne tombent donc pas dans le piège grossier au fond duquel on trouve OpenPGP. Ces fonctions utilisent des &lt;em&gt;slices&lt;/em&gt; de &lt;em&gt;bytes&lt;/em&gt;. Cela pourrait ressembler à un point bloquant. Cet article vise précisément à proposer une solution pour contourner cette particularité, tout en offrant un niveau de sécurité correct.&lt;/p&gt;
&lt;h2 id=&#34;astuces-systèmes-à-la-rescousse&#34;&gt;Astuces systèmes à la rescousse&lt;/h2&gt;
&lt;h3 id=&#34;contrôler-la-mise-à-disposition-des-données&#34;&gt;Contrôler la mise à disposition des données&lt;/h3&gt;
&lt;p&gt;Comme vu en début d&amp;rsquo;article, il est important de maitriser le moment où les données déchiffrées sont publiées ; tant que ces dernières ne sont pas complètes ou pas vérifiées, la copie de travail de ces données doit rester privée. Vu que nous traitons des gros fichiers, qui ne tiennent pas en RAM, il est nécessaire de stocker la copie de travail sur le système de fichiers, tout en s&amp;rsquo;assurant que nul autre processus ou tâche ne puisse y avoir accès. Pour ce faire, il est possible d&amp;rsquo;utiliser les fichiers anonymes.&lt;/p&gt;
&lt;p&gt;Les fichiers anonymes sont des fichiers qui sont stockés sur le système de fichiers, sans qu&amp;rsquo;aucun lien n&amp;rsquo;existe vers ces derniers. Par lien, ici, il faut comprendre lien dans le sens &amp;ldquo;entrée dans un répertoire&amp;rdquo; (&lt;em&gt;hardlink&lt;/em&gt;). Ces fichiers sont créés en spécifiant l&amp;rsquo;option O_TMPFILE au &lt;em&gt;syscall&lt;/em&gt; &lt;a href=&#34;https://man7.org/linux/man-pages/man2/open.2.html&#34;&gt;open(2)&lt;/a&gt;. Tout octet écrit dans un tel fichier est effectivement stocké sur le système de fichiers, par l&amp;rsquo;intermédiaire du descripteur de fichier renvoyé par open(2) et connu uniquement du programme qui l&amp;rsquo;a créé (et des processus qui vont farfouiller dans /proc&amp;hellip; mais ils cherchent les problèmes ;)). Il s&amp;rsquo;agit donc d&amp;rsquo;une copie privée du déchiffré. Lorsque le fichier est complet et son contenu vérifié, il est alors possible de le publier de différentes manières.&lt;/p&gt;
&lt;p&gt;Une manière de publier le fichier d&amp;rsquo;une manière peu élégante est simplement de créer un nouveau fichier, sans l&amp;rsquo;option O_TMPFILE, puis de recopier le contenu du fichier déchiffré dans ce nouveau fichier qui est accessible par les autres processus. Le descripteur de fichiers peut alors être fermé, et le fichier anonyme sera automatiquement libéré. Cette méthode est couteuse et présente le défaut de doubler la taille disque nécessaire pour stocker le déchiffré, au moins temporairement, jusqu&amp;rsquo;à la fermeture du descripteur de fichier du fichier anonyme.&lt;/p&gt;
&lt;p&gt;Une manière plus élégante, qui tire cependant partie d&amp;rsquo;une fonctionnalité qui n&amp;rsquo;est pas toujours disponible, est d&amp;rsquo;utiliser &lt;a href=&#34;https://man7.org/linux/man-pages/man2/ioctl_ficlone.2.html&#34;&gt;FICLONE&lt;/a&gt; du &lt;em&gt;syscall&lt;/em&gt; &lt;a href=&#34;https://man7.org/linux/man-pages/man2/ioctl.2.html&#34;&gt;ioctl(2)&lt;/a&gt;. FICLONE utilise la fonctionnalité de copy-on-write (COW) de certains systèmes de fichiers, comme &lt;a href=&#34;https://btrfs.wiki.kernel.org/index.php/Main_Page&#34;&gt;btrfs&lt;/a&gt;. Avec ce &lt;em&gt;syscall&lt;/em&gt;, il est possible d&amp;rsquo;ouvrir un fichier ayant un lien (&lt;em&gt;hardlink&lt;/em&gt;) puis de demander que le fichier nommé soit une copie instantanée du fichier anonyme. Les deux fichiers partageront alors les mêmes blocs de données sur le système de fichiers, jusqu&amp;rsquo;à ce que l&amp;rsquo;un d&amp;rsquo;entre eux modifie un bloc. Mais en l&amp;rsquo;espèce, il n&amp;rsquo;y aura pas d&amp;rsquo;écriture ultérieure dans le fichier anonyme, après cet appel à ioctl(2). Il s&amp;rsquo;agit donc simplement d&amp;rsquo;une astuce qui permet de créer un lien vers le contenu du fichier anonyme, et donc de le publier.
Le seul défaut de cette approche est qu&amp;rsquo;il faut utiliser un système de fichier compatible avec FICLONE, et ce n&amp;rsquo;est notamment pas le cas de ext4, qui est généralement le système de fichiers par défaut des distrubutions Linux.&lt;/p&gt;
&lt;p&gt;Finalement, il existe une troisième méthode, elle aussi élégante, qui ne tire par partie d&amp;rsquo;une fonctionnalité particulière de certains systèmes de fichiers. Hélas, il est nécessaire de disposer de certains privilèges système pour ce faire : &lt;a href=&#34;https://man7.org/linux/man-pages/man7/capabilities.7.html&#34;&gt;CAP_DAC_READ_SEARCH&lt;/a&gt;. &lt;code&gt;CAP_DAC_READ_SEARCH&lt;/code&gt; permet de contourner cette protection du système de fichiers, ce qui est regrettable, car il s&amp;rsquo;agit aussi du privilège requis pour appeler le syscall &lt;a href=&#34;https://man7.org/linux/man-pages/man2/linkat.2.html&#34;&gt;linkat(2)&lt;/a&gt;, avec l&amp;rsquo;option &lt;code&gt;AT_EMPTY_PATH&lt;/code&gt;. Ce syscall cumulé à cette option permet de créer un lien à partir d&amp;rsquo;un descripteur de fichiers. Il permet donc de donner un nom à notre fichier anonyme, une fois celui-ci complet. Il peut être acceptable de donner &lt;code&gt;CAP_DAC_READ_SEARCH&lt;/code&gt; à notre processus, si ce dernier est exécuté dans un &lt;a href=&#34;https://man7.org/linux/man-pages/man2/chroot.2.html&#34;&gt;chroot&lt;/a&gt; dans lequel cette permission ne permet pas au programme de gagner ou conserver des accès indûs à des ressources du système. Cette solution est donc probablement acceptable dans certaines conditions, qui doivent cependant être bien maitrisées.&lt;/p&gt;
&lt;h3 id=&#34;travailler-sur-une-copie-inaltérable-du-chiffré&#34;&gt;Travailler sur une copie inaltérable du chiffré&lt;/h3&gt;
&lt;p&gt;Dans le cas d&amp;rsquo;un procédé de déchiffrement en deux passes, une pour la vérification d&amp;rsquo;intégrité, et une pour le déchiffrement en lui-même, il est possible d&amp;rsquo;utiliser les mêmes mécanismes que détaillés dans la section précédente de cet article pour obtenir une copie privée : créer un fichier anonyme dont le contenu sera alimenté par recopie (avec un surcoût en espace disque) ou le syscall ioctl(2) avec FICLONE pour obtenir une copie instantanée et qui ne pourra être modifiée par des processus ou taches tiers.&lt;/p&gt;
&lt;h3 id=&#34;déchiffrer-un-gros-fichier-en-mémoire-virtuelle&#34;&gt;Déchiffrer un gros fichier en mémoire virtuelle&lt;/h3&gt;
&lt;p&gt;Tout ce qui est dans la mémoire virtuelle n&amp;rsquo;est pas nécessairement de la mémoire physique. Ainsi, il est possible d&amp;rsquo;obtenir une &lt;em&gt;slice&lt;/em&gt; Go comportant le contenu d&amp;rsquo;un fichier, sans que celui-ci ne soit lu et recopié en RAM. De même, il est possible d&amp;rsquo;écrire dans une &lt;em&gt;slice&lt;/em&gt;, qui n&amp;rsquo;est pas stocké en RAM, grâce à un &lt;em&gt;syscall&lt;/em&gt; : &lt;a href=&#34;https://man7.org/linux/man-pages/man2/mmap.2.html&#34;&gt;mmap(2)&lt;/a&gt;. Il nous est donc possible d&amp;rsquo;appeler &lt;code&gt;box.Seal&lt;/code&gt; et &lt;code&gt;box.Open&lt;/code&gt; sur de telles &lt;em&gt;slices&lt;/em&gt;, et le résultat aura été calculé sans que le contenu des fichiers ne soit stocké en intégralité en RAM !&lt;/p&gt;
&lt;p&gt;Hélas, les choses ne sont jamais aussi &amp;ldquo;simples&amp;rdquo;. Il a quelques petites subtilités supplémentaires, requises lorsqu&amp;rsquo;on effectue cette opération d&amp;rsquo;écriture dans une &lt;em&gt;slice&lt;/em&gt; pointant vers un fichier placé en mémoire virtuelle avec mmap(2). D&amp;rsquo;une part, il est nécessaire que le fichier de destination soit de la bonne taille avant l&amp;rsquo;appel à mmap(2). Pour cela, on peut créer un fichier creux (&lt;em&gt;sparse file&lt;/em&gt;), à l&amp;rsquo;aide de l&amp;rsquo;appel système &lt;a href=&#34;https://man7.org/linux/man-pages/man1/fallocate.1.html&#34;&gt;fallocate(2)&lt;/a&gt;. Ensuite, une fois l&amp;rsquo;écriture dans la &lt;em&gt;slice&lt;/em&gt; accomplie, il est nécessaire d&amp;rsquo;appeler le &lt;em&gt;syscall&lt;/em&gt; &lt;a href=&#34;https://man7.org/linux/man-pages/man2/msync.2.html&#34;&gt;msync(2)&lt;/a&gt; afin de forcer le transfert de données depuis la mémoire virtuelle vers le fichier, avant d&amp;rsquo;effectuer l&amp;rsquo;appel à munmap(2), pour &amp;ldquo;défaire&amp;rdquo; la &lt;em&gt;slice&lt;/em&gt; créée par mmap(2).&lt;/p&gt;
&lt;p&gt;De même, mmap(2) est utilisé pour le fichier chiffré, mais il y a là aussi quelques subtilités. Il est notamment préférable de travailler sur une copie privée du fichier, plutôt qu&amp;rsquo;un fichier altérable par une source externe. En effet, le comportement n&amp;rsquo;est pas spécifié si un programme externe tronquait le fichier après que ce dernier ait été passé à mmap(2).&lt;/p&gt;
&lt;p&gt;Enfin, lorsqu&amp;rsquo;on passe la &lt;em&gt;slice&lt;/em&gt; recevant les données déchiffrées à &lt;code&gt;box.Open&lt;/code&gt;, il convient de passer cette &lt;em&gt;slice&lt;/em&gt; découpée avec [:0], afin de garder la capacité de la &lt;em&gt;slice&lt;/em&gt; égale à la taille du fichier, mais de forcer sa longueur à 0. Ce faisant, &lt;code&gt;box.Open&lt;/code&gt; ne procèdera pas à des réallocations du tableau qui sous-tend la &lt;em&gt;slice&lt;/em&gt;. Il est, en effet, capital d&amp;rsquo;user de cette astuce, afin de continuer de travailler dans la mémoire virtuelle retournée par mmap(2) et ne pas se retrouver à travailler accidentellement en RAM.&lt;/p&gt;
&lt;h2 id=&#34;rassembler-tout-en-un-programme-cohérent&#34;&gt;Rassembler tout en un programme cohérent&lt;/h2&gt;
&lt;p&gt;Pour résumer tout ce qui a été abordé dans cet article :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pour traiter un gros fichier, il est préférable d&amp;rsquo;utiliser efficacement Linux que de risquer de créer des vulnérabilités en essayant de tronçonner le fichier ;&lt;/li&gt;
&lt;li&gt;il est important de toujours travailler avec des copies privées des données, que ce soit le contenu chiffré et le contenu déchiffré ;&lt;/li&gt;
&lt;li&gt;il est nécessaire d&amp;rsquo;avoir un contrôle sur la publication du déchiffré, notamment pour s&amp;rsquo;assurer que le contenu est intègre, et complet avant de le rendre accessible à des applications tierces.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour accomplir ces objectifs, il est possible d&amp;rsquo;exploiter les syscall Linux mmap(2), fallocate(2), msync(2), et ioctl(2) ou linkat(2).&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/X-Cli/large-file-decrypt&#34;&gt;Ce dépôt git&lt;/a&gt; contient un exemple d&amp;rsquo;algorithme mettant tous ces éléments en oeuvre, pour déchiffrer un gros fichier, de manière sécurisée.&lt;/p&gt;</description>
		</item>
		<item>
			<title>TousAntiCovid Verif : vulnérabilité et développement défensif</title>
			<link>https://broken-by-design.fr/posts/tacv-vuln-dev-defensif/</link>
			<pubDate>Thu, 05 Aug 2021 00:00:00 +0200</pubDate>
			<guid isPermaLink="true">https://broken-by-design.fr/posts/tacv-vuln-dev-defensif/</guid>
			<description>&lt;p&gt;L&amp;rsquo;application TousAntiCovid Verif sur Android nous a récemment régalé d&amp;rsquo;une vulnérabilité permettant d&amp;rsquo;afficher comme valides des pass sanitaires au format 2D-DOC manifestement invalides. Le bug n&amp;rsquo;intervient pas dans la vérification cryptographique de l&amp;rsquo;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&amp;rsquo;appareil faisant tourner TousAntiCovid Verif utilise la locale anglaise.&lt;/p&gt;
&lt;p&gt;Une &lt;a href=&#34;https://twitter.com/X_Cli_Public/status/1422240038377644038&#34;&gt;vidéo de démonstration&lt;/a&gt; a été publiée par l&amp;rsquo;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&amp;rsquo;a pas corrigé la vulnérabilité.&lt;/p&gt;
&lt;p&gt;Cet article propose d&amp;rsquo;étudier le bug, ses causes, et comment se protéger de tels bugs lorsqu&amp;rsquo;on pratique le développement défensif.&lt;/p&gt;
&lt;h2 id=&#34;la-vulnérabilité&#34;&gt;La vulnérabilité&lt;/h2&gt;
&lt;p&gt;Comme le code source de TousAntiCovid Verif n&amp;rsquo;a été &lt;a href=&#34;https://gitlab.inria.fr/tousanticovid-verif/tousanticovid-verif-android/-/commit/accf4cce921b0c078c35ba8c4ae7244a1c834b17&#34;&gt;publié que très tardivement&lt;/a&gt;, et que la vulnérabilité était présente dès cette publication initiale, il n&amp;rsquo;est pas possible de déterminer la date d&amp;rsquo;introduction du bug. En outre, tous les commits étant fusionné sous un unique commit à l&amp;rsquo;intitulé laconique &amp;ldquo;initial commit&amp;rdquo;, il n&amp;rsquo;est pas possible de faire une revue de code des changements dans le détail et de déterminer si l&amp;rsquo;auteur de ce bug a également commis d&amp;rsquo;autres impairs dans le code source de l&amp;rsquo;application. Bref, nous avons affaire à une parodie de code en sources ouvertes.&lt;/p&gt;
&lt;p&gt;Toujours est-il que l&amp;rsquo;excellent &lt;a href=&#34;https://twitter.com/gilbsgilbs&#34;&gt;@Gilbsgilbs&lt;/a&gt; a détecté, puis identifié la vulnérabilité. Elle se situe à aux lignes suivantes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://gitlab.inria.fr/tousanticovid-verif/tousanticovid-verif-android/-/blob/master/app/src/main/java/com/ingroupe/verify/anticovid/ui/result/ResultScanPresenterImpl.kt#L151&#34;&gt;https://gitlab.inria.fr/tousanticovid-verif/tousanticovid-verif-android/-/blob/master/app/src/main/java/com/ingroupe/verify/anticovid/ui/result/ResultScanPresenterImpl.kt#L151&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gitlab.inria.fr/tousanticovid-verif/tousanticovid-verif-android/-/blob/master/app/src/main/java/com/ingroupe/verify/anticovid/ui/result/ResultScanPresenterImpl.kt#L261&#34;&gt;https://gitlab.inria.fr/tousanticovid-verif/tousanticovid-verif-android/-/blob/master/app/src/main/java/com/ingroupe/verify/anticovid/ui/result/ResultScanPresenterImpl.kt#L261&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(oui, parce que non contents de faire un bug, ils font des copier-coller du bug pour être sûrs de l&amp;rsquo;avoir dans plusieurs branches de code&amp;hellip;)&lt;/p&gt;
&lt;p&gt;Au niveau le plus basique de l&amp;rsquo;analyse, le hic se situe sur le fait que &lt;code&gt;status&lt;/code&gt;, en anglais, ne vaut pas &lt;code&gt;Not Valid&lt;/code&gt; mais &lt;code&gt;Invalid&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Cette variable est assignée ici : &lt;a href=&#34;https://gitlab.inria.fr/tousanticovid-verif/tousanticovid-verif-android/-/blob/master/app/src/main/java/com/ingroupe/verify/anticovid/ui/result/ResultScanPresenterImpl.kt#L590&#34;&gt;https://gitlab.inria.fr/tousanticovid-verif/tousanticovid-verif-android/-/blob/master/app/src/main/java/com/ingroupe/verify/anticovid/ui/result/ResultScanPresenterImpl.kt#L590&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;La valeur assignée à cette variable est, elle-même, assignée ici : &lt;a href=&#34;https://gitlab.inria.fr/tousanticovid-verif/tousanticovid-verif-android/-/blob/master/app/src/main/java/com/ingroupe/verify/anticovid/service/document/StaticDataService.kt#L68&#34;&gt;https://gitlab.inria.fr/tousanticovid-verif/tousanticovid-verif-android/-/blob/master/app/src/main/java/com/ingroupe/verify/anticovid/service/document/StaticDataService.kt#L68&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;On peut noter que la valeur est issue d&amp;rsquo;un fichier de traduction : &lt;a href=&#34;https://gitlab.inria.fr/tousanticovid-verif/tousanticovid-verif-android/-/blob/master/app/src/main/res/values/strings.xml#L174&#34;&gt;en français&lt;/a&gt; ou &lt;a href=&#34;https://gitlab.inria.fr/tousanticovid-verif/tousanticovid-verif-android/-/blob/master/app/src/main/res/values-b+en/strings.xml#L156&#34;&gt;en anglais&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Le niveau zéro de la correction de cette vulnérabilité serait donc de remplacer &lt;code&gt;Not Valid&lt;/code&gt; par &lt;code&gt;Invalid&lt;/code&gt;&amp;hellip; Mais il y a bien plus d&amp;rsquo;enseignements à tirer de cette erreur criante. Le reste de cet article s&amp;rsquo;attache à expliquer les stratégies de développement défensif visant à prévenir de ce genre de bugs.&lt;/p&gt;
&lt;h2 id=&#34;tester&#34;&gt;Tester&lt;/h2&gt;
&lt;p&gt;Le code de TousAntiCovid Verif ne semble manifestement pas faire l&amp;rsquo;objet de tests unitaires (à l&amp;rsquo;exception &lt;a href=&#34;https://gitlab.inria.fr/tousanticovid-verif/tousanticovid-verif-android/-/blob/master/decoder/src/test/java/dgca/verifier/app/decoder/X509Tests.kt&#34;&gt;de&lt;/a&gt; &lt;a href=&#34;https://gitlab.inria.fr/tousanticovid-verif/tousanticovid-verif-android/-/blob/master/decoder/src/test/java/dgca/verifier/app/decoder/CertificateCheckTest.kt&#34;&gt;trois&lt;/a&gt; &lt;a href=&#34;https://gitlab.inria.fr/tousanticovid-verif/tousanticovid-verif-android/-/blob/master/decoder/src/test/java/dgca/verifier/app/decoder/QrCodeTests.kt&#34;&gt;fichiers&lt;/a&gt;). Plusieurs indices le laissent penser. D&amp;rsquo;une part, il n&amp;rsquo;y a aucune trace de ces tests dans le &lt;a href=&#34;https://gitlab.inria.fr/tousanticovid-verif/tousanticovid-verif-android/&#34;&gt;dépôt de code source&lt;/a&gt;. 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&amp;rsquo;ils ont commité tout ce qu&amp;rsquo;ils avaient (à l&amp;rsquo;exception des fichiers exclus par .gitignore, et qui ne font pas mention des tests unitaires).&lt;/p&gt;
&lt;p&gt;Ensuite, on peut voir que le code fautif était déjà présent dans le &lt;a href=&#34;https://gitlab.inria.fr/tousanticovid-verif/tousanticovid-verif-android/-/tree/accf4cce921b0c078c35ba8c4ae7244a1c834b17&#34;&gt;commit initial&lt;/a&gt; tandis que le fichier de langue contenant la chaine de caractères a été introduit dans un &lt;a href=&#34;https://gitlab.inria.fr/tousanticovid-verif/tousanticovid-verif-android/-/commit/1a0abc923f30a25c2d50398af903473ab12bc835&#34;&gt;commit ultérieur&lt;/a&gt;. 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.&lt;/p&gt;
&lt;p&gt;La première stratégie de développement défensif, qui constitue une bonne pratique standard de l&amp;rsquo;industrie, est de tester son code.&lt;/p&gt;
&lt;h2 id=&#34;utiliser-les-bons-types-booléens-et-les-bonnes-variables&#34;&gt;Utiliser les bons types (booléens) et les bonnes variables&lt;/h2&gt;
&lt;p&gt;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&amp;rsquo;elle repose sur la comparaison de nombreux octets qui doivent être tous justes pour que le test réussisse. À l&amp;rsquo;inverse, la comparaison d&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;Le plus navrant avec TousAntiCovid Verif, c&amp;rsquo;est qu&amp;rsquo;il y a &lt;a href=&#34;https://gitlab.inria.fr/tousanticovid-verif/tousanticovid-verif-android/-/blob/master/app/src/main/java/com/ingroupe/verify/anticovid/service/document/StaticDataService.kt#L67&#34;&gt;dans la même structure&lt;/a&gt; que celle dont est extraite cette chaine de caractères, un attribut &lt;code&gt;isValid&lt;/code&gt; de type booléen et qui aurait pu être avantageusement utilisé pour ce test. C&amp;rsquo;est à se demander s&amp;rsquo;il y a eu une revue de code !&lt;/p&gt;
&lt;h2 id=&#34;utiliser-des-symboles-plutôt-que-des-littéraux&#34;&gt;Utiliser des symboles plutôt que des littéraux&lt;/h2&gt;
&lt;p&gt;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&amp;rsquo;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&amp;rsquo;utiliser des symboles de langages, comme des constantes nommées ou des &lt;a href=&#34;http://rubylearning.com/satishtalim/ruby_hashes.html&#34;&gt;symboles&lt;/a&gt;. L&amp;rsquo;usage de symboles présente l&amp;rsquo;avantage qu&amp;rsquo;en cas de coquille dans le nom du symbole : une erreur sera levée au moment de la compilation ou de l&amp;rsquo;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.&lt;/p&gt;
&lt;h2 id=&#34;utiliser-lapproche-liste-autorisée-blanche-plutôt-que-liste-interdite-noire&#34;&gt;Utiliser l&amp;rsquo;approche liste autorisée (&amp;ldquo;blanche&amp;rdquo;), plutôt que liste interdite (&amp;ldquo;noire&amp;rdquo;)&lt;/h2&gt;
&lt;p&gt;L&amp;rsquo;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 &amp;ldquo;Non valide&amp;rdquo;. 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&amp;rsquo;applications sécurisées, car il est en général bien plus difficile d&amp;rsquo;envisager l&amp;rsquo;infinité des valeurs susceptibles d&amp;rsquo;être invalides, alors que les valeurs valides sont bien souvent en quantité très limitée.&lt;/p&gt;
&lt;p&gt;Une manière de programmer de manière défensive le test fautif aurait été d&amp;rsquo;inverser sa nature : plutôt que de tester si le statut du pass est &amp;ldquo;Non valide&amp;rdquo;, il aurait été préférable de tester s&amp;rsquo;il n&amp;rsquo;était pas &amp;ldquo;Valide&amp;rdquo;. Ainsi, en cas d&amp;rsquo;oubli, de coquille, ou de toute autre raison inattendue, le résultat de la validation aurait été un échec et non un succès.&lt;/p&gt;
&lt;h2 id=&#34;émuler-le-pattern-matching-complet&#34;&gt;Émuler le pattern matching complet&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Par exemple, en Caml ou en Rust (parmi tant d&amp;rsquo;autres ; je ne fais que citer ceux que j&amp;rsquo;ai pratiqués), il existe du &lt;a href=&#34;https://doc.rust-lang.org/book/ch18-03-pattern-syntax.html&#34;&gt;pattern matching&lt;/a&gt; dont l&amp;rsquo;exhaustivité des cas est vérifiée à la compilation. Si vous ne connaissez pas ce mécanisme, imaginez une sorte d&amp;rsquo;instruction &lt;code&gt;switch&lt;/code&gt; qui refuse de compiler si tous les &lt;code&gt;case&lt;/code&gt; possibles n&amp;rsquo;ont pas été énumérés.&lt;/p&gt;
&lt;p&gt;Typiquement, ici, il aurait pu être pertinent d&amp;rsquo;utiliser une telle instruction de contrôle pour énumérer de façon exhaustive les cas &amp;ldquo;Valide&amp;rdquo;, &amp;ldquo;Non valide&amp;rdquo;, &amp;ldquo;Valid&amp;rdquo; et &amp;ldquo;Invalid&amp;rdquo; à l&amp;rsquo;exclusion de tout autre, sauf à encourir une erreur de compilation.&lt;/p&gt;
&lt;p&gt;Même quand le langage ne dispose pas de telles instructions de pattern matching (ou même de switch !), il est possible de l&amp;rsquo;émuler.&lt;/p&gt;
&lt;p&gt;Par exemple, en Python :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  if status in [&amp;#34;Non valide&amp;#34;, &amp;#34;Invalid&amp;#34;]:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    handle_invalid_case()
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  else if status in [&amp;#34;Valide&amp;#34;, &amp;#34;Valid&amp;#34;]:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    handle_valid_case()
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  else:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    raise NotImplementedError()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;employer-les-design-patterns-lorsquils-sont-pertinents&#34;&gt;Employer les design patterns lorsqu&amp;rsquo;ils sont pertinents&lt;/h2&gt;
&lt;p&gt;Finalement, on peut noter que les développeurs de TousAntiCovid Verif n&amp;rsquo;ont absolument pas respecté les patrons de conception (&amp;ldquo;design patterns&amp;rdquo;) pourtant standard dans l&amp;rsquo;industrie. Je pense notamment à Model View Controler (MVC), &lt;a href=&#34;http://dl.acm.org/citation.cfm?id=50757.50759&#34;&gt;introduit dans les années 80&lt;/a&gt;. En effet, les développeurs de TousAntiCovid Verif ont &lt;a href=&#34;https://gitlab.inria.fr/tousanticovid-verif/tousanticovid-verif-android/-/blob/master/app/src/main/java/com/ingroupe/verify/anticovid/service/document/StaticDataService.kt#L68&#34;&gt;initialisé l&amp;rsquo;attribut status de type string de la structure DocumentSignatureResult avec le résultat d&amp;rsquo;une interrogation du module d&amp;rsquo;internationalisation&lt;/a&gt;. Cette initialisation est faite dès l&amp;rsquo;acquisition du code-barre 2D-DOC. Il s&amp;rsquo;agit donc d&amp;rsquo;une violation du patron MVC qui réserve l&amp;rsquo;affichage (éventuellement internationalisé) à la View, alors que l&amp;rsquo;initialisation du résultat de l&amp;rsquo;acquisition du code barre est clairement du code métier, devant être développé dans le Model.&lt;/p&gt;
&lt;p&gt;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 &amp;ldquo;Design Patterns: Elements of Reusable Object-Oriented Software&amp;rdquo;.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;L&amp;rsquo;application TousAntiCovid Verif présente de nombreux signes d&amp;rsquo;une application développée sans respect des bonnes pratiques et des standards de l&amp;rsquo;industrie. L&amp;rsquo;absence de tests unitaires, et le manque de vigilance lors des revues de code (s&amp;rsquo;il y en a eu), indiquent également une très faible qualité code. Il est également permis de douter qu&amp;rsquo;un tel code ait été validé par l&amp;rsquo;ANSSI ou ait même subi un audit externe indépendant.&lt;/p&gt;
&lt;p&gt;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&amp;rsquo;incompétence manifeste de ses développeurs.&lt;/p&gt;
</description>
		</item>
		<item>
			<title>7 gestes barrières contre le pass sanitaire et pour préserver sa vie privée</title>
			<link>https://broken-by-design.fr/posts/gestes-barrieres-pass-sanitaire/</link>
			<pubDate>Thu, 29 Jul 2021 00:00:00 +0200</pubDate>
			<guid isPermaLink="true">https://broken-by-design.fr/posts/gestes-barrieres-pass-sanitaire/</guid>
			<description>&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h2 id=&#34;1-stratégie-dévitement--boycotter-les-lieux-qui-exigent-le-pass-sanitaire&#34;&gt;1. Stratégie d’évitement : boycotter les lieux qui exigent le pass sanitaire&lt;/h2&gt;
&lt;p&gt;Le premier geste barrière est d&amp;rsquo;adopter une stratégie d&amp;rsquo;évitemment de l&amp;rsquo;emploi du pass sanitaire. En boycottant les lieux qui l&amp;rsquo;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&amp;rsquo;évitemment est la seule option des non-vaccinés. Ce n&amp;rsquo;est pas faux. Mais c&amp;rsquo;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&amp;rsquo;égalité en droit.&lt;/p&gt;
&lt;h2 id=&#34;2-stratégie-dobstruction--maximiser-le-temps-requis-pour-faire-le-contrôle-du-pass-sanitaire-sans-toutefois-refuser&#34;&gt;2. Stratégie d&amp;rsquo;obstruction : maximiser le temps requis pour faire le contrôle du pass sanitaire, sans toutefois refuser&lt;/h2&gt;
&lt;p&gt;Le deuxième geste barrière est à appliquer lorsque la stratégie d&amp;rsquo;évitemment n&amp;rsquo;est pas possible ou n&amp;rsquo;est pas appropriée. L&amp;rsquo;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&amp;rsquo;un controleur vérifie le pass sanitaire.&lt;/p&gt;
&lt;p&gt;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&amp;rsquo;activité économique.&lt;/p&gt;
&lt;p&gt;N&amp;rsquo;hésitez pas à présenter des pass sanitaires de type tests (PCR ou antigéniques) périmés (&amp;ldquo;oh, je me suis trompé ; le voici&amp;rdquo;), à baisser la luminosité du téléphone pour gêner la lecture du code barre. Galérez à trouver le bouton pour l&amp;rsquo;augmenter. Présentez une photocopie chiffonnée.&lt;/p&gt;
&lt;p&gt;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&amp;rsquo;appliquer au final la stratégie d&amp;rsquo;é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.&lt;/p&gt;
&lt;h2 id=&#34;3-ne-jamais-diffuser-son-pass-sanitaire-même-partiellement-masqué-à-des-personnes-nayant-pas-le-besoin-den-connaitre&#34;&gt;3. Ne jamais diffuser son pass sanitaire, même partiellement masqué à des personnes n&amp;rsquo;ayant pas le besoin d&amp;rsquo;en connaitre&lt;/h2&gt;
&lt;p&gt;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&amp;rsquo;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&amp;rsquo;agent prophylactique et la date d&amp;rsquo;injection du dernier vaccin reçu.&lt;/p&gt;
&lt;p&gt;Ces informations sont lisibles par n&amp;rsquo;importe qui qui peut visualiser votre code barre et qui dispose d&amp;rsquo;un logiciel dédié. Certains sont librement accessibles sur le net. Cette &lt;a href=&#34;https://peertube.stream/w/chiP7CT37rwQJoyNuD3HMp&#34;&gt;petite vidéo&lt;/a&gt; vous en convainvra.&lt;/p&gt;
&lt;p&gt;En outre, les code barres 2D (datamatrix et qrcode) contiennent des codes correcteurs d&amp;rsquo;erreurs. Un code correcteur d&amp;rsquo;erreurs, c&amp;rsquo;est un outil mathématique qui vise à compenser la destruction partielle du code barre. Dans le cas des qrcodes, c&amp;rsquo;est le même code correcteur d&amp;rsquo;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&amp;rsquo;il contient.&lt;/p&gt;
&lt;p&gt;Finalement, la diffusion de son pass sanitaire avec l&amp;rsquo;intention d&amp;rsquo;encourager son emploi par un tiers est puni selon le code pénal de 75 000 € d&amp;rsquo;amende et de 5 ans de prison.&lt;/p&gt;
&lt;p&gt;Le troisième geste barrière est donc de ne pas diffuser son pass sanitaire.&lt;/p&gt;
&lt;h2 id=&#34;4-privilégier-le-papier&#34;&gt;4. Privilégier le papier&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Si votre poche n&amp;rsquo;est pas un endroit sûr (?), alors un téléphone avec un code d&amp;rsquo;accès fort peut éventuellement mieux le protéger. Notez bien que vous n&amp;rsquo;avez pas besoin d&amp;rsquo;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&amp;rsquo;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&amp;rsquo;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&amp;rsquo;affaire.&lt;/p&gt;
&lt;h2 id=&#34;5-vérifier-le-logiciel-utilisé-par-le-controleur&#34;&gt;5. Vérifier le logiciel utilisé par le controleur&lt;/h2&gt;
&lt;p&gt;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&amp;rsquo;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 !&lt;/p&gt;
&lt;p&gt;Ce cinquième geste barrière consiste à exiger du controleur qu&amp;rsquo;il lance l&amp;rsquo;application de vérification (par exemple TousAntiCovid Verif) depuis l&amp;rsquo;app store, devant vos yeux. Si le controleur refuse, insistez (stratégie d&amp;rsquo;obstruction). Finalement, en cas de refus ferme, appliquez la stratégie d&amp;rsquo;évitemment : il en va de la sécurité de vos données personnelles et médicales.&lt;/p&gt;
&lt;h2 id=&#34;6-refuser-la-vérification-didentité-par-les-personnes-non-habilitées&#34;&gt;6. Refuser la vérification d&amp;rsquo;identité par les personnes non habilitées&lt;/h2&gt;
&lt;p&gt;Le contrôle d&amp;rsquo;identité est un acte qui ne peut être effectué que par certains membres des forces de l&amp;rsquo;ordre. Aucun contrôleur de pass sanitaire employé par le secteur privé, ni même certains agents des forces de l&amp;rsquo;ordre ne sont habilités à contrôler votre identité.&lt;/p&gt;
&lt;p&gt;En conséquence, ce sixième geste barrière consister à refuser de présenter sa carte d&amp;rsquo;identité ou tout autre justificatif d&amp;rsquo;identité à ces personnes. Appliquez la stratégie d&amp;rsquo;obstruction en cas de refus, et faites intervenir les forces de l&amp;rsquo;ordre.&lt;/p&gt;
&lt;p&gt;Lors d&amp;rsquo;un contrôle d&amp;rsquo;identité par les forces de l&amp;rsquo;ordre, privilégiez la preuve d&amp;rsquo;identité par témoignage, si vous êtes dans un groupe d&amp;rsquo;amis, plutôt que de présenter vos papiers d&amp;rsquo;identité. C&amp;rsquo;est peu connu, mais des personnes attestant de votre identité sont suffisantes pour satisfaire un contrôle d&amp;rsquo;identité. Il n&amp;rsquo;y a pas besoin de présenter des titres émis par l&amp;rsquo;État.&lt;/p&gt;
&lt;h2 id=&#34;7-ne-pas-convertir-son-pass-avec-tousanticovid&#34;&gt;7. Ne pas convertir son pass avec TousAntiCovid&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;EDIT&lt;/strong&gt; du 4 août 2021 : ce geste barrière n&amp;rsquo;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.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;L&amp;rsquo;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&amp;rsquo;effectue par l&amp;rsquo;envoi du pass sanitaire à un serveur central, via des serveurs américains, qui peuvent voir le contenu du pass sanitaire dans son intégralité.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Je doute qu&amp;rsquo;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&amp;rsquo;hésitez pas à redistribuer cet article. Vous pouvez le republier, le commenter, en faire des travaux dérivés. Sa licence est CC-0.&lt;/p&gt;
&lt;p&gt;Si vous souhaitez me contacter, je suis disponible sur &lt;a href=&#34;https://twitter.com/x_cli_public&#34;&gt;Twitter&lt;/a&gt; ou le &lt;a href=&#34;https://infosec.exchange/@x_cli&#34;&gt;Fédiverse&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Merci à toutse de m&amp;rsquo;avoir lu.&lt;/p&gt;
&lt;p&gt;Vive la Nation !&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;bonus--gestes-barrières-relatifs-à-tousanticovid-signal&#34;&gt;BONUS : gestes barrières relatifs à TousAntiCovid Signal&lt;/h2&gt;
&lt;h3 id=&#34;limiter-la-diffusion-dinformations-personnelles-dans-les-carnets-de-rappel-tousanticovid-signal&#34;&gt;Limiter la diffusion d&amp;rsquo;informations personnelles dans les carnets de rappel (TousAntiCovid Signal)&lt;/h3&gt;
&lt;p&gt;Lorsque l&amp;rsquo;on se rend dans certains lieux, il est requis de s&amp;rsquo;enregistrer soit avec l&amp;rsquo;application TousAntiCovid en scannant un QRCode de l&amp;rsquo;établissement, soit en ajoutant ses informations de contact dans un carnet de rappel papier.&lt;/p&gt;
&lt;p&gt;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).&lt;/p&gt;
&lt;p&gt;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&amp;rsquo;enregistrement dans le carnet de rappel refuse l&amp;rsquo;usage d&amp;rsquo;une adresse email, prétexter que vous n&amp;rsquo;avez pas de téléphone, ou que vous êtes sur un numéro temporaire car vous changez d&amp;rsquo;opérateur.&lt;/p&gt;
&lt;p&gt;Utiliser ou non TousAntiCovid Signal avec prise de photo d&amp;rsquo;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&amp;rsquo;est donc pas possible de donner une recommandation universelle quant à son emploi ou non.&lt;/p&gt;
&lt;h3 id=&#34;régénérer-très-fréquemment-les-qrcodes-tousanticovid-signal&#34;&gt;Régénérer très fréquemment les QRCodes TousAntiCovid Signal&lt;/h3&gt;
&lt;p&gt;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&amp;rsquo;ouverture de l&amp;rsquo;établissement.&lt;/p&gt;
&lt;p&gt;Changer le code régulièrement aide vos clients à préserver leur vie privée lorsqu&amp;rsquo;ils se déclarent malades. Cela limite la possibilité de désanonymiser le malade, et de tracer ses lieux de fréquentation d&amp;rsquo;une manière disproportionnée par rapport à la finalité de détection de clusters. &lt;/p&gt;</description>
		</item>
		<item>
			<title>Vacciné et contre le pass sanitaire</title>
			<link>https://broken-by-design.fr/posts/anti-pass-sanitaire/</link>
			<pubDate>Mon, 19 Jul 2021 00:00:00 +0200</pubDate>
			<guid isPermaLink="true">https://broken-by-design.fr/posts/anti-pass-sanitaire/</guid>
			<description>&lt;p&gt;Un billet d&amp;rsquo;humeur contre l&amp;rsquo;extension du pass sanitaire, son principe en général et ses dérives autoritaires.&lt;/p&gt;
&lt;p&gt;Je suis contre le pass sanitaire, et je suis pourtant vacciné.&lt;/p&gt;
&lt;p&gt;Comme il semble importer à certains de comprendre qui parle pour ensuite savoir l&amp;rsquo;é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.&lt;/p&gt;
&lt;h1 id=&#34;qui-suis-je-&#34;&gt;Qui suis-je ?&lt;/h1&gt;
&lt;p&gt;Je suis Florian Maury. J&amp;rsquo;ai 38 ans, et je suis en surpoids (IMC 29.5), sans autre comorbidité connue. Je ne suis ni rattaché, ni sympathisant d&amp;rsquo;aucun parti politique. Mon seul engagement politique significatif est l&amp;rsquo;antispécisme.&lt;/p&gt;
&lt;p&gt;Pendant la pandémie, mon emploi a été maintenu et j&amp;rsquo;ai pu le continuer, en bénéficiant du télétravail à 100%. Ce jour encore, je suis en télétravail.&lt;/p&gt;
&lt;p&gt;Ma compagne, elle, travaille avec des enfants et est donc exposée à un risque de contamination plus important que d&amp;rsquo;autres corps de métier.&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;ai fait le choix de me vacciner parce que j&amp;rsquo;ai considéré les risques de ne pas me vacciner, et ceux de me vacciner, et j&amp;rsquo;ai jugé que la balance bénéfices/risques, dans mon cas, penchait vers l&amp;rsquo;intérêt d&amp;rsquo;être vacciné. C&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;Pour protéger les autres, je respecte les gestes barrières depuis la première heure. J&amp;rsquo;ai porté un masque, conformément aux directives sanitaires, y compris en forêt, lorsque je croisais d&amp;rsquo;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&amp;rsquo;étais malade. Par respect pour mes collègues de travail, et mes compagnons de voyage de la région parisienne.&lt;/p&gt;
&lt;h1 id=&#34;quels-sont-les-problèmes-du-pass-sanitaire-&#34;&gt;Quels sont les problèmes du pass sanitaire ?&lt;/h1&gt;
&lt;p&gt;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&amp;rsquo;Emmanuel Macron, ce 12 juillet 2021.&lt;/p&gt;
&lt;h2 id=&#34;aspect-technique&#34;&gt;Aspect technique&lt;/h2&gt;
&lt;p&gt;Depuis la parution du pass sanitaire, de nombreuses critiques sont formulées sur sa réalisation technique.&lt;/p&gt;
&lt;p&gt;Dans &lt;a href=&#34;https://www.broken-by-design.fr/posts/pass-sanitaire/&#34;&gt;cet article&lt;/a&gt;, Piotr Chmielnicki et moi-même avons analysé le contenu du pass sanitaire, et l&amp;rsquo;avons comparé aux annonces gouvernementales, aux déclarations sur les sites gouvernementaux, et à l&amp;rsquo;avis de la CNIL.&lt;/p&gt;
&lt;p&gt;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&amp;rsquo;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 &lt;a href=&#34;https://twitter.com/MathisHammel/status/1397902091067265026&#34;&gt;Mathis Hammel&lt;/a&gt;, celle de &lt;a href=&#34;https://cq94.medium.com/la-fin-du-pseudonymat-dans-tousanticovid-932d50de11ee&#34;&gt;Christian Quest&lt;/a&gt;, aux excellentes analyses de TousAntiCovid Verif par &lt;a href=&#34;https://twitter.com/gilbsgilbs&#34;&gt;Gilbsgilbs&lt;/a&gt;, ou à l&amp;rsquo;implémentation de preuves de concept comme &lt;a href=&#34;https://sanipasse.fr/&#34;&gt;sanipasse.fr&lt;/a&gt; et celle de &lt;a href=&#34;https://twitter.com/BLeQuerrec/status/1401290053687644169&#34;&gt;Bastien Le Querrec&lt;/a&gt;, de la Quadrature du Net.&lt;/p&gt;
&lt;p&gt;Il est intéressant de noter que dans son &lt;a href=&#34;https://www.cnil.fr/sites/default/files/atoms/files/deliberation_2021-054_du_12_mai_2021_portant_avis_sur_le_projet_de_mise_en_place_dun_passe_sanitaire.pdf&#34;&gt;avis du 12 mai&lt;/a&gt;, la CNIL disait d&amp;rsquo;ailleurs à juste titre :&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start=&#34;8&#34;&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;/ol&gt;&lt;/blockquote&gt;
&lt;p&gt;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&amp;rsquo;un pass, le contenu de ce pass sanitaire (c&amp;rsquo;est-à-dire nos données privées et de santé) à un acteur américain (Akamai), puis à une société française : IN Groupe, l&amp;rsquo;imprimerie nationale. L&amp;rsquo;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&amp;rsquo;un point de vue technique, d&amp;rsquo;après de nombreux spécialistes en cryptographie. D&amp;rsquo;ailleurs, &lt;a href=&#34;https://github.com/ofa-/&#34;&gt;Olaf&lt;/a&gt; et le créateur de sanipasse.fr l&amp;rsquo;ont prouvé en fournissant au public des vérificateurs de pass sanitaires hors-ligne, c&amp;rsquo;est-à-dire sans connexion à Internet nécessaire. En outre, TousAntiCovid Verif contenait des logiciels de tracking des utilisateurs provenant de Google.&lt;/p&gt;
&lt;p&gt;De nombreux journaux ont relayé l’information, parmi lesquels &lt;a href=&#34;https://www.nextinpact.com/article/46153/pass-sanitaire-poudre-aux-yeux-pseudonymat-donnees-medicales-en-clair&#34;&gt;NextInpact&lt;/a&gt;, &lt;a href=&#34;https://www.numerama.com/tech/717219-tousanticovid-verif-pourquoi-lapp-verifiant-les-donnees-du-pass-sanitaire-fait-polemique.html&#34;&gt;Numerama&lt;/a&gt;, &lt;a href=&#34;https://www.01net.com/actualites/tousanticovid-verif-le-panier-perce-du-pass-sanitaire-2044056.html&#34;&gt;01net&lt;/a&gt;, &lt;a href=&#34;https://www.mediapart.fr/journal/france/090621/donnees-personnelles-les-controles-du-passe-sanitaire-suscitent-linquietude&#34;&gt;Mediapart&lt;/a&gt;, &lt;a href=&#34;https://www.contrepoints.org/2021/06/09/399255-donnees-medicales-anonymat-surveillance-un-pass-sanitaire-passoire&#34;&gt;Contrepoints&lt;/a&gt;, &lt;a href=&#34;https://www.lemondeinformatique.fr/actualites/lire-tousanticovid-le-pass-sanitaire-en-quete-de-protection-83204.html&#34;&gt;Le Monde Informatique&lt;/a&gt;. Il y eut aussi d&amp;rsquo;autres formes de relais dont &lt;a href=&#34;https://www.developpez.com/actu/315816/Application-TousAntiCovid-et-Pass-sanitaire-les-informations-personnelles-et-medicales-sont-disponibles-en-clair-previent-Christian-Quest/&#34;&gt;Developpez&lt;/a&gt; ou &lt;a href=&#34;https://www.igen.fr/ailleurs/2021/06/le-pass-sanitaire-souleve-des-craintes-en-matiere-de-confidentialite-123027&#34;&gt;iGeneration&lt;/a&gt;.
Finalement, le gouvernement a annoncé, lors d&amp;rsquo;une &lt;a href=&#34;https://www.nextinpact.com/article/46147/pass-sanitaire-donnees-en-clair-open-source-on-fait-au-plus-simple&#34;&gt;conférence de presse&lt;/a&gt;, l&amp;rsquo;élaboration dans l&amp;rsquo;urgence d&amp;rsquo;un mode &amp;ldquo;offline&amp;rdquo; (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&amp;rsquo;a toujours pas été publié, contrairement aux annonces gouvernementales effectuées durant cette même conférence de presse.&lt;/p&gt;
&lt;p&gt;Depuis, Olaf et Gilbsgilbs ont pu noter que la fonctionnalité de conversion des pass sanitaires français en pass sanitaires européens, par l&amp;rsquo;entremise de TousAntiCovid, avait recours à l&amp;rsquo;envoi du pass sanitaire dans son intégralité, toujours via les serveurs américains d&amp;rsquo;Akamai, puis via les serveurs d&amp;rsquo;IN Groupe.&lt;/p&gt;
&lt;p&gt;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é&amp;hellip;&lt;/p&gt;
&lt;h2 id=&#34;aspect-juridique&#34;&gt;Aspect juridique&lt;/h2&gt;
&lt;p&gt;Le pass sanitaire présente de nombreuses faiblesses juridiques.&lt;/p&gt;
&lt;p&gt;Pour commencer, le pass sanitaire a failli être retoqué par le Parlement puisqu&amp;rsquo;il a été nécessaire de faire deux votes, le premier ayant eu pour résultat son rejet. C&amp;rsquo;est au prix d&amp;rsquo;amendements, à l&amp;rsquo;initiative du Modem, visant à restreindre la durée du pass, que celui-ci a été finalement accepté par le Parlement.&lt;/p&gt;
&lt;p&gt;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 :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;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&amp;rsquo;il contient.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Or il se trouve que le pass sanitaire est librement lisible par tous, à l&amp;rsquo;aide d&amp;rsquo;un lecteur de code barre 2D, et qu&amp;rsquo;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&amp;rsquo;un pass sanitaire de type vaccinal. Des informations différentes sont présentées dans le cas d&amp;rsquo;un pass sanitaire de type test. Le pass est donc contraire à cette loi en cela qu&amp;rsquo;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&amp;rsquo;il contient. Peu importe que l&amp;rsquo;application TousAntiCovid Verif dissimule certaines informations ; n&amp;rsquo;importe quel lecteur de code barres peut en révéler le contenu intégral.&lt;/p&gt;
&lt;p&gt;En outre, il est attendu, pour qu&amp;rsquo;il soit efficace, que les personnes habilitées ou les services autorisés à en assurer le contrôle puissent vérifier l&amp;rsquo;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&amp;rsquo;identité. Or, la vérification de l&amp;rsquo;identité d&amp;rsquo;une personne est encadrée par la loi. En l&amp;rsquo;occurrence, sur le site &lt;a href=&#34;https://www.service-public.fr/particuliers/vosdroits/F1036&#34;&gt;Services Publics.fr&lt;/a&gt;, on peut lire que le contrôle d&amp;rsquo;identité est limité aux personnes suivantes :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Les forces de l&amp;rsquo;ordre (police, gendarmerie) habilitées à faire un contrôle d&amp;rsquo;identité sont les suivantes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Officier de police judiciaire (OPJ)&lt;/li&gt;
&lt;li&gt;Agents de police judiciaire, sous la responsabilité de l&amp;rsquo;OPJ&lt;/li&gt;
&lt;li&gt;Certains agents de police judiciaire adjoints, sous la responsabilité de l&amp;rsquo;OPJ
Un douanier peut aussi faire un contrôle d&amp;rsquo;identité dans certains cas.
A savoir : un agent de police municipale peut relever votre identité lorsqu&amp;rsquo;il constate une contravention. Par exemple, une contravention de stationnement. Toutefois, il n&amp;rsquo;est pas autorisé à contrôler votre identité.&lt;/li&gt;
&lt;/ul&gt;&lt;/blockquote&gt;
&lt;p&gt;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&amp;rsquo;aucun lieu de loisirs ne sont habilités à demander aux citoyens français leurs papiers d&amp;rsquo;identité pour en faire le contrôle. Alexandre Horn informe également dans ce sens, dans &lt;a href=&#34;https://www.liberation.fr/checknews/pass-sanitaire-commercants-et-restaurateurs-peuvent-ils-controler-lidentite-de-leurs-clients-20210716_G7VJUUHV4RHLTABS4B64OWHTZU/&#34;&gt;les colonnes de Libération&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Par ailleurs, la Quadrature du Net a saisi le Conseil d&amp;rsquo;État, le 9 juin, à propos du pass sanitaire, via la procédure de référé-liberté. Bien que le Conseil d&amp;rsquo;État soit censé rendre un verdict en deux jours, dans ce cadre de procédure, il a fallu attendre près d&amp;rsquo;un mois pour obtenir un jugement. Il s&amp;rsquo;agit là d&amp;rsquo;un délai noté comme anormalement long par de nombreux juristes, même dans les circonstances exceptionnelles de cette pandémie.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.conseil-etat.fr/actualites/actualites/le-conseil-d-etat-ne-suspend-pas-le-passe-sanitaire&#34;&gt;Le verdict du Conseil d&amp;rsquo;État&lt;/a&gt;, rendu le 6 juillet a soigneusement évité d&amp;rsquo;adresser certains points cruciaux de la plainte, a énoncé des banalités sans rapport avec la plainte (avaient-ils perdu le dossier ?), et n&amp;rsquo;a finalement pas suspendu le pass sanitaire pour les raisons suivantes (liste non exhaustive) :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&amp;ldquo;Il résulte de l&amp;rsquo;instruction et il n&amp;rsquo;est d&amp;rsquo;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 (&amp;rdquo; mode off-line &amp;ldquo;), 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&amp;rdquo;. On notera que ce &amp;ldquo;renoncement&amp;rdquo; du gouvernement coïncide avec les révélations faites par le groupe de citoyens mentionnés dans la section &amp;ldquo;Aspects techniques&amp;rdquo; de ce billet.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&amp;ldquo;Son usage a été restreint aux déplacements avec l&amp;rsquo;étranger, la Corse et l&amp;rsquo;outre-mer, d&amp;rsquo;une part, et à l&amp;rsquo;accès à des lieux de loisirs, d&amp;rsquo;autre part, sans que soient concernées les activités quotidiennes ou l&amp;rsquo;exercice des libertés de culte, de réunion ou de manifestation&amp;rdquo;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Or, avec l&amp;rsquo;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&amp;rsquo;État, il apparaît très clairement que le contexte sanitaire n&amp;rsquo;a pas changé du tout au tout en ces 6 jours, et que le pass concerne désormais les activités quotidiennes.&lt;/p&gt;
&lt;p&gt;Sur le plan juridique, il y a également la question de la proportionnalité de l&amp;rsquo;atteinte à la liberté de circulation, et au principe d’égalité, au vu de l&amp;rsquo;objectif. Étant donné que la France est l&amp;rsquo;un des rares pays à avoir choisi de déployer un tel dispositif généralisé, il me semble raisonnable d&amp;rsquo;en douter. Hélas, comme l&amp;rsquo;explique &lt;a href=&#34;https://www.lefigaro.fr/vox/societe/passe-sanitaire-n-attendons-rien-du-conseil-constitutionnel-20210716&#34;&gt;Dominique Bompoint dans son article dans Le Figaro&lt;/a&gt;, il n&amp;rsquo;y a rien à attendre du Conseil Constitutionnel.&lt;/p&gt;
&lt;p&gt;Le recours déposé par Piotr Chmielnicki auprès de la CNIL, avec en copie le Défenseur des droits, n&amp;rsquo;a pas abouti. Le Défenseur des droits s&amp;rsquo;est défaussé en pointant vers &lt;a href=&#34;https://www.defenseurdesdroits.fr/fr/communique-de-presse/2021/05/la-defenseure-des-droits-sinquiete-des-risques-datteintes-aux-droits-et&#34;&gt;son article à ce sujet&lt;/a&gt;, 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 &amp;ldquo;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é&amp;rdquo;. Or, il s&amp;rsquo;avère que même si la loi contient effectivement ces garanties, l&amp;rsquo;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.&lt;/p&gt;
&lt;h1 id=&#34;aspect-éthique&#34;&gt;Aspect éthique&lt;/h1&gt;
&lt;p&gt;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&amp;rsquo;euros par mois, pour vivre normalement. Il s&amp;rsquo;agit là d&amp;rsquo;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&amp;rsquo;humilité des instances dirigeantes sur leur capacité à capturer l&amp;rsquo;infinie complexité des situations individuelles et à asséner une solution universelle.&lt;/p&gt;
&lt;p&gt;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&amp;rsquo;ailleurs lors d&amp;rsquo;un &lt;a href=&#34;https://www.francetvinfo.fr/sante/maladie/coronavirus/pass-sanitaire/manifestations-contre-le-pass-sanitaire-vos-droits-ne-peuvent-pas-etre-les-memes-repond-emmanuel-macron_4704357.html&#34;&gt;entretien&lt;/a&gt; : &amp;ldquo;Vos droits ne peuvent pas être les mêmes parce qu&amp;rsquo;ils supposent des devoirs&amp;rdquo;. Dès lors, la notion d&amp;rsquo;é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.&lt;/p&gt;
&lt;p&gt;Hélas, les pauvres hères de la caste des non-vaccinés (ou devrait-on les appeler &amp;ldquo;intouchables&amp;rdquo; ?) 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 &lt;a href=&#34;https://www.ined.fr/en/everything_about_population/data/france/population-structure/population-age/&#34;&gt;50 millions d’adultes âgés de 20 ans et plus&lt;/a&gt;, 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 &lt;a href=&#34;https://solidarites-sante.gouv.fr/grands-dossiers/vaccin-covid-19/article/le-tableau-de-bord-de-la-vaccination&#34;&gt;71 millions de doses&lt;/a&gt;. 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.&lt;/p&gt;
&lt;p&gt;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 &lt;a href=&#34;https://ourworldindata.org/covid-vaccinations&#34;&gt;87% de la population mondiale n’a pas reçu deux doses&lt;/a&gt;. 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.&lt;/p&gt;
&lt;h1 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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 : “&lt;strong&gt;Vive la Nation !&lt;/strong&gt;”. Faisons trembler la terre, et pourquoi pas l’Élysée !&lt;/p&gt;</description>
		</item>
		<item>
			<title>Pass sanitaire et vie privée : quels sont les risques ?</title>
			<link>https://broken-by-design.fr/posts/pass-sanitaire/</link>
			<pubDate>Thu, 03 Jun 2021 18:00:00 +0200</pubDate>
			<guid isPermaLink="true">https://broken-by-design.fr/posts/pass-sanitaire/</guid>
			<description>&lt;p&gt;Cet article est sous licence CC-BY-ND.&lt;/p&gt;
&lt;p&gt;Auteurs :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://infosec.exchange/@X_Cli&#34;&gt;Florian Maury&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://twitter.com/piotrcki&#34;&gt;Piotr Chmielnicki&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Les auteurs de cet article peuvent être contactés :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;par email : florian.maury-pass-sanitaire VOUS-SAVEZ-QUOI broken-by-design.fr&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;par chat, avec Matrix : #pass-sanitaire:matrix.piotr.paris&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Mise à jour importante du 10 juin 2021&lt;/strong&gt; : &lt;a href=&#34;https://twitter.com/gilbsgilbs/status/1402689482193879045&#34;&gt;l&amp;rsquo;application TousAntiCovid Verif&lt;/a&gt;, dans sa dernière version à la date d&amp;rsquo;écriture de cette ligne, ne fait plus appel à un serveur centralisé pour valider les pass sanitaires. Elle n&amp;rsquo;envoie plus de données à un prestataire américain. Elle ne contient plus de services Google Firebase. Hélas, le reste de l&amp;rsquo;article et de la vidéo continuent d&amp;rsquo;être pertinents pour l&amp;rsquo;heure. La Quadrature du Net effectue &lt;a href=&#34;https://www.laquadrature.net/2021/06/09/passe-sanitaire-attaquons-lobligation-didentification/&#34;&gt;une action en justice&lt;/a&gt; en ce sens.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Il existe une vidéo compagnon, pour ceux qui préfèrent regarder que lire.&lt;/p&gt;
&lt;p&gt;Sur Peertube :&lt;/p&gt;
&lt;div style=&#34;position: relative; padding-bottom: 56.25%; margin-bottom: 1rem; height: 0; overflow: hidden;&#34;&gt;
&lt;iframe sandbox=&#34;allow-scripts allow-popups&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34;
    src=&#34;https://peertube.stream/videos/embed/a1b37a25-fa83-4350-8da9-db3f89c662b0?title=0&amp;warningTitle=0&amp;peertubeLink=0&#34; title=&#34;Peertube Video&#34; allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;En téléchargement : &lt;a href=&#34;https://data.piotr.paris/pass-sanitaire.mp4&#34;&gt;Haute qualité (1300MB)&lt;/a&gt; / &lt;a href=&#34;https://data.piotr.paris/pass-sanitaire-br.mp4&#34;&gt;Faible qualité (90MB)&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Ce document porte sur le pass sanitaire, qui est en train d&amp;rsquo;ê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&amp;rsquo;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&amp;rsquo;identité.&lt;/p&gt;
&lt;p&gt;Le pass sanitaire est présenté sous la forme d&amp;rsquo;un code barre en deux dimensions, appelé datamatrix. Ce code barre, comme son nom l&amp;rsquo;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&amp;rsquo;information. Au lieu d&amp;rsquo;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&amp;rsquo;encodage de ces informations ne constitue pas une mesure de protection des données puisque n&amp;rsquo;importe qui équipé d&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;D&amp;rsquo;après le site &lt;a href=&#34;https://www.service-public.fr/particuliers/actualites/A14896&#34;&gt;Service Public.fr&lt;/a&gt;, le pass sanitaire contient les informations suivantes :&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;nom, prénom ;&lt;/li&gt;
&lt;li&gt;date de naissance ;&lt;/li&gt;
&lt;li&gt;type de certificat et résultat éventuel (test PCR ou antigénique ou vaccination première et seconde dose) ;&lt;/li&gt;
&lt;li&gt;type de vaccin le cas échéant ;&lt;/li&gt;
&lt;li&gt;date et heure du certificat.&lt;/li&gt;
&lt;/ul&gt;&lt;/blockquote&gt;
&lt;p&gt;Le site &lt;a href=&#34;https://www.gouvernement.fr/pass-sanitaire-toutes-les-reponses-a-vos-questions&#34;&gt;gouvernement.fr&lt;/a&gt; indique la même liste.&lt;/p&gt;
&lt;p&gt;Nous avons analysé le contenu du pass sanitaire, à l&amp;rsquo;aide d&amp;rsquo;outils grands publics, trouvables sur n&amp;rsquo;importe quel Store d&amp;rsquo;applications, comme le Google Play Store ou l&amp;rsquo;Apple Store. Par exemple, Barcode Scanner de ZXing Team sur le Google Play Store.&lt;/p&gt;
&lt;p&gt;Nous affirmons que la liste dressée par les sites gouvernmentaux est incomplète.&lt;/p&gt;
&lt;p&gt;Le pass est composé de 3 types d&amp;rsquo;informations :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;des informations techniques, qui permettent de vérifier l&amp;rsquo;authenticité du pass sanitaire ; on y retrouve des informations sur l&amp;rsquo;émetteur du pass sanitaire, ainsi que la date d&amp;rsquo;émission, et le sceau d&amp;rsquo;authenticité (une signature numérique) ;&lt;/li&gt;
&lt;li&gt;des informations personnelles : nom, prénom et date de naissance ;&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
  &lt;img src=&#34;https://broken-by-design.fr/pass_content.png&#34; alt=&#34;Décomposition du pass sanitaire&#34;&gt;

&lt;/p&gt;
&lt;p&gt;Au-delà de ces informations de santé, il est également possible d&amp;rsquo;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&amp;rsquo;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 ?&lt;/p&gt;
&lt;p&gt;Ces informations dépassent largement le cadre et la finalité du pass sanitaire.&lt;/p&gt;
&lt;p&gt;Les sites gouvernementaux (comme gouvernement.fr et servic public.fr) se veulent cependant rassurants. Ils précisent :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Pour accéder à un lieu, un établissement ou un événement, seuls les ouvreurs engagés par les organisateurs pourront lire :&lt;/p&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;nom et prénom ;&lt;/li&gt;
&lt;li&gt;date de naissance ;&lt;/li&gt;
&lt;li&gt;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é).&lt;/li&gt;
&lt;/ul&gt;&lt;/blockquote&gt;
&lt;p&gt;De même, M. Cédric O, secrétaire d&amp;rsquo;État, chargé de la transition numérique, indique dans son interview exclusive donnée au journal &lt;a href=&#34;https://www.leparisien.fr/societe/pass-sanitaire-carnet-de-rappel-numerique-cedric-o-devoile-les-nouveautes-de-tousanticovid-24-05-2021-BGOIIX3GSRH7XAUPCDZDMNZO3Y.php&#34;&gt;Le Parisien&lt;/a&gt; :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Comment les professionnels vérifieront-ils le pass sanitaire numérique ?&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Comme nous l&amp;rsquo;avons démontré plus tôt dans ce document, il n&amp;rsquo;existe aucune protection contre l&amp;rsquo;obtention de l&amp;rsquo;ensemble des données contenues dans le pass sanitaire. Tout lecteur de code barre grand public est suffisant. Il n&amp;rsquo;est nul besoin d&amp;rsquo;être membre d&amp;rsquo;une compagnie aérienne pour obtenir une application aux pouvoirs supérieurs permettant d&amp;rsquo;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&amp;rsquo;attente, ou à un personnel de sécurité à l&amp;rsquo;entrée d&amp;rsquo;un événement.&lt;/p&gt;
&lt;p&gt;Il existe également d&amp;rsquo;autres parties qui pourraient être mises au courant du contenu de votre pass sanitaire. D&amp;rsquo;après un &lt;a href=&#34;https://twitter.com/TousAntiCovid/status/1395317625161408512&#34;&gt;tweet du compte TousAntiCovid du 20 mai 2021&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;#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&amp;rsquo;@IN_Groupe respectant toutes les règles de sécurité des systèmes d&amp;rsquo;information.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Cette assertion est également corroborée par la demande de l&amp;rsquo;application TousAntiCovid Verif d&amp;rsquo;avoir un accès complet au réseau, lors de son installation. De même, on trouve dans les entrailles de l&amp;rsquo;application TousAntiCovid Verif, une URL (&lt;code&gt;https://portail.tacv.myservices-ingroupe.com&lt;/code&gt;), et ainsi qu&amp;rsquo;un fichier comportant une fonction &lt;code&gt;call2dDoc&lt;/code&gt;, qui fait une requête HTTP avec des paramètres &lt;code&gt;2ddoc&lt;/code&gt;, &lt;code&gt;latitude&lt;/code&gt; et &lt;code&gt;longitude&lt;/code&gt;. Enfin, lorsque l&amp;rsquo;on scanne un pass sanitaire en mode avion, TousAntiCovid Verif affiche un message d&amp;rsquo;erreur &amp;ldquo;Erreur de connexion&amp;rdquo; et n&amp;rsquo;affiche pas de résultat.&lt;/p&gt;
&lt;p&gt;Il n&amp;rsquo;est pas aisé de déterminer clairement ce que fait cette fonction, car l&amp;rsquo;application TousAntiCovid Verif, contrairement à l&amp;rsquo;application TousAntiCovid, n&amp;rsquo;est pas en sources ouvertes. Néanmoins, &lt;a href=&#34;https://twitter.com/gilbsgilbs&#34;&gt;gilbsgilbs&lt;/a&gt; a su faire de l&amp;rsquo;ingénierie inverse et &lt;a href=&#34;https://twitter.com/gilbsgilbs/status/1401129388234657794&#34;&gt;il confirme nos craintes et observations&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Il convient de noter qu&amp;rsquo;une telle communication réseau génère des meta-données de communication avec le serveur ; il y a notamment l&amp;rsquo;adresse IP de l&amp;rsquo;équipement faisant tourner l&amp;rsquo;application TousAntiCovid Verif. Cette adresse IP permet la géolocalisation de l&amp;rsquo;équipement faisant tourner TousAntiCovid Verif, par l&amp;rsquo;entremise des opérateurs de télécommunication, comme Orange.&lt;/p&gt;
&lt;p&gt;En croisant ces données, l&amp;rsquo;État serait donc en mesure de dresser un listing des citoyens et de leurs lieux de fréquentation, grâce au pass sanitaire.&lt;/p&gt;
&lt;p&gt;Il convient de noter que l&amp;rsquo;envoi des données (complètes ou sous la forme d&amp;rsquo;empreintes cryptographiques) n&amp;rsquo;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&amp;rsquo;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&amp;rsquo;est aussi pour la vérification de la signature.&lt;/p&gt;
&lt;p&gt;Nous ne sommes pas les seuls à dénoncer le pass sanitaire, et la quantité d&amp;rsquo;informations qu&amp;rsquo;il recèle. La CNIL, la Commission Nationale Informatique et Liberté, a été saisie et a rendu un avis le 12 mai 2021 :&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start=&#34;36&#34;&gt;
&lt;li&gt;
&lt;p&gt;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&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;&lt;/blockquote&gt;
&lt;p&gt;Hélas, aucune &amp;ldquo;mesure opérationnelle&amp;rdquo; significative n&amp;rsquo;a été mise en place par le gouvernement. Il aurait, par exemple, été possible d&amp;rsquo;émettre plusieurs pass, contenant plus ou moins d&amp;rsquo;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).&lt;/p&gt;
&lt;p&gt;Nous affirmons donc, que la mise en oeuvre du pass sanitaire, en l&amp;rsquo;état, constitue un risque significatif pour la vie privée, pour les données personnelles (risque de vol d&amp;rsquo;identité accru) et pour les données médicales des citoyens.&lt;/p&gt;
&lt;p&gt;Nous affirmons qu&amp;rsquo;il contient des informations sensibles sans aucun rapport avec la finalité énoncée.&lt;/p&gt;
&lt;p&gt;Nous affirmons qu&amp;rsquo;il peut être détourné pour pister les citoyens.&lt;/p&gt;
&lt;p&gt;Nous demandons le retrait du pass sanitaire dans sa forme actuelle.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Nous invitons les citoyens européens et les responsables politiques à s&amp;rsquo;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. &lt;/p&gt;
&lt;p&gt;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&amp;rsquo;en connaitre des employés de sécurité filtrant l&amp;rsquo;accès à un lieu.&lt;/p&gt;
&lt;p&gt;Finalement, nous exigeons que la vérification de l&amp;rsquo;authencité du pass sanitaire s&amp;rsquo;effectue localement par une application de vérification en source ouverte, sans avoir besoin de la permission d&amp;rsquo;accès au réseau. &lt;/p&gt;
&lt;p&gt;M. Cédric O s&amp;rsquo;indigne, dans son interview au Parisien :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;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.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Nous affirmons que la confiance ne s&amp;rsquo;exige pas, mais qu&amp;rsquo;elle s&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;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&amp;rsquo;ils l&amp;rsquo;avaient été, le pass sanitaire dans sa forme actuelle aurait été rejeté selon le principe de prudence, au nom de la protection des citoyens.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Autres documents :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;un &lt;a href=&#34;https://cq94.medium.com/la-fin-du-pseudonymat-dans-tousanticovid-932d50de11ee&#34;&gt;excellent article&lt;/a&gt; de Christian Quest, sur ce même sujet, qui confirme nos observations  ;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;un &lt;a href=&#34;https://twitter.com/MathisHammel/status/1397902091067265026&#34;&gt;fil de tweets de Mathis Hammel&lt;/a&gt;, qui faisait une analyse similaire à la nôtre, au même moment où nous tournions les rushs de notre vidéo ;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;une &lt;a href=&#34;https://twitter.com/BLeQuerrec/status/1401290053687644169&#34;&gt;application Android en preuve de concept&lt;/a&gt;, qui collecte et extrait les informations de pass sanitaires scannés, a été développée par Bastien Le Querrec ;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/ofa-/stopcovid-android&#34;&gt;une version alternative de TousAntiCovid&lt;/a&gt; maintenue par Olaf, qui contient notamment un lecteur/vérificateur du pass sanitaire au format 2D-DOC, prouvant la faisabilité d&amp;rsquo;une lecture et d&amp;rsquo;une vérification en local, sans avoir besoin des serveurs d&amp;rsquo;IN Groupe ;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;un &lt;a href=&#34;https://twitter.com/pixeldetracking/status/1401626317053992963&#34;&gt;fil de tweets de Pixel de Tracking&lt;/a&gt;, qui indique des trouvailles similaires à celles sur Android : le pass sanitaire est envoyé aux serveurs d&amp;rsquo;IN Groupe en totalité ;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/lovasoa/sanipasse&#34;&gt;une application web qui vérifie les pass sanitaires de manière autonome&lt;/a&gt; ;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://www.nextinpact.com/article/46153/pass-sanitaire-poudre-aux-yeux-pseudonymat-donnees-medicales-en-clair&#34;&gt;l&amp;rsquo;article de presse de NextInpact&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://www.numerama.com/tech/717219-tousanticovid-verif-pourquoi-lapp-verifiant-les-donnees-du-pass-sanitaire-fait-polemique.html&#34;&gt;l&amp;rsquo;article de press de Numerama&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://www.developpez.com/actu/315816/Application-TousAntiCovid-et-Pass-sanitaire-les-informations-personnelles-et-medicales-sont-disponibles-en-clair-previent-Christian-Quest/&#34;&gt;l&amp;rsquo;article de Developpez&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://www.igen.fr/ailleurs/2021/06/le-pass-sanitaire-souleve-des-craintes-en-matiere-de-confidentialite-123027&#34;&gt;l&amp;rsquo;article d&amp;rsquo;igen&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://www.01net.com/actualites/tousanticovid-verif-le-panier-perce-du-pass-sanitaire-2044056.html&#34;&gt;l&amp;rsquo;article de 01net&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://www.lemondeinformatique.fr/actualites/lire-tousanticovid-le-pass-sanitaire-en-quete-de-protection-83204.html&#34;&gt;l&amp;rsquo;article de lemondeinformatique.fr&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://www.mediapart.fr/journal/france/090621/donnees-personnelles-les-controles-du-passe-sanitaire-suscitent-linquietude&#34;&gt;l&amp;rsquo;article de Mediapart&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://www.contrepoints.org/2021/06/09/399255-donnees-medicales-anonymat-surveillance-un-pass-sanitaire-passoire&#34;&gt;l&amp;rsquo;article de Contrepoints&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://www.nextinpact.com/article/46147/pass-sanitaire-donnees-en-clair-open-source-on-fait-au-plus-simple&#34;&gt;l&amp;rsquo;article de NextInpact sur la réaction du gouvernement le 8 juin, en conférence de presse&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://www.cnil.fr/sites/default/files/atoms/files/deliberation_2021-067_du_7_juin_2021_portant_avis_sur_le_projet_de_decret_portant_application_du_ii_de_larticle_1er_de_la_loi_du_31_mai_2021.pdf&#34;&gt;la délibération de la CNIL du 7 juin (PDF)&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;Remerciements : Aurélien Hugues, Émilie Gill, Stéphane Bortzmeyer&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Historique d&amp;rsquo;édition :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;5 juin 2021 à 13h55 : ajout des références aux travaux de gilbsgilbs et de Christian Quest&lt;/li&gt;
&lt;li&gt;5 juin 2021 à 14h35 : ajout du fil de tweets de Mathis Hammel&lt;/li&gt;
&lt;li&gt;5 juin 2021 à 16h20 : ajout des remerciements&lt;/li&gt;
&lt;li&gt;6 juin 2021 à 8h45 : ajout de l&amp;rsquo;application en preuve de concept&lt;/li&gt;
&lt;li&gt;6 juin 2021 à 11h50 : ajout de la version alternative de TousAntiCovid par Olaf&lt;/li&gt;
&lt;li&gt;7 juin 2021 à 12h40 : corrections de coquilles, précisions sur les auteurs, rajout d&amp;rsquo;une réference à NextInpact, reformulation de la contribution d&amp;rsquo;Olaf&lt;/li&gt;
&lt;li&gt;7 juin 2021 à 13h30 : ajout du fil de tweets de Pixel de Tracking&lt;/li&gt;
&lt;li&gt;8 juin 2021 à 8h50 : ajout des articles de Numerama, de Developpez, et du code source de sanipasse&lt;/li&gt;
&lt;li&gt;8 juin à 19h15 : ajout des articles d&amp;rsquo;igen, de 01net et de lemondeinformatique.fr&lt;/li&gt;
&lt;li&gt;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&amp;rsquo;aurait pas été celle qu&amp;rsquo;elle a connue&lt;/li&gt;
&lt;li&gt;10 juin à 8h25 : ajout du bandeau de mise à jour en tête d&amp;rsquo;article concernant TousAntiCovid Verif&lt;/li&gt;
&lt;/ul&gt;
</description>
		</item>
		<item>
			<title>Attestation COVID-19 en ligne : un outil de surveillance globale sur Internet ?</title>
			<link>https://broken-by-design.fr/posts/attestation-covid-19/</link>
			<pubDate>Wed, 25 Nov 2020 22:00:00 +0000</pubDate>
			<guid isPermaLink="true">https://broken-by-design.fr/posts/attestation-covid-19/</guid>
			<description>&lt;p&gt;Cet article est sous licence CC-BY-NC-ND.&lt;/p&gt;
&lt;p&gt;Les auteurs de cet article peuvent être contactés sur :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;le numéro Signal : +33687414960 (Florian Maury)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;le compte Twitter : &lt;a href=&#34;https://twitter.com/piotrcki&#34;&gt;Piotr Chmielnicki - Twitter&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;le compte Twitter : &lt;a href=&#34;https://twitter.com/x_cli_public&#34;&gt;Florian Maury - Twitter&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;synthèse-non-technique&#34;&gt;Synthèse non-technique&lt;/h2&gt;
&lt;p&gt;Le Ministère de l&amp;rsquo;Intérieur, par l&amp;rsquo;intermédiaire du site permettant la génération d&amp;rsquo;attestations de déplacement dérogatoire COVID-19, est en mesure d&amp;rsquo;assurer un pistage nominatif des citoyens, en usant de procédés comparables à ceux qu&amp;rsquo;emploient les régies publicitaires et d&amp;rsquo;autres spécifiques aux services de renseignement. Il est impossible de prouver qu&amp;rsquo;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&amp;rsquo;ils le font ou l&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;Il n&amp;rsquo;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&amp;rsquo;éviter le risque en ne faisant pas usage de la fonctionnalité &amp;ldquo;Mon téléphone se souvient de moi&amp;rdquo;, ou en privilégiant les attestations au format papier. Si un citoyen a déjà utilisé la fonctionnalité &amp;ldquo;Mon téléphone se souvient de moi&amp;rdquo;, il est recommandé qu&amp;rsquo;il efface son historique de navigation, y compris les données mémorisées par le site web &lt;a href=&#34;https://media.interieur.gouv.fr&#34;&gt;https://media.interieur.gouv.fr&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Il est recommandé au Ministère de l&amp;rsquo;Intérieur de modifier le site web de génération des attestations de déplacement COVID-19 afin :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;de supprimer la fonctionnalité &amp;ldquo;Mon téléphone se souvient de moi&amp;rdquo; ; &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;d&amp;rsquo;automatiser l&amp;rsquo;effacement des données mémorisées précedemment ;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;d&amp;rsquo;héberger l&amp;rsquo;application sur une autre adresse que &lt;a href=&#34;https://media.interieur.gouv.fr&#34;&gt;https://media.interieur.gouv.fr&lt;/a&gt; ;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;dans le cas d&amp;rsquo;un maintien de la fonctionnalité de mémorisation, de supprimer la couche de chiffrement qui ne sert à rien d&amp;rsquo;autre qu&amp;rsquo;à induire un faux sentiment de sécurité ;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;de renforcer la sécurité de son site web (détail technique plus bas).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Une voie alternative pour le Ministère de l&amp;rsquo;Intérieur serait de fournir une application mobile en sources ouvertes dédiée à la génération d&amp;rsquo;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.&lt;/p&gt;
&lt;h2 id=&#34;présentation-succincte-de-lapplication-démission-dattestation&#34;&gt;Présentation succincte de l&amp;rsquo;application d&amp;rsquo;émission d&amp;rsquo;attestation&lt;/h2&gt;
&lt;p&gt;Pour le second confinement de 2020, le Ministère de l&amp;rsquo;Intérieur a publié une application en ligne pour l&amp;rsquo;émission d&amp;rsquo;attestation de déplacement dérogatoire COVID-19 à l&amp;rsquo;adresse : &lt;a href=&#34;https://media.interieur.gouv.fr/deplacement-covid-19/&#34;&gt;https://media.interieur.gouv.fr/deplacement-covid-19/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Cette application a subi notamment une mise à jour afin de permettre de mémoriser les informations saisies dans le formulaire, afin d&amp;rsquo;éviter d&amp;rsquo;avoir à retaper tous les renseignements à chaque nouvelle visite. Ce mécanisme est au coeur des risques évoqués dans cet article.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;application fonctionne à l&amp;rsquo;aide d&amp;rsquo;un formulaire dans lequel les citoyens saississent leurs informations d&amp;rsquo;é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 &amp;ldquo;mon téléphone se souvient de moi&amp;rdquo; 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.&lt;/p&gt;
&lt;p&gt;Lors du rechargement de la page, le localStorage est consulté afin d&amp;rsquo;auto-compléter le formulaire.&lt;/p&gt;
&lt;p&gt;Les informations sont stockées sous une forme de document JSON chiffré à l&amp;rsquo;aide &lt;a href=&#34;https://www.npmjs.com/package/secure-ls&#34;&gt;secure-ls&lt;/a&gt;. Secure-ls est un module Javascript permettant de chiffrer les données dans le localStorage afin d&amp;rsquo;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&amp;hellip;), et que l&amp;rsquo;implémentation contienne des versions Javascript de ces algorithmes alors qu&amp;rsquo;il existe &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API&#34;&gt;WebCrypto&lt;/a&gt;, le problème de l&amp;rsquo;implémentation du Ministère de l&amp;rsquo;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 :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;s3cr3t$#@135^&amp;amp;*246
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Autant dire que cette couche de chiffrement ne sert strictement à rien, et n&amp;rsquo;est là que pour donner une fausse impression de sécurité&amp;hellip; ou pour cacher ce que contient le localStorage aux yeux des curieux.&lt;/p&gt;
&lt;p&gt;Il se trouve que le localStorage ne contient rien de bien excitant : une entrée &lt;code&gt;_secure__ls__metadata&lt;/code&gt; qui contient un document JSON listant les autres entrées &amp;ldquo;sécurisées&amp;rdquo; du localStorage et leurs clés de chiffrement :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;{&amp;#34;keys&amp;#34;:[{&amp;#34;k&amp;#34;:&amp;#34;profile&amp;#34;,&amp;#34;s&amp;#34;:&amp;#34;7bebe7af384395d2ec6d383ac5380c4f&amp;#34;}]}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La clé &amp;ldquo;profile&amp;rdquo; contient l&amp;rsquo;état civil et des informations étrangement redondantes :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;firstname&amp;#34;: &amp;#34;Camille&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;lastname&amp;#34;: &amp;#34;Dupont&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;birthday&amp;#34;: &amp;#34;01/01/1970&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;placeofbirth&amp;#34;: &amp;#34;Paris&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;address&amp;#34;: &amp;#34;999 avenue de France&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;city&amp;#34;: &amp;#34;Paris&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;zipcode&amp;#34;: &amp;#34;75001&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;datesortie&amp;#34;: &amp;#34;24/11/2020&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;heuresortie&amp;#34;: &amp;#34;18:00&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;ox-travail&amp;#34;: &amp;#34;travail&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;ox-achats&amp;#34;: &amp;#34;achats&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;ox-sante&amp;#34;: &amp;#34;sante&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;ox-famille&amp;#34;: &amp;#34;famille&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;ox-handicap&amp;#34;: &amp;#34;handicap&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;ox-sport_animaux&amp;#34;: &amp;#34;sport_animaux&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;ox-convocation&amp;#34;: &amp;#34;convocation&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;ox-missions&amp;#34;: &amp;#34;missions&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;ox-enfants&amp;#34;: &amp;#34;enfants&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;À première vue, l&amp;rsquo;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&amp;rsquo;Intérieur, et même ce qui semble &amp;ldquo;caché&amp;rdquo; sous du chiffrement médiocre est en fait sans surprise ni risque.&lt;/p&gt;
&lt;p&gt;Quel est donc le problème décrit par cet article ?&lt;/p&gt;
&lt;h2 id=&#34;isolation-des-sites-web&#34;&gt;Isolation des sites web&lt;/h2&gt;
&lt;p&gt;Le web est un milieu dangereux ; s&amp;rsquo;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&amp;rsquo;origines diverses et d&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;Pour parrer à ce type de porosité, très tôt dans l&amp;rsquo;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&amp;rsquo;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 &lt;a href=&#34;http://example.com&#34;&gt;http://example.com&lt;/a&gt;, &lt;a href=&#34;http://exemple.net&#34;&gt;http://exemple.net&lt;/a&gt;, &lt;a href=&#34;http://broken-by-design.fr&#34;&gt;http://broken-by-design.fr&lt;/a&gt;, &lt;a href=&#34;https://broken-by-design.fr&#34;&gt;https://broken-by-design.fr&lt;/a&gt;, &lt;a href=&#34;https://www.broken-by-design.fr&#34;&gt;https://www.broken-by-design.fr&lt;/a&gt; et &lt;a href=&#34;https://www.broken-by-design.fr:8080&#34;&gt;https://www.broken-by-design.fr:8080&lt;/a&gt; sont toutes des applications séparées.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Il est ainsi impossible pour Facebook de consulter l&amp;rsquo;état civil stocké par l&amp;rsquo;application de génération des attestations COVID-19, par exemple.&lt;/p&gt;
&lt;h2 id=&#34;techniques-de-pistage-des-utilisateurs&#34;&gt;Techniques de pistage des utilisateurs&lt;/h2&gt;
&lt;p&gt;Les techniques de pistage des utilisateurs sont très nombreuses. Parmi ces dernières, les cookies sont un outil redoutable. &lt;/p&gt;
&lt;p&gt;Visiter un site A, puis visiter un site B. Les deux sites utilisent les services d&amp;rsquo;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&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;Les cookies ne sont qu&amp;rsquo;un des nombreux moyens à la disposition des régies publicitaires. Ils sont les plus pratiques car les cookies usent d&amp;rsquo;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&amp;rsquo;outil de stockage également employé par le site de génération des attestations COVID-19 du Ministère de l&amp;rsquo;Intérieur. Le localStorage est légèrement plus sécurisé (c&amp;rsquo;est-à-dire moins pratique pour les régies), mais il a le mérite d&amp;rsquo;avoir une durée de vie potentiellement illimitée, et de passer un peu plus sous le radar juridique.&lt;/p&gt;
&lt;h2 id=&#34;pistage-des-citoyens&#34;&gt;Pistage des citoyens&lt;/h2&gt;
&lt;p&gt;Les lecteurs les plus perspicaces auront déjà fait 1 + 1. &lt;/p&gt;
&lt;p&gt;Le citoyen soucieux de ne pas être sanctionné en cas d&amp;rsquo;absence d&amp;rsquo;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&amp;rsquo;application web du Ministère de l&amp;rsquo;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é à &lt;a href=&#34;https://media.interieur.gouv.fr/&#34;&gt;https://media.interieur.gouv.fr/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;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 &lt;a href=&#34;https://media.interieur.gouv.fr&#34;&gt;https://media.interieur.gouv.fr&lt;/a&gt;, qu&amp;rsquo;elle soit visible ou non, permettra potentiellement au Ministère de l&amp;rsquo;Intérieur d&amp;rsquo;associer cette visite à un état civil. Il s&amp;rsquo;agit d&amp;rsquo;un pistage nominatif, et non plus d&amp;rsquo;un pistage sur la base de pseudonymes (comme des identifiants numériques arbitraires ou des adresses IP).&lt;/p&gt;
&lt;p&gt;Mettons que l&amp;rsquo;on veuille préremplir un formulaire sur service-public.fr ; il suffit d&amp;rsquo;inclure une sous-page téléchargée depuis &lt;a href=&#34;https://media.interieur.gouv.fr&#34;&gt;https://media.interieur.gouv.fr&lt;/a&gt; et boom : service-public.fr peut collaborer avec media.interieur.gouv.fr pour obtenir les informations d&amp;rsquo;état civil ! (Par exemple, avec une technique d&amp;rsquo;affaiblissement de la SOP nommée &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage&#34;&gt;message passing&lt;/a&gt;, qui permet à des onglets de communiquer entre eux par messages.)&lt;/p&gt;
&lt;p&gt;Mettons que l&amp;rsquo;on veuille identifier les bons citoyens qui se rendent régulièrement sur le site gouvernement.fr : boom, même technique.&lt;/p&gt;
&lt;p&gt;Mettons qu&amp;rsquo;un service de renseignement peu scrupuleux des limites du droit français souhaite identifier les utilisateurs d&amp;rsquo;un site peu recommandable. Plusieurs options sont à sa disposition.&lt;/p&gt;
&lt;p&gt;La première possibilité serait l&amp;rsquo;exploitation d&amp;rsquo;une vulnérabilité de XSS (Cross Site Scripting) qui serait présente sur ce site. Cette vulnérabilité permet d&amp;rsquo;ajouter du code illégitime dans une page d&amp;rsquo;un site web. Les XSS font partie des vulnérabilités &lt;a href=&#34;https://owasp.org/www-project-top-ten/&#34;&gt;les plus communes du web&lt;/a&gt; ; cela ne semble donc pas improbable. Grâce à cette faille, il est possible d&amp;rsquo;ajouter une sous-page de &lt;a href=&#34;https://media.interieur.gouv.fr&#34;&gt;https://media.interieur.gouv.fr&lt;/a&gt; sur le site ciblé et boom : citoyen Camille Dupont a visité un site interdit !&lt;/p&gt;
&lt;p&gt;Une seconde solution pour ce service de renseignement, si le site peu recommandable est servi en HTTP : pratiquer l&amp;rsquo;attaque de l&amp;rsquo;homme du milieu (MITM). Cette attaque permet également d&amp;rsquo;injecter du code dans une page du site web.&lt;/p&gt;
&lt;p&gt;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&amp;rsquo;encontre des régies publicitaires, y compris &lt;a href=&#34;https://wiki.mozilla.org/Security/FirstPartyIsolation&#34;&gt;First Party Isolation de Mozilla&lt;/a&gt;, et son équivalent dans le Tor Browser. Cette technique utilise la redirection HTTP et une page web qui pourrait être hébergée sur &lt;a href=&#34;https://media.interieur.gouv.fr&#34;&gt;https://media.interieur.gouv.fr&lt;/a&gt;. Cette page web offrirait volontairement une vulnérabilité de type &lt;a href=&#34;https://cwe.mitre.org/data/definitions/601.html&#34;&gt;Open Redirect&lt;/a&gt; : en clair, dès que le Javascript de cette page est chargé, il enregistrerait les paramètres de la query string ainsi que l&amp;rsquo;état civil de l&amp;rsquo;utilisateur, puis effectuerait une redirection du navigateur (top level navigation) vers l&amp;rsquo;adresse du site web peu recommandable indiquée dans cette query string. &lt;/p&gt;
&lt;p&gt;Délibérée ou accidentelle, cette fonctionnalité est dangereuse pour les libertés des citoyens français.&lt;/p&gt;
&lt;p&gt;Pour les plus sceptiques, &lt;a href=&#34;https://covid.broken-by-design.fr/attestation.html&#34;&gt;un ensemble de sites de démonstration&lt;/a&gt; ont été mis en place, qui simulent ce que le Ministère de l&amp;rsquo;Intérieur peut faire.&lt;/p&gt;
&lt;h2 id=&#34;comment-sen-protéger-&#34;&gt;Comment s&amp;rsquo;en protéger ?&lt;/h2&gt;
&lt;p&gt;Une application mobile en sources ouvertes dédiée à la génération d&amp;rsquo;attestation est une voie intéressante : elle serait immunisée aux attaques web. La recommandation n&amp;rsquo;est cependant pas d&amp;rsquo;utiliser TousAntiCovid. &lt;a href=&#34;https://www.franceculture.fr/emissions/superfail/stopcovid-encore-une-appli-qui-a-plante&#34;&gt;Son modèle est voué à l&amp;rsquo;échec&lt;/a&gt; et &lt;a href=&#34;https://risques-tracage.fr&#34;&gt;présente des risques d&amp;rsquo;atteinte à la vie privée&lt;/a&gt;. De plus, TousAntiCovid accomplit de nombreuses autres missions qui nécessitent des privilèges supplémentaires, dont la connexion au réseau.&lt;/p&gt;
&lt;p&gt;Pour se protéger des risques de dévoiement du site de génération de l&amp;rsquo;attestation COVID-19, il n&amp;rsquo;existe aucune panacée au meilleur de la connaissance des auteurs de cet article. Il est donc recommandé :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;de ne pas enregistrer ses données en laissant décoché &amp;ldquo;Mon téléphone se souvient de moi&amp;rdquo; ou&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;d&amp;rsquo;é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).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Enfin, si vous avez utilisé la fonction de mémorisation des données personnelles par le passé, il convient d&amp;rsquo;effacer toutes les données stockées par le site &lt;a href=&#34;https://media.interieur.gouv.fr&#34;&gt;https://media.interieur.gouv.fr&lt;/a&gt;. Il est préférable de le faire en utilisant la fonctionnalité de nettoyage de l&amp;rsquo;historique du navigateur (en cochant bien la case d&amp;rsquo;effacement des données stockées par le site), plutôt que d&amp;rsquo;utiliser le bouton prévu à cet effet dans l&amp;rsquo;application web de génération des attestations (bien que celle-ci agisse correctement à l&amp;rsquo;heure de l&amp;rsquo;écriture de cet article).&lt;/p&gt;
&lt;h2 id=&#34;recommandations-au-ministère-de-lintérieur&#34;&gt;Recommandations au Ministère de l&amp;rsquo;Intérieur&lt;/h2&gt;
&lt;p&gt;Les recommandations principales sont de retirer la fonctionnalité de mémorisation de l&amp;rsquo;état civil, et d&amp;rsquo;ajouter un nettoyage automatique de ces données si elles ont été mémorisées par le passé.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;usage de l&amp;rsquo;origine &lt;a href=&#34;https://media.interieur.gouv.fr&#34;&gt;https://media.interieur.gouv.fr&lt;/a&gt; est un choix médiocre pour plusieurs raisons :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;de nombreuses ressources sont servies par cette origine ; la compromission d&amp;rsquo;une seule de ces ressources entraine la fuite des données personnelles (état civil) des citoyens français. L&amp;rsquo;isoler sur une origine dédié est une tâche prioritaire.&lt;/li&gt;
&lt;li&gt;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 &lt;a href=&#34;https://media.interieur.gouv.fr&#34;&gt;https://media.interieur.gouv.fr&lt;/a&gt;, il ne fera pas immédiatement le rapport avec le risque de pistage des citoyens. En utilisant une autre origine dédiée (&lt;a href=&#34;https://attestation-covid.media.interieur.gouv.fr&#34;&gt;https://attestation-covid.media.interieur.gouv.fr&lt;/a&gt;, par exemple), vous faîtes preuve de transparence et vous permettez à vos partenaires et vos citoyens de vérifier/douter d&amp;rsquo;une sous-page que vous voudriez qu&amp;rsquo;ils ajoutent à votre site web.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;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&amp;rsquo;écriture de cet article &lt;code&gt;X-XSS-Protection&lt;/code&gt; &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection&#34;&gt;qui est obsolète&lt;/a&gt;, HSTS (de manière adéquate, bravo), &lt;code&gt;x-content-type-options&lt;/code&gt;. Les auteurs de cet article recommandent l&amp;rsquo;ajout des entêtes suivants :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Content-Security-Policy&lt;/code&gt; (dont frame-ancestors &amp;rsquo;none&amp;rsquo;, script-src et default-src), afin de prévenir l&amp;rsquo;inclusion dans une sous-page et de charger du contenu malveillant en cas de XSS qui ne serait pas bloquée par &lt;code&gt;X-XSS-protection&lt;/code&gt; qui est obsolète ;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;X-Frame-Options: deny&lt;/code&gt; afin de prévenir l&amp;rsquo;inclusion dans des sous-pages ;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Cross-Origin-Opener-Policy: same-origin&lt;/code&gt; afin de prévenir la fuite d&amp;rsquo;information via l&amp;rsquo;ouverture de pop-ups par un attaquant (Spectre, etc.) ;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Cross-Origin-Resource-Policy: same-site&lt;/code&gt; afin de prévenir l&amp;rsquo;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 ;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Cross-Origin-Embedder-Policy: require-corp&lt;/code&gt; afin d&amp;rsquo;imposer l&amp;rsquo;usage de Cross-Origin-Resource-Policy&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;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 &lt;a href=&#34;https://www.ssi.gouv.fr/uploads/2015/01/RGS_v-2-0_B1.pdf&#34;&gt;Référentiel Général de Sécurité (RGS) - Annexe B1&lt;/a&gt;.&lt;/p&gt;
</description>
		</item>
		<item>
			<title>L’empoisonnement de cache DNS : toujours d’actualité ?</title>
			<link>https://broken-by-design.fr/posts/cache-poisoning/</link>
			<pubDate>Wed, 01 Jul 2020 00:00:00 +0000</pubDate>
			<guid isPermaLink="true">https://broken-by-design.fr/posts/cache-poisoning/</guid>
			<description>&lt;p&gt;Le &lt;abbr title=&#34;Domain Name System&#34;&gt;DNS&lt;/abbr&gt; 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 ?&lt;/p&gt;
&lt;h1 id=&#34;1-rappels-sur-le-fonctionnement-nominal-du-dns&#34;&gt;1. Rappels sur le fonctionnement nominal du DNS&lt;/h1&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Les données stockées dans le DNS sont d’ordres multiples : des adresses IP
(types A, AAAA&amp;hellip;), des informations utiles pour la livraison des courriers
électroniques (types MX, TXT&amp;hellip;), des politiques de sécurité (types TXT, TLSA&amp;hellip;),
des clés cryptographiques (types DNSKEY, TLSA&amp;hellip;), ou encore des informations
techniques nécessaires au bon fonctionnement et à la sécurisation du DNS
lui-même (types NS, RRSIG, DS&amp;hellip;). 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.&lt;/p&gt;
&lt;p&gt;
  &lt;figure&gt;
    &lt;img src=&#34;./arbo_0.jpg&#34; alt=&#34;Illustration de l’arborescence DNS&#34;&gt;
    &lt;figcaption&gt;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.&lt;/figcaption&gt;
  &lt;/figure&gt;

&lt;/p&gt;
&lt;p&gt;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é.&lt;/p&gt;
&lt;p&gt;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
&lt;code&gt;john.domaine-fictif.fr&lt;/code&gt; est délégué, et deux serveurs font autorité sur ce
dernier : &lt;code&gt;srv.autre-domaine.fr&lt;/code&gt;, et &lt;code&gt;truc.john.domaine-fictif.fr&lt;/code&gt;. Ces
informations de délégations sont fournies dans la section &lt;code&gt;Authority&lt;/code&gt; de la
réponse DNS. Nous verrons ultérieurement le rôle des sections dans les
empoisonnements de cache. Comme le nom de domaine &lt;code&gt;truc.john.domaine-fictif.fr&lt;/code&gt;
est situé à l’intérieur du domaine délégué &lt;code&gt;john.domaine-fictif.fr&lt;/code&gt;, une adresse
doit être fournie pour ce dernier, dans la section &lt;code&gt;Additional&lt;/code&gt; de la réponse
DNS de délégation.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ dig -t NS john.domaine-fictif.fr @ns1.domaine-fictif.fr
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;lt;snip&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;;;&lt;/span&gt; QUESTION SECTION:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;john.domaine-fictif.fr. IN NS
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;;;&lt;/span&gt; AUTHORITY SECTION:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;john.domaine-fictif.fr. &lt;span class=&#34;m&#34;&gt;172800&lt;/span&gt; IN NS srv.autre-domaine.fr.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;john.domaine-fictif.fr. &lt;span class=&#34;m&#34;&gt;172800&lt;/span&gt; IN NS truc.john.domaine-fictif.fr.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;;;&lt;/span&gt; ADDITIONAL SECTION:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;truc.john.domaine-fictif.fr. &lt;span class=&#34;m&#34;&gt;172800&lt;/span&gt; IN A 198.51.100.53
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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 &lt;code&gt;ping&lt;/code&gt;. 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).&lt;/p&gt;
&lt;p&gt;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).&lt;/p&gt;
&lt;p&gt;
  &lt;figure&gt;
    &lt;img src=&#34;./resolve_dns.jpg&#34; alt=&#34;Résolution DNS standard&#34;&gt;
    &lt;figcaption&gt;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.&lt;/figcaption&gt;
  &lt;/figure&gt;

&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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 &lt;abbr title=&#34;Small Office, Home Office&#34;&gt;SOHO&lt;/abbr&gt;
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.&lt;/p&gt;
&lt;p&gt;
  &lt;figure&gt;
    &lt;img src=&#34;./relais.jpg&#34; alt=&#34;Résolution DNS avec un relais&#34;&gt;
    &lt;figcaption&gt;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.&lt;/figcaption&gt;
  &lt;/figure&gt;

&lt;/p&gt;
&lt;h1 id=&#34;2-lempoisonnement-de-cache&#34;&gt;2. L’empoisonnement de cache&lt;/h1&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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 &lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;L’empoisonnement de cache peut généralement être exécuté par quatre vecteurs,
chacun objet d’une des sections suivantes.&lt;/p&gt;
&lt;h2 id=&#34;21-le-cas-décole--lattaque-de-lhomme-du-milieu&#34;&gt;2.1. Le cas d’école : l’attaque de l’homme du milieu&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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é.&lt;/p&gt;
&lt;p&gt;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 &lt;em&gt;ARP poisoning&lt;/em&gt;, afin de détourner le trafic local en se
faisant passer pour la passerelle du réseau. Sur Internet, en revanche, les
attaques &lt;abbr title=&#34;Address Resolution Protocol&#34;&gt;ARP&lt;/abbr&gt; ne sont pas possibles.
Détourner du trafic reste, bien entendu, possible, notamment grâce à des
attaques sur les protocoles de routage dynamiques comme  &lt;abbr title=&#34;Border Gateway Protocol&#34;&gt;BGP&lt;/abbr&gt;.
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 &lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;. La NSA a également monté le programme QUANTUMDNS pour
effectuer ce genre d’empoisonnement de cache &lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;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 ».&lt;/p&gt;
&lt;h2 id=&#34;22-la-compromission-des-serveurs-faisant-autorité-ou-de-la-chaîne-dapprovisionnement&#34;&gt;2.2. La compromission des serveurs faisant autorité ou de la chaîne d’approvisionnement&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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 &lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;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 &lt;sup id=&#34;fnref:5&#34;&gt;&lt;a href=&#34;#fn:5&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h2 id=&#34;23-lexploitation-de-bugs-de-logique-logicielle&#34;&gt;2.3. L’exploitation de bugs de logique logicielle&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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
&lt;a href=&#34;https://www.example.net&#34;&gt;www.example.net&lt;/a&gt;, 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 ?&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ dig -t A any1.abc.com
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;lt;snip&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;;;&lt;/span&gt; QUESTION SECTION:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;any1.abc.com.         IN    A
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;;;&lt;/span&gt; ANSWER SECTION:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;any1.abc.com.        IN    A    1.2.3.4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;;;&lt;/span&gt; AUTHORITY SECTION:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;abc.com.    &lt;span class=&#34;m&#34;&gt;172800&lt;/span&gt;    IN    NS    www.abc.com.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;;;&lt;/span&gt; ADDITIONAL SECTION:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;www.abc.com.        &lt;span class=&#34;m&#34;&gt;172800&lt;/span&gt;    IN    A    6.6.6.6
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La réponse n’est pas simple, car il y a de nombreux facteurs à considérer :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;sur quel(s) domaines(s) le serveur produisant la réponse fait-il autorité ;&lt;/li&gt;
&lt;li&gt;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) ;&lt;/li&gt;
&lt;li&gt;l’information reçue est-elle signée cryptographiquement, avec les extensions
de sécurité du DNS : DNSSEC.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Cela a notamment été documenté dans l’étude « &lt;em&gt;The Hitchhiker’s Guide to DNS
Cache Poisoning&lt;/em&gt; » &lt;sup id=&#34;fnref:6&#34;&gt;&lt;a href=&#34;#fn:6&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;6&lt;/a&gt;&lt;/sup&gt;, 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 &lt;a href=&#34;https://www.abc.com&#34;&gt;www.abc.com&lt;/a&gt; si
celle-ci a déjà été mémorisée dans le cadre d’une réponse où elle figurait dans
la section Answer.&lt;/p&gt;
&lt;p&gt;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 &lt;sup id=&#34;fnref:7&#34;&gt;&lt;a href=&#34;#fn:7&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;7&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h2 id=&#34;24-lattaque-à-laveugle&#34;&gt;2.4. L’attaque à l’aveugle&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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 :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;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
;&lt;/li&gt;
&lt;li&gt;la réponse doit être reçue (c’est-à-dire qu’elle doit être envoyée à la bonne
adresse IP et au bon port) ;&lt;/li&gt;
&lt;li&gt;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).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;À cela, il faut également ajouter les éventuelles informations spécifiques au
protocole de transport employé : UDP, TCP, D-TLS &lt;sup id=&#34;fnref:8&#34;&gt;&lt;a href=&#34;#fn:8&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;8&lt;/a&gt;&lt;/sup&gt;, TLS &lt;sup id=&#34;fnref:9&#34;&gt;&lt;a href=&#34;#fn:9&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;9&lt;/a&gt;&lt;/sup&gt; ou HTTP/2
&lt;sup id=&#34;fnref:10&#34;&gt;&lt;a href=&#34;#fn:10&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;10&lt;/a&gt;&lt;/sup&gt;. 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.&lt;/p&gt;
&lt;p&gt;D-TLS, quant à lui, introduit, entre autres, des éléments cryptographiques très
difficiles à deviner par un attaquant.&lt;/p&gt;
&lt;p&gt;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 :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;QXID au maximum 16 bits ;&lt;/li&gt;
&lt;li&gt;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 ;&lt;/li&gt;
&lt;li&gt;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 ;&lt;/li&gt;
&lt;li&gt;le port sur lequel la réponse doit être envoyée : si ce dernier est choisi
aléatoirement, selon les recommandations &lt;sup id=&#34;fnref:11&#34;&gt;&lt;a href=&#34;#fn:11&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;11&lt;/a&gt;&lt;/sup&gt; &lt;sup id=&#34;fnref:12&#34;&gt;&lt;a href=&#34;#fn:12&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;12&lt;/a&gt;&lt;/sup&gt;, au maximum 16 bits.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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é &lt;sup id=&#34;fnref:13&#34;&gt;&lt;a href=&#34;#fn:13&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;13&lt;/a&gt;&lt;/sup&gt; &lt;sup id=&#34;fnref:14&#34;&gt;&lt;a href=&#34;#fn:14&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;14&lt;/a&gt;&lt;/sup&gt; (note : le calcul
ci-dessus est faux, mais constitue une approximation compréhensible acceptable).&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h1 id=&#34;3-défenses&#34;&gt;3. Défenses&lt;/h1&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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é.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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’&lt;abbr title=&#34;Internet Engineering Task Force&#34;&gt;IETF&lt;/abbr&gt;,
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.&lt;/p&gt;
&lt;p&gt;Le principe de DNSSEC a déjà été détaillé de nombreuses fois dans MISC, ainsi
que dans un document publié par l’Afnic &lt;sup id=&#34;fnref:15&#34;&gt;&lt;a href=&#34;#fn:15&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;15&lt;/a&gt;&lt;/sup&gt;. 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.&lt;/p&gt;
&lt;p&gt;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&amp;hellip; 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&amp;hellip; pour peu que les domaines soient signés.&lt;/p&gt;
&lt;p&gt;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é.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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&amp;hellip; 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 !&lt;/p&gt;
&lt;p&gt;Plusieurs propositions ont été avancées pour combler cette absence.&lt;/p&gt;
&lt;p&gt;Le protocole DNSCrypt &lt;sup id=&#34;fnref:16&#34;&gt;&lt;a href=&#34;#fn:16&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;16&lt;/a&gt;&lt;/sup&gt; 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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h1 id=&#34;4-conclusion&#34;&gt;4. Conclusion&lt;/h1&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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) &lt;sup id=&#34;fnref:17&#34;&gt;&lt;a href=&#34;#fn:17&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;17&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h1 id=&#34;5-remerciements&#34;&gt;5. Remerciements&lt;/h1&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h1 id=&#34;6-références&#34;&gt;6. Références&lt;/h1&gt;
&lt;p&gt;Publié par les &lt;a href=&#34;https://connect.ed-diamond.com/MISC/mischs-021/l-empoisonnement-de-cache-dns-toujours-d-actualite&#34;&gt;Editions Diamond&lt;/a&gt; sous licence &lt;a href=&#34;https://creativecommons.org/licenses/by-nc-nd/4.0/deed.fr&#34;&gt;CC-BY-NC-ND&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;SMTP la killer-app de DNSSEC : &lt;a href=&#34;https://connect.ed-diamond.com/MISC/MISC-097/SMTP-la-killer-app-de-DNSSEC&#34;&gt;https://connect.ed-diamond.com/MISC/MISC-097/SMTP-la-killer-app-de-DNSSEC&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;Article sur l’attaque BGP pour détourner les serveurs DNS d’Amazon : &lt;a href=&#34;https://dyn.com/blog/bgp-hijack-of-amazon-dns-to-steal-crypto-currency/&#34;&gt;https://dyn.com/blog/bgp-hijack-of-amazon-dns-to-steal-crypto-currency/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;Quantum DNS : &lt;a href=&#34;https://arstechnica.com/information-technology/2015/01/nsa-secretly-hijacked-existing-malware-to-spy-on-n-korea-others/&#34;&gt;https://arstechnica.com/information-technology/2015/01/nsa-secretly-hijacked-existing-malware-to-spy-on-n-korea-others/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;Article sur l’attaque via Mark Monitor : &lt;a href=&#34;https://mashable.com/2014/02/01/syrian-electronic-army-ebay/&#34;&gt;https://mashable.com/2014/02/01/syrian-electronic-army-ebay/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:5&#34;&gt;
&lt;p&gt;Blog de Matthew Bryant : &lt;a href=&#34;https://thehackerblog.com/the-io-error-taking-control-of-all-io-domains-with-a-targeted-registration/&#34;&gt;https://thehackerblog.com/the-io-error-taking-control-of-all-io-domains-with-a-targeted-registration/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:5&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:6&#34;&gt;
&lt;p&gt;The Hitchhiker’s Guide to DNS Cache Poisoning : &lt;a href=&#34;https://www.cs.cornell.edu/~shmat/shmat_securecomm10.pdf&#34;&gt;https://www.cs.cornell.edu/~shmat/shmat_securecomm10.pdf&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:6&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:7&#34;&gt;
&lt;p&gt;Systemd-resolved DNS cache poisoning &lt;a href=&#34;https://seclists.org/oss-sec/2014/q4/592&#34;&gt;https://seclists.org/oss-sec/2014/q4/592&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:7&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:8&#34;&gt;
&lt;p&gt;DNS over Datagram Transport Layer Security (DTLS) : &lt;a href=&#34;https://www.rfc-editor.org/rfc/rfc8094.txt&#34;&gt;https://www.rfc-editor.org/rfc/rfc8094.txt&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:8&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:9&#34;&gt;
&lt;p&gt;Specification for DNS over Transport Layer Security (TLS) : &lt;a href=&#34;https://www.rfc-editor.org/rfc/rfc7858.txt&#34;&gt;https://www.rfc-editor.org/rfc/rfc7858.txt&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:9&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:10&#34;&gt;
&lt;p&gt;DNS Queries over HTTPS (DoH) : &lt;a href=&#34;https://www.rfc-editor.org/rfc/rfc8484.txt&#34;&gt;https://www.rfc-editor.org/rfc/rfc8484.txt&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:10&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:11&#34;&gt;
&lt;p&gt;DNS forgery : &lt;a href=&#34;http://cr.yp.to/djbdns/forgery.html&#34;&gt;http://cr.yp.to/djbdns/forgery.html&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:11&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:12&#34;&gt;
&lt;p&gt;Measures for Making DNS More Resilient against Forged Answers : &lt;a href=&#34;https://www.rfc-editor.org/rfc/rfc5452.txt&#34;&gt;https://www.rfc-editor.org/rfc/rfc5452.txt&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:12&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:13&#34;&gt;
&lt;p&gt;Blocking DNS messages is Dangerous : &lt;a href=&#34;https://www.ssi.gouv.fr/uploads/IMG/pdf/DNS-OARC-2013-Blocking_DNS_Messages_Is_Dangerous.pdf&#34;&gt;https://www.ssi.gouv.fr/uploads/IMG/pdf/DNS-OARC-2013-Blocking_DNS_Messages_Is_Dangerous.pdf&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:13&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:14&#34;&gt;
&lt;p&gt;Fragments Considered Poisonous : &lt;a href=&#34;https://u.cs.biu.ac.il/~herzbea/security/13-03-frag.pdf&#34;&gt;https://u.cs.biu.ac.il/~herzbea/security/13-03-frag.pdf&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:14&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:15&#34;&gt;
&lt;p&gt;Dossier DNSSEC de l’Afnic : &lt;a href=&#34;https://www.afnic.fr/data/divers/public/afnic-dossier-dnssec-2010-09.pdf&#34;&gt;https://www.afnic.fr/data/divers/public/afnic-dossier-dnssec-2010-09.pdf&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:15&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:16&#34;&gt;
&lt;p&gt;Site du projet DNSCrypt : &lt;a href=&#34;https://dnscrypt.info/&#34;&gt;https://dnscrypt.info/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:16&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:17&#34;&gt;
&lt;p&gt;Rapport de l’observatoire de la résilience de l’Internet français : &lt;a href=&#34;https://ssi.gouv.fr/observatoire&#34;&gt;https://ssi.gouv.fr/observatoire&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:17&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description>
		</item>
		<item>
			<title>Sondes de détection : performances, évaluations et biais</title>
			<link>https://broken-by-design.fr/posts/sondes/</link>
			<pubDate>Fri, 01 Nov 2019 00:00:00 +0000</pubDate>
			<guid isPermaLink="true">https://broken-by-design.fr/posts/sondes/</guid>
			<description>&lt;p&gt;En avril 2019, l’ANSSI a qualifié les premières sondes pour assurer la
supervision de sécurité de réseaux.
Les &lt;abbr title=&#34;opérateurs d’importance vitale&#34;&gt;OIV&lt;/abbr&gt;,
les &lt;abbr title=&#34;opérateurs de services essentiels&#34;&gt;OSE&lt;/abbr&gt; 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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h1 id=&#34;de-la-notion-de-budget&#34;&gt;De la notion de budget&lt;/h1&gt;
&lt;p&gt;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&amp;hellip;).&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h1 id=&#34;les-goulots-détranglement&#34;&gt;Les goulots d’étranglement&lt;/h1&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h2 id=&#34;pertes-par-la-carte-réseau&#34;&gt;Pertes par la carte réseau&lt;/h2&gt;
&lt;p&gt;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
&lt;abbr title=&#34;Direct Memory Access&#34;&gt;DMA&lt;/abbr&gt; ou des variantes, telles
qu’&lt;abbr title=&#34;I/O Acceleration Technology DMA&#34;&gt;IOAT/DMA&lt;/abbr&gt;).&lt;/p&gt;
&lt;p&gt;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’&lt;abbr title=&#34;I/O Memory Management Unit&#34;&gt;IOMMU&lt;/abbr&gt; &lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.
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.&lt;/p&gt;
&lt;h2 id=&#34;pertes-dans-le-noyau&#34;&gt;Pertes dans le noyau&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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 &lt;abbr title=&#34;eXpress Data Path&#34;&gt;XDP&lt;/abbr&gt;
très gourmands, ou des algorithmes peu performants de répartition des paquets
(load-balancing) entre les différents processeurs.&lt;/p&gt;
&lt;p&gt;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&amp;hellip;). Si les périphériques de stockage ne sont pas suffisamment
rapides, les appels système d’opération sur les fichiers (&lt;code&gt;write(2)&lt;/code&gt;,
&lt;code&gt;sync(2)&lt;/code&gt;&amp;hellip;) 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.&lt;/p&gt;
&lt;h2 id=&#34;pertes-dues-au-logiciel-de-détection&#34;&gt;Pertes dues au logiciel de détection&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Les moteurs d’analyse sont découpés, en interne, en plusieurs sous-tâches :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;acquérir de nouveaux paquets à traiter ;&lt;/li&gt;
&lt;li&gt;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 ? ») ;&lt;/li&gt;
&lt;li&gt;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 ;&lt;/li&gt;
&lt;li&gt;produire des journaux enregistrant les événements générés.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;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).&lt;/p&gt;
&lt;p&gt;Une analyse de performance assez poussée du logiciel de détection Suricata a été
conduite &lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; ; 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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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 &lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;. Le problème est que cette méthodologie ne
répartit pas correctement le trafic incluant des tunnels (IPsec, GRE, L2TP,
TLS&amp;hellip;). 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.&lt;/p&gt;
&lt;p&gt;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
&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;, à 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.&lt;/p&gt;
&lt;p&gt;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 &lt;sup id=&#34;fnref:5&#34;&gt;&lt;a href=&#34;#fn:5&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h1 id=&#34;biais-introduits-par-les-méthodologies-dévaluation&#34;&gt;Biais introduits par les méthodologies d’évaluation&lt;/h1&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h2 id=&#34;les-outils-pour-lémulation-de-réseaux&#34;&gt;Les outils pour l’émulation de réseaux&lt;/h2&gt;
&lt;p&gt;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 :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;tcpdump, qui permet la capture de trafic, le filtrage et le stockage dans des
fichiers PCAP &lt;sup id=&#34;fnref:6&#34;&gt;&lt;a href=&#34;#fn:6&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;6&lt;/a&gt;&lt;/sup&gt; ;&lt;/li&gt;
&lt;li&gt;tcpreplay, qui permet de rejouer des PCAP à plus ou moins grande vitesse, et
même d’éditer les PCAP &lt;sup id=&#34;fnref:7&#34;&gt;&lt;a href=&#34;#fn:7&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;7&lt;/a&gt;&lt;/sup&gt; ;&lt;/li&gt;
&lt;li&gt;TRex, de Cisco, qui constitue une plateforme de rejeu de trafic complète
[^TRex] ;&lt;/li&gt;
&lt;li&gt;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 &lt;sup id=&#34;fnref:8&#34;&gt;&lt;a href=&#34;#fn:8&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;8&lt;/a&gt;&lt;/sup&gt; ;&lt;/li&gt;
&lt;li&gt;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&amp;hellip;) avec le module netem &lt;sup id=&#34;fnref:9&#34;&gt;&lt;a href=&#34;#fn:9&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;9&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;tcpdump&#34;&gt;Tcpdump&lt;/h3&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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 &lt;sup id=&#34;fnref:10&#34;&gt;&lt;a href=&#34;#fn:10&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;10&lt;/a&gt;&lt;/sup&gt;. 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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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 (&lt;em&gt;timeout&lt;/em&gt;) agressifs sont employés.&lt;/p&gt;
&lt;h3 id=&#34;tcpreplay&#34;&gt;Tcpreplay&lt;/h3&gt;
&lt;p&gt;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
&lt;code&gt;--loop&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;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 (&lt;em&gt;timeout&lt;/em&gt;)
&lt;code&gt;CLOSE_WAIT&lt;/code&gt; configuré dans la sonde. Dans l’absolu, &lt;code&gt;CLOSE_WAIT&lt;/code&gt; 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 &lt;code&gt;CLOSE_WAIT&lt;/code&gt;
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.&lt;/p&gt;
&lt;p&gt;Pour éviter le biais précédent, il est possible d’utiliser l’option
&lt;code&gt;--unique-ip&lt;/code&gt; de tcpreplay qui fait varier les adresses IP à chaque nouvelle
itération d’un PCAP. Hélas, cette option conduit au second biais !&lt;/p&gt;
&lt;p&gt;Ce second biais est une amusante et improbable coïncidence. Il existe, en effet,
une interaction entre l’algorithme utilisé par &lt;code&gt;--unique-ip&lt;/code&gt; et certaines
méthodes de hachage des paquets en vue d’effectuer la répartition des paquets
entre les processus d’analyse !&lt;/p&gt;
&lt;p&gt;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$.&lt;/p&gt;
&lt;p&gt;De son côté, l’implémentation de &lt;code&gt;--unique-ip&lt;/code&gt; 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 !&lt;/p&gt;
&lt;h3 id=&#34;trex&#34;&gt;TRex&lt;/h3&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h3 id=&#34;scapy&#34;&gt;Scapy&lt;/h3&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h3 id=&#34;tc-qdisc&#34;&gt;Tc qdisc&lt;/h3&gt;
&lt;p&gt;tc qdisc (traffic control &amp;ndash; queue discipline) est un cadriciel reposant sur le
noyau Linux et des outils de l’espace utilisateur (&lt;em&gt;userland&lt;/em&gt;) 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 (&lt;em&gt;veth&lt;/em&gt;). 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&amp;hellip;).&lt;/p&gt;
&lt;h2 id=&#34;biais-introduits-par-linjection-de-flux-non-représentatifs&#34;&gt;Biais introduits par l’injection de flux non représentatifs&lt;/h2&gt;
&lt;p&gt;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 &lt;em&gt;jumbo frames&lt;/em&gt; (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.&lt;/p&gt;
&lt;p&gt;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).&lt;/p&gt;
&lt;p&gt;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&amp;hellip;) peuvent faire
exploser les états dans la sonde, comme cela a été détaillé plus haut dans cet
article.&lt;/p&gt;
&lt;h1 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;Au fil de cet article ont été présentés différents :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;goulots d’étranglement d’une sonde ;&lt;/li&gt;
&lt;li&gt;ressources critiques ;&lt;/li&gt;
&lt;li&gt;sources de lenteur ;&lt;/li&gt;
&lt;li&gt;biais pouvant être introduits involontairement lors de l’évaluation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;À 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.&lt;/p&gt;
&lt;p&gt;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 &lt;sup id=&#34;fnref:11&#34;&gt;&lt;a href=&#34;#fn:11&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;11&lt;/a&gt;&lt;/sup&gt; 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.&lt;/p&gt;
&lt;p&gt;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é.&lt;/p&gt;
&lt;h1 id=&#34;remerciements&#34;&gt;Remerciements&lt;/h1&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h1 id=&#34;références&#34;&gt;Références&lt;/h1&gt;
&lt;p&gt;Publié par les &lt;a href=&#34;https://connect.ed-diamond.com/MISC/misc-106/sondes-de-detection-performances-evaluations-et-biais&#34;&gt;Editions Diamond&lt;/a&gt; sous licence &lt;a href=&#34;https://creativecommons.org/licenses/by-nc-nd/4.0/deed.fr&#34;&gt;CC-BY-NC-ND&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;Neugebauer et alii., « Understanding PCIe performance for end host networking », août 2018&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;Étude sur l’incidence des verrous dans Suricata : &lt;a href=&#34;https://xbu.me/article/performance-characterization-of-suricata-thread-models/&#34;&gt;https://xbu.me/article/performance-characterization-of-suricata-thread-models/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;Document sur l’amélioration des performances d’acquisition de Suricata : &lt;a href=&#34;https://github.com/pevma/SEPTun&#34;&gt;https://github.com/pevma/SEPTun&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;Rapport d’incident de Cloudflare impliquant leur pare-feu applicatif web : &lt;a href=&#34;https://blog.cloudflare.com/cloudflare-outage/&#34;&gt;https://blog.cloudflare.com/cloudflare-outage/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:5&#34;&gt;
&lt;p&gt;Exemples cassant le modèle de threads collaboratifs de Lua : &lt;a href=&#34;https://stackoverflow.com/a/18964444&#34;&gt;https://stackoverflow.com/a/18964444&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:5&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:6&#34;&gt;
&lt;p&gt;Site de l’outil Tcpdump : &lt;a href=&#34;https://www.tcpdump.org/&#34;&gt;https://www.tcpdump.org/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:6&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:7&#34;&gt;
&lt;p&gt;Site de l’outil Tcpreplay : &lt;a href=&#34;https://tcpreplay.appneta.com/&#34;&gt;https://tcpreplay.appneta.com/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:7&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:8&#34;&gt;
&lt;p&gt;Dépôt de l’outil Scapy : &lt;a href=&#34;https://github.com/secdev/scapy&#34;&gt;https://github.com/secdev/scapy&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:8&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:9&#34;&gt;
&lt;p&gt;Documentation sur l’émulation d’incidents réseau avec Traffic Control : &lt;a href=&#34;https://wiki.linuxfoundation.org/networking/netem#packet_duplication&#34;&gt;https://wiki.linuxfoundation.org/networking/netem#packet_duplication&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:9&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:10&#34;&gt;
&lt;p&gt;Script permettant de nettoyer les demi-flux : &lt;a href=&#34;https://frama.link/RfNczV0d&#34;&gt;https://frama.link/RfNczV0d&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:10&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:11&#34;&gt;
&lt;p&gt;Site de la certification ISA Secure : &lt;a href=&#34;https://www.isasecure.org/en-US/&#34;&gt;https://www.isasecure.org/en-US/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:11&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description>
		</item>
		<item>
			<title>Python String Emptiness Test</title>
			<link>https://broken-by-design.fr/posts/python-string-emptiness/</link>
			<pubDate>Mon, 25 Mar 2019 00:00:00 +0000</pubDate>
			<guid isPermaLink="true">https://broken-by-design.fr/posts/python-string-emptiness/</guid>
			<description>&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Is that a useful use of their time? That question is open to debate ;p&lt;/p&gt;
&lt;p&gt;But I believe writing about them IS a useful use of my time on a gray Sunday
morning!&lt;/p&gt;
&lt;h1 id=&#34;python-string-emptiness-test&#34;&gt;Python String Emptiness Test&lt;/h1&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;He wrote this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;should_i_do_smth&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;bool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;some_string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;some_int&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I wrote that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;should_i_do_smth&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;some_string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;some_int&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The only use case of that function was in an if condition:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;should_i_do_smth&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;The poll was:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;According to you, which of the four following lines of #Python code (poll) is
the most &lt;em&gt;self-explanatory&lt;/em&gt; and the &lt;em&gt;safest&lt;/em&gt; to express that the string
variable &amp;ldquo;value&amp;rdquo; is not empty? All answers are valid Python.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;if value:&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;if bool(value):&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;if len(value) != 0:&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;if value != &#39;&#39;:&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/blockquote&gt;
&lt;h2 id=&#34;regarding-the-poll-itself&#34;&gt;Regarding the poll itself&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;People who answered the poll may have read differently:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;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)?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;String variable: did I mean &lt;code&gt;str&lt;/code&gt; or &lt;code&gt;Optional[str]&lt;/code&gt;, only Unicode string
(&lt;code&gt;&#39;&#39;&lt;/code&gt;) or also bytestring (&lt;code&gt;b&#39;&#39;&lt;/code&gt;)? Was there a test to control the type? Or
static typing analysis?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Not empty: did I mean that we should refuse the empty string only, or should
we also refuse None?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;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?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;At the time of writing, with 54 voters, the poll results is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;if value:&lt;/code&gt; 38%&lt;/li&gt;
&lt;li&gt;&lt;code&gt;if bool(value):&lt;/code&gt; 4%&lt;/li&gt;
&lt;li&gt;&lt;code&gt;if len(value) != 0:&lt;/code&gt; 34%&lt;/li&gt;
&lt;li&gt;&lt;code&gt;if value != &#39;&#39;:&lt;/code&gt; 24%&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;answer-analysis&#34;&gt;Answer analysis&lt;/h2&gt;
&lt;p&gt;Each of the poll answers is valid Python, but they all also have merits.&lt;/p&gt;
&lt;h3 id=&#34;first-answer&#34;&gt;&lt;!-- raw HTML omitted --&gt;&lt;!-- raw HTML omitted --&gt;First Answer&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;if value:&lt;/code&gt; 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 &lt;code&gt;&#39;&#39;&lt;/code&gt; is
evaluated to False in the context of a condition expression.&lt;/p&gt;
&lt;p&gt;To some extent, it is comparable to the following C code :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;instructions&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This code plays on the fact that a &lt;code&gt;NULL&lt;/code&gt; pointer values 0, which is evaluated
to &lt;code&gt;False&lt;/code&gt; in C. It also plays on the fact that if the string is empty, the
first character will be the &lt;code&gt;NULL&lt;/code&gt; byte (&lt;code&gt;\0&lt;/code&gt;), which is also evaluated to
&lt;code&gt;False&lt;/code&gt;. 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.&lt;/p&gt;
&lt;p&gt;But the real issue of this syntax is that there is absolutely no type checking
whatsoever. That&amp;rsquo;s not really a problem if you embrace Python&amp;rsquo;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 &lt;code&gt;value&lt;/code&gt; variable is a Unicode string, this approach
bares no risks.&lt;/p&gt;
&lt;p&gt;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?&lt;/p&gt;
&lt;p&gt;I mean, this can happen easily when you refactor your code or when you meddle
with some code you don&amp;rsquo;t fully understand. Sure, unit tests and static analysis
are valid answers to refactoring problems&amp;hellip; but let&amp;rsquo;s be honest here:
correctly written unit tests are not frequent in the startup industry.&lt;/p&gt;
&lt;p&gt;And mistakes happen. One of my followers told me a &amp;ldquo;war story&amp;rdquo;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Yeah, that&amp;rsquo;s it ^_^ A colleague of them wrote this test to guard against the
&lt;code&gt;None&lt;/code&gt; value&amp;hellip; but &lt;code&gt;i&lt;/code&gt; was an integer. And some day, that integer equaled 0.
If you don&amp;rsquo;t know, 0, in Python, is evaluated as &lt;code&gt;False&lt;/code&gt; in a condition
expression.  Oops.&lt;/p&gt;
&lt;p&gt;But let&amp;rsquo;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 &lt;code&gt;__bool__&lt;/code&gt;
or &lt;code&gt;__len__&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;In Python, truth evaluation on arbitrary object is done by trying to call
&lt;code&gt;__bool__&lt;/code&gt; that should return the truth value for this object. If &lt;code&gt;__bool__&lt;/code&gt; is
not implemented, &lt;code&gt;__len__&lt;/code&gt; is tried. If &lt;code&gt;__len__&lt;/code&gt; returns 0, then the
evaluation result is &lt;code&gt;False&lt;/code&gt;, else &lt;code&gt;True&lt;/code&gt;. Finally, if &lt;code&gt;__len__&lt;/code&gt; is not
implemented, then it returns &lt;code&gt;True&lt;/code&gt; for variable that are not &lt;code&gt;None&lt;/code&gt; nor a
scalar that evaluates to &lt;code&gt;None&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;Test&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;fm&#34;&gt;__bool__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;gt;&amp;gt;Bool!&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Test&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;gt;&amp;gt;Hey!&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;gt;&amp;gt;Bool!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;gt;&amp;gt;Hey!
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;Test&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;fm&#34;&gt;__len__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;gt;&amp;gt;Len!&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Test&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;gt;&amp;gt;Hey!&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;gt;&amp;gt;Len!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;gt;&amp;gt;Hey!
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;Test&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;fm&#34;&gt;__len__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;gt;&amp;gt;Len!&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Test&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;gt;&amp;gt;Hey!&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;gt;&amp;gt;Len!
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;Test&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;pass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Test&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;gt;&amp;gt;Hey!&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;gt;&amp;gt;Hey!
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;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 &lt;code&gt;value&lt;/code&gt; variable is capable of,
resulting in the infamous &lt;code&gt;AttributeError: &#39;Foo&#39; object has no attribute &#39;bar&#39;&lt;/code&gt;. Or worse: no crash and a very stupid result.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;So, if you hinted that the type of value was &lt;code&gt;str&lt;/code&gt; before the &lt;code&gt;if value:&lt;/code&gt;
statement, then your code is probably safe and robust if you use a static
analyzer.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;foo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you do not have a type hint and you don&amp;rsquo;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.&lt;/p&gt;
&lt;h3 id=&#34;second-answer&#34;&gt;&lt;!-- raw HTML omitted --&gt;&lt;!-- raw HTML omitted --&gt;Second Answer&lt;/h3&gt;
&lt;p&gt;The second answer is nonsensical and I admittedly did a poor job at
representing the opinion of my colleague when writing this poll. Let&amp;rsquo;s put it
on the fact that I was forced to use their solution.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;if bool(value):&lt;/code&gt; 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.&lt;/p&gt;
&lt;p&gt;For instance, in the following code, what would you replace &lt;strong&gt;XXX&lt;/strong&gt; with?&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;foo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Tuple&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;some instructions&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;bar&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;XXX&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;foo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;s&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you answered &lt;code&gt;bool&lt;/code&gt;, you are wrong. &lt;strong&gt;XXX&lt;/strong&gt; must be replaced by &lt;code&gt;Union[str, int]&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;error: Incompatible return value type (got &amp;#34;Union[str, int]&amp;#34;, expected &amp;#34;bool&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s because Python logical operators do not return booleans! In the case of
the &lt;code&gt;and&lt;/code&gt; operator, it returns the first value that cannot be evaluated to
&lt;code&gt;True&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Thus, if you meant the bar function to return a boolean, you need to cast the
whole expression as bool before returning it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;bar&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;bool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;foo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;bool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can also only cast elements that are not comparisons, because, at least,
comparisons do return booleans:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;bar&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;bool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;foo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;bool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#39;&amp;#39;#include &amp;lt;stdio.h&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;int main(){
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;  printf(&amp;#34;&amp;gt; %d\n&amp;#34;, 2 &amp;amp;&amp;amp; 3);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;  return 0;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;}&amp;#39;&amp;#39;&amp;#39;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; gcc -o /tmp/condition -x c -
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ /tmp/condition
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;gt;1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ php -r &lt;span class=&#34;s1&#34;&gt;&amp;#39;echo 2 &amp;amp;&amp;amp; 3;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h3 id=&#34;third-answer&#34;&gt;&lt;!-- raw HTML omitted --&gt;&lt;!-- raw HTML omitted --&gt;Third Answer&lt;/h3&gt;
&lt;p&gt;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 &lt;code&gt;value&lt;/code&gt; variable is studied and must not
be equal to 0 and it returns an unambiguous result: a truth value: True or
False.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;TypeError: object of type &amp;#39;NoneType&amp;#39; has no len()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;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 &lt;code&gt;AttributeError: &#39;NoneType&#39; object has no attribute &#39;foo&#39;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;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?&lt;/p&gt;
&lt;p&gt;Unfortunately, this answer is also susceptible to cause late crashes because of
duck typing. The &lt;code&gt;len()&lt;/code&gt; function is only a keyword that calls on the &lt;code&gt;__len__&lt;/code&gt;
implementation of the receiver (that is the object provided as &lt;code&gt;len()&lt;/code&gt;&amp;rsquo;s
argument. This means that this test won&amp;rsquo;t guard against objects implementing
&lt;code&gt;__len__&lt;/code&gt;, just like &lt;code&gt;str&lt;/code&gt;, but not being a string. The perfect builtin example
would be the bytestring.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;sa&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;bonjour&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;l&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;split&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;o&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;TypeError: a bytes-like object is required, not &amp;#39;str&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;All in all, this answer is relatively explicit in what is tested and what&amp;rsquo;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.&lt;/p&gt;
&lt;h3 id=&#34;fourth-answer&#34;&gt;&lt;!-- raw HTML omitted --&gt;&lt;!-- raw HTML omitted --&gt;Fourth Answer&lt;/h3&gt;
&lt;p&gt;The fourth answer is pretty straightforward. The meaning is crystal clear: it
evaluates to &lt;code&gt;True&lt;/code&gt; as long as &lt;code&gt;value&lt;/code&gt; is not the empty Unicode string. Anybody
gifted with eyes can read this expression and understand what is the intent of
the author.&lt;/p&gt;
&lt;p&gt;It won&amp;rsquo;t be abused by the empty bytestring. It won&amp;rsquo;t be abused by the &lt;code&gt;None&lt;/code&gt;
value. It won&amp;rsquo;t be abused by objects implementing &lt;code&gt;__str__&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;Test&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;fm&#34;&gt;__str__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Test&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Foo&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Foo
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Wait, what? It printed &lt;code&gt;Foo&lt;/code&gt;?! 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.&lt;/p&gt;
&lt;p&gt;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:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;isinstance&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(note: using &lt;code&gt;isinstance()&lt;/code&gt; is prefered to &lt;code&gt;type(value) is str&lt;/code&gt; just in case
someone got the extra-weird idea to subclass &lt;code&gt;str&lt;/code&gt;; don&amp;rsquo;t do that.
Unfortunately, &lt;code&gt;type(value) is str&lt;/code&gt; would have been so much more readable)&lt;/p&gt;
&lt;h2 id=&#34;a-word-about-efficiency&#34;&gt;A Word About Efficiency&lt;/h2&gt;
&lt;p&gt;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).&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;For 10 million iterations, run 100 times to clear out statistical noise, the
average results are:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Answer&lt;/th&gt;
          &lt;th&gt;Time&lt;/th&gt;
          &lt;th&gt;Ratio&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;First&lt;/td&gt;
          &lt;td&gt;1.28s&lt;/td&gt;
          &lt;td&gt;1&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Second&lt;/td&gt;
          &lt;td&gt;2.81s&lt;/td&gt;
          &lt;td&gt;2.19&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Third&lt;/td&gt;
          &lt;td&gt;1.92s&lt;/td&gt;
          &lt;td&gt;1.5&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Fourth&lt;/td&gt;
          &lt;td&gt;1.52s&lt;/td&gt;
          &lt;td&gt;1.19&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h1 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;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&amp;rsquo;s the case of the third answer
that will make pylint, a Python code linter, complain about the use of &lt;code&gt;len()&lt;/code&gt;
to test if an sequence is empty (because a &lt;code&gt;str&lt;/code&gt; is also an character
sequence):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Do not use `len(SEQUENCE)` to determine if a sequence is empty (len-as-condition)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Overall, my personal belief is that the fourth answer (especially when guarded
with the &lt;code&gt;isinstance()&lt;/code&gt; call) should be prefered because the developer&amp;rsquo;s intent
is explicit and one gets exactly what they asked for, without any of the magic
offered by the language.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Please post your comments as answers on &lt;a href=&#34;https://twitter.com/X_Cli_Public/status/1110275080221806593&#34;&gt;Twitter&lt;/a&gt; or on the &lt;a href=&#34;https://infosec.exchange/@x_cli/101813137227224905&#34;&gt;Fediverse&lt;/a&gt;!&lt;/p&gt;
</description>
		</item>
		<item>
			<title>About</title>
			<link>https://broken-by-design.fr/about/</link>
			<pubDate>Sun, 24 Mar 2019 23:22:48 +0100</pubDate>
			<guid isPermaLink="true">https://broken-by-design.fr/about/</guid>
			<description>&lt;p&gt;My name is Florian Maury. I am a network and protocol security specialist.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;./cv.pdf&#34;&gt;My resume&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;My social media links:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&#34;me&#34; href=&#34;https://infosec.exchange/@X_Cli&#34;&gt;Fediverse&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My Contact Info:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;mailto:florian.maury-website@broken-by-design.fr&#34;&gt;florian.maury-website@broken-by-design.fr&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
		</item>
		<item>
			<title>A PKI Rant: the Free (as in free beer) Certificate Problem</title>
			<link>https://broken-by-design.fr/posts/pki-rant/</link>
			<pubDate>Wed, 24 Oct 2018 00:00:00 +0000</pubDate>
			<guid isPermaLink="true">https://broken-by-design.fr/posts/pki-rant/</guid>
			<description>&lt;h1 id=&#34;intro&#34;&gt;Intro&lt;/h1&gt;
&lt;p&gt;Someone asked me what I had to object to &lt;a href=&#34;https://scotthelme.co.uk/debunking-the-fallacy-that-paid-certificates-are-better-than-free-certificates-and-other-related-nonsense/&#34;&gt;this article&lt;/a&gt; about free certificates versus paying ones.&lt;/p&gt;
&lt;h1 id=&#34;the-competing-interests-problem&#34;&gt;The competing interests problem&lt;/h1&gt;
&lt;p&gt;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&amp;rsquo;t feel like I am not FUDing, or I would not speak up. I think I am just being extra precautious.&lt;/p&gt;
&lt;p&gt;First, I find amusing that many people like to quote &amp;ldquo;if that is free, then you are the product&amp;rdquo;, but when it comes to Let&amp;rsquo;s Encrypt, they forget this statement and enjoy their certificates carelessly. So, you might ask: &amp;ldquo;How am I a product, when I am a client of Let&amp;rsquo;s Encrypt? They are not selling my information, and even if they were, all they have on me and my website are public data&amp;rdquo;. True. Your information is not a good for Let&amp;rsquo;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 &lt;a href=&#34;https://letsencrypt.org/2016/09/20/what-it-costs-to-run-lets-encrypt.html&#34;&gt;Let&amp;rsquo;s Encrypt staffing budget&lt;/a&gt; was a whooping $2.06M for 10 people in 2017 ). So if you get your certificates for free, someone is paying for them. Let&amp;rsquo;s see, &amp;ldquo;platinum sponsors&amp;rdquo; (over $300K annually):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;EFF: OK.&lt;/li&gt;
&lt;li&gt;OVH: they make a heavy usage of Let&amp;rsquo;s Encrypt for their shared hosting; OK.&lt;/li&gt;
&lt;li&gt;Cisco and Akamai: hmm, OK.&lt;/li&gt;
&lt;li&gt;Mozilla and Chrome? Uh-oh.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You see, if Let&amp;rsquo;s Encrypt is giving certificates for free, other CAs won&amp;rsquo;t sell any, because people know that there is no difference between a paying DV certificate and a Let&amp;rsquo;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&amp;rsquo;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&amp;rsquo;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&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;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&amp;rsquo;s funding to exist and operate properly?&lt;/p&gt;
&lt;h1 id=&#34;the-certificate-transparency-problem&#34;&gt;The Certificate Transparency problem&lt;/h1&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;You see, Let&amp;rsquo;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 (&amp;ldquo;public&amp;rdquo;) CAs are registered, for them to be publicly auditable. The important word in the previous sentence is &amp;ldquo;append-only&amp;rdquo;. 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.&lt;/p&gt;
&lt;h1 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;If DV certificate price was low but non-null, commercial CAs would still be able to exist, and Let&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;This content was originally posted by myself on &lt;a href=&#34;Fediverse.blog&#34;&gt;https://fediverse.blog/~/InfiniteTypingPlatypuses/a-pki-rant-the-free-as-in-beer-certificate-problem&lt;/a&gt;.&lt;/p&gt;
</description>
		</item>
		<item>
			<title>SMTP : la « killer app » de DNSSEC</title>
			<link>https://broken-by-design.fr/posts/smtp-killer-app-dnssec/</link>
			<pubDate>Tue, 01 May 2018 00:00:00 +0000</pubDate>
			<guid isPermaLink="true">https://broken-by-design.fr/posts/smtp-killer-app-dnssec/</guid>
			<description>&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h1 id=&#34;1-état-des-lieux&#34;&gt;1. État des lieux&lt;/h1&gt;
&lt;p&gt;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 &lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h2 id=&#34;11-tls-pour-smtp&#34;&gt;1.1. TLS pour SMTP&lt;/h2&gt;
&lt;p&gt;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é &lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;À 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 [&amp;ldquo;SaferEmail]. Il y est notamment possible d’observer le pourcentage
de courriers envoyés sur un canal chiffré, par domaine expéditeur/destinataire.&lt;/p&gt;
&lt;p&gt;L’ANSSI a également rédigé une charte &lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;, 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).&lt;/p&gt;
&lt;p&gt;Finalement, le BSI a publié un document &lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt; 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.&lt;/p&gt;
&lt;h2 id=&#34;12-dnssec&#34;&gt;1.2. DNSSEC&lt;/h2&gt;
&lt;p&gt;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 : &lt;abbr title=&#34;DNS-based Authentication of Named Entities&#34;&gt;DANE&lt;/abbr&gt; &lt;sup id=&#34;fnref:5&#34;&gt;&lt;a href=&#34;#fn:5&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;, &lt;abbr title=&#34;Certification Authority Authorization&#34;&gt;CAA&lt;/abbr&gt;
&lt;sup id=&#34;fnref:6&#34;&gt;&lt;a href=&#34;#fn:6&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;6&lt;/a&gt;&lt;/sup&gt; 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 &lt;sup id=&#34;fnref:7&#34;&gt;&lt;a href=&#34;#fn:7&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;7&lt;/a&gt;&lt;/sup&gt; &lt;sup id=&#34;fnref:8&#34;&gt;&lt;a href=&#34;#fn:8&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;8&lt;/a&gt;&lt;/sup&gt;. 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 &lt;sup id=&#34;fnref1:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;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 &lt;sup id=&#34;fnref:9&#34;&gt;&lt;a href=&#34;#fn:9&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;9&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h2 id=&#34;13-spf&#34;&gt;1.3. SPF&lt;/h2&gt;
&lt;p&gt;&lt;abbr title=&#34;Sender Policy Framework&#34;&gt;SPF&lt;/abbr&gt; &lt;sup id=&#34;fnref:10&#34;&gt;&lt;a href=&#34;#fn:10&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;10&lt;/a&gt;&lt;/sup&gt; 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 &lt;a href=&#34;mailto:john@example.com&#34;&gt;john@example.com&lt;/a&gt;, l’enregistrement SPF suivant sera consulté :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;example.com. 86400 IN TXT “v=spf1 ip4:192.0.2.1 -all”
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Le déploiement de SPF pour les domaines délégués depuis le nom de domaine de
premier niveau (en anglais, &lt;abbr title=&#34;Top-Level Domain&#34;&gt;TLD&lt;/abbr&gt;) « .fr » est
d’environ 37%. Cependant, seuls 7,4% des zones étudiées contiennent des
enregistrements SPF signés avec DNSSEC.&lt;/p&gt;
&lt;h2 id=&#34;14-dkim&#34;&gt;1.4. DKIM&lt;/h2&gt;
&lt;p&gt;&lt;abbr title=&#34;DomainKeys Identified Mail&#34;&gt;DKIM&lt;/abbr&gt; Signatures &lt;sup id=&#34;fnref:11&#34;&gt;&lt;a href=&#34;#fn:11&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;11&lt;/a&gt;&lt;/sup&gt; 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.&lt;/p&gt;
&lt;p&gt;La signature DKIM est placée dans les en-têtes d’un courrier électronique. En
voici un exemple :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;DKIM-Signature: d=example.net; s=chaine_arbitraire; …
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;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 &lt;code&gt;d=&lt;/code&gt; de la
signature, préfixée de la chaîne constante &lt;code&gt;_domainkey&lt;/code&gt;, 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
&lt;code&gt;s=&lt;/code&gt; de la signature). Ainsi pour la signature donnée en exemple ci-dessus,
l’enregistrement DNS suivant est récupéré :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chaine_arbitraire._domainkey.example.net. 86400 IN TXT “v=DKIM1; k=rsa; p=base64clef”
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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 &lt;sup id=&#34;fnref:12&#34;&gt;&lt;a href=&#34;#fn:12&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;12&lt;/a&gt;&lt;/sup&gt;.
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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h2 id=&#34;15-dmarc&#34;&gt;1.5. DMARC&lt;/h2&gt;
&lt;p&gt;&lt;abbr title=&#34;Domain-based Message Authentication, Reporting and Conformance&#34;&gt;DMARC&lt;/abbr&gt; &lt;sup id=&#34;fnref:13&#34;&gt;&lt;a href=&#34;#fn:13&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;13&lt;/a&gt;&lt;/sup&gt; 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 &lt;code&gt;_dmarc&lt;/code&gt; du domaine de l’expéditeur d’un courrier, dont voici un
exemple :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;_dmarc.example.net. 86400 IN TXT “v=DMARC1; p=none; pct=100; ruf=mailto:dmarc-feedback@example.com&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h1 id=&#34;2-modélisation-dun-attaquant-actif&#34;&gt;2. Modélisation d’un attaquant actif&lt;/h1&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h2 id=&#34;21-négociation-tls&#34;&gt;2.1. Négociation TLS&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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 &lt;code&gt;STARTTLS&lt;/code&gt; par le serveur, et que le client est libre de solliciter en
envoyant le message &lt;code&gt;STARTTLS&lt;/code&gt;. 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 &lt;code&gt;STARTTLS&lt;/code&gt;. Les lignes préfixées par
&lt;code&gt;S:&lt;/code&gt; sont envoyées par le serveur, et celles par &lt;code&gt;C:&lt;/code&gt; par le client.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;S: 220 smtp.gmail.com ESMTP 186sm7907497wmm.32 - gsmtp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;C: EHLO x-cli.eu
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;S: 250-smtp.gmail.com at your service, [2001:41d0:51:1::716]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;S: 250-SIZE 35882577
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;S: 250-8BITMIME
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;S: 250-STARTTLS
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;S: 250-ENHANCEDSTATUSCODES
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;S: 250-PIPELINING
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;S: 250-CHUNKING
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;S: 250 SMTPUTF8
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;C: STARTTLS
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;S: 220 2.0.0 Ready to start TLS
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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 &lt;em&gt;STARTTLS Stripping&lt;/em&gt;. Ce risque n’est pas théorique ; dans un
excellent papier de Google, l’université du Michigan et l’université de
l’Illinois &lt;sup id=&#34;fnref:14&#34;&gt;&lt;a href=&#34;#fn:14&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;14&lt;/a&gt;&lt;/sup&gt;, 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.&lt;/p&gt;
&lt;p&gt;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 &lt;code&gt;STARTTLS&lt;/code&gt;, non reconnue par l’autre partie, comme &lt;code&gt;XXXXXXXX&lt;/code&gt;. En
conséquence, le client ne verra pas l’option &lt;code&gt;STARTTLS&lt;/code&gt;, mais une option
&lt;code&gt;XXXXXXXX&lt;/code&gt; qu’il ne sait pas utiliser, ou le serveur recevra une commande
&lt;code&gt;XXXXXXXX&lt;/code&gt; du client, à laquelle il répondra avec un message d’erreur indiquant
qu’il s’agit d’une commande invalide.&lt;/p&gt;
&lt;p&gt;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 &lt;sup id=&#34;fnref1:14&#34;&gt;&lt;a href=&#34;#fn:14&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;14&lt;/a&gt;&lt;/sup&gt;,
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).&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;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 ! ».&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;22-remplacement-des-enregistrements-mx&#34;&gt;2.2. Remplacement des enregistrements MX&lt;/h2&gt;
&lt;p&gt;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 :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;example.com. 86400 IN MX 5 mail1.example.com.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;example.com. 86400 IN MX 10 smtp.example.net.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Dans le même papier &lt;sup id=&#34;fnref2:14&#34;&gt;&lt;a href=&#34;#fn:14&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;14&lt;/a&gt;&lt;/sup&gt;, 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.&lt;/p&gt;
&lt;p&gt;Les auteurs de &lt;sup id=&#34;fnref3:14&#34;&gt;&lt;a href=&#34;#fn:14&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;14&lt;/a&gt;&lt;/sup&gt; 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.&lt;/p&gt;
&lt;p&gt;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 &lt;abbr title=&#34;Server Name Indication&#34;&gt;SNI&lt;/abbr&gt;. À 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.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;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 (&lt;em&gt;Virtual Host&lt;/em&gt;) sur une même adresse IP servant du HTTPS.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;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
&lt;code&gt;@example.com&lt;/code&gt;. Le serveur de destination aurait alors pu fournir un certificat
valide pour &lt;code&gt;example.com&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;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 &lt;code&gt;example.com&lt;/code&gt; pour l’envoi d’un
courrier au nom de domaine cohébergé &lt;code&gt;example.net&lt;/code&gt;. À 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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h1 id=&#34;3-la-contre-mesure--dnssec-et-dane&#34;&gt;3. La contre-mesure : DNSSEC et DANE&lt;/h1&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Un aspect « chiffrement opportuniste » demeure néanmoins, lors du signalement de
la prise en charge de TLS par le client et le serveur, avec &lt;code&gt;STARTTLS&lt;/code&gt;, 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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;La technologie DANE &lt;sup id=&#34;fnref1:5&#34;&gt;&lt;a href=&#34;#fn:5&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt; 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.&lt;/p&gt;
&lt;p&gt;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 &lt;code&gt;_25._tcp.&lt;/code&gt;. Ainsi, le serveur &lt;code&gt;smtp.gmail.com&lt;/code&gt; pourrait disposer d’un
enregistrement TLSA comme celui-ci :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;_25._tcp.smtp.gmail.com. IN TLSA 3 1 1 Base64DuCertificatOuDeLaClefPublique
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;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 &lt;sup id=&#34;fnref:15&#34;&gt;&lt;a href=&#34;#fn:15&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;15&lt;/a&gt;&lt;/sup&gt;
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.&lt;/p&gt;
&lt;p&gt;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 &lt;code&gt;main.cf&lt;/code&gt; les
lignes suivantes :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;smtp_tls_security_level = dane
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;smtp_dns_support_level = dnssec
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;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 &lt;code&gt;STARTTLS&lt;/code&gt; 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.&lt;/p&gt;
&lt;h1 id=&#34;4-conclusion&#34;&gt;4. Conclusion&lt;/h1&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;
  &lt;figure&gt;
    &lt;img src=&#34;./schema_smtp.jpg&#34; alt=&#34;Synthèse des menaces étudiées dans cet article&#34;&gt;
    &lt;figcaption&gt;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.&lt;/figcaption&gt;
  &lt;/figure&gt;

&lt;/p&gt;
&lt;p&gt;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é).&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h1 id=&#34;5-remerciements&#34;&gt;5. Remerciements&lt;/h1&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Merci également à Claudio Fiandrino pour son code TikZ pour topologies réseaux,
publié en &lt;sup id=&#34;fnref:16&#34;&gt;&lt;a href=&#34;#fn:16&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;16&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h1 id=&#34;6-références&#34;&gt;6. Références&lt;/h1&gt;
&lt;p&gt;Publié par les &lt;a href=&#34;https://connect.ed-diamond.com/MISC/misc-097/smtp-la-killer-app-de-dnssec&#34;&gt;Editions Diamond&lt;/a&gt; sous licence &lt;a href=&#34;https://creativecommons.org/licenses/by-nc-nd/4.0/deed.fr&#34;&gt;CC-BY-NC-ND&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;Outil de mesures DNS développé pour cet article : &lt;a href=&#34;https://github.com/X-Cli/collectDNSSECEmailStats&#34;&gt;https://github.com/X-Cli/collectDNSSECEmailStats&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;Observatoire de la résilience de l’Internet français : &lt;a href=&#34;https://www.ssi.gouv.fr/observatoire&#34;&gt;https://www.ssi.gouv.fr/observatoire&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref1:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;Charte de l’ANSSI pour l’amélioration de la sécurité des échanges de courriers électroniques : &lt;a href=&#34;https://www.ssi.gouv.fr/particulier/precautions-elementaires/charte-pour-la-securite-des-courriers-electroniques/&#34;&gt;https://www.ssi.gouv.fr/particulier/precautions-elementaires/charte-pour-la-securite-des-courriers-electroniques/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;Document équivalent au lien précédent, rédigé par l’homologue de l’ANSSI en Allemagne : &lt;a href=&#34;http://www.project-consult.de/files/BSI_TR03108-1_Sichere_EMail.pdf&#34;&gt;http://www.project-consult.de/files/BSI_TR03108-1_Sichere_EMail.pdf&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:5&#34;&gt;
&lt;p&gt;The DNS-Based Authentication of Named Entities (DANE) Transport Layer Security (TLS) Protocol : TLSA &lt;a href=&#34;https://tools.ietf.org/html/rfc6698&#34;&gt;https://tools.ietf.org/html/rfc6698&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:5&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref1:5&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:6&#34;&gt;
&lt;p&gt;DNS Certification Authority Authorization (CAA) Resource Record : &lt;a href=&#34;https://tools.ietf.org/html/rfc6844&#34;&gt;https://tools.ietf.org/html/rfc6844&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:6&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:7&#34;&gt;
&lt;p&gt;CAA Study : &lt;a href=&#34;https://caastudy.github.io/&#34;&gt;https://caastudy.github.io/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:7&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:8&#34;&gt;
&lt;p&gt;Measuring DANE TLSA Deployment : &lt;a href=&#34;https://www.isi.edu/~liangzhu/presentation/dns-oarc/dane_tlsa_survey.pdf&#34;&gt;https://www.isi.edu/~liangzhu/presentation/dns-oarc/dane_tlsa_survey.pdf&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:8&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:9&#34;&gt;
&lt;p&gt;Baseline Requirements Documents : &lt;a href=&#34;https://cabforum.org/baseline-requirements-documents/&#34;&gt;https://cabforum.org/baseline-requirements-documents/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:9&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:10&#34;&gt;
&lt;p&gt;Sender Policy Framework (SPF) for Authorizing Use of Domains in Email, Version 1 : &lt;a href=&#34;https://tools.ietf.org/html/rfc7208&#34;&gt;https://tools.ietf.org/html/rfc7208&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:10&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:11&#34;&gt;
&lt;p&gt;DomainKeys Identified Mail (DKIM) Signatures : &lt;a href=&#34;https://tools.ietf.org/html/rfc6376&#34;&gt;https://tools.ietf.org/html/rfc6376&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:11&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:12&#34;&gt;
&lt;p&gt;NXDOMAIN : There Really Is Nothing Underneath : &lt;a href=&#34;https://tools.ietf.org/html/rfc8020&#34;&gt;https://tools.ietf.org/html/rfc8020&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:12&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:13&#34;&gt;
&lt;p&gt;Domain-based Message Authentication, Reporting, and Conformance (DMARC) : &lt;a href=&#34;https://tools.ietf.org/html/rfc7489&#34;&gt;https://tools.ietf.org/html/rfc7489&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:13&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:14&#34;&gt;
&lt;p&gt;Neither Snow Nor Rain Nor MITM… An Empirical Analysis of Email Delivery Security : &lt;a href=&#34;https://static.googleusercontent.com/media/research.google.com/fr//pubs/archive/43962.pdf&#34;&gt;https://static.googleusercontent.com/media/research.google.com/fr//pubs/archive/43962.pdf&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:14&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref1:14&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref2:14&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref3:14&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:15&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.huque.com/bin/gen_tlsa&#34;&gt;https://www.huque.com/bin/gen_tlsa&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:15&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:16&#34;&gt;
&lt;p&gt;Attribution 2.5 Generic : &lt;a href=&#34;https://creativecommons.org/licenses/by/2.5/&#34;&gt;https://creativecommons.org/licenses/by/2.5/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:16&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description>
		</item>
		<item>
			<title>Chiffrement de messagerie quasi instantanée : à quel protocole se vouer ?</title>
			<link>https://broken-by-design.fr/posts/instant-msg/</link>
			<pubDate>Wed, 01 Mar 2017 00:00:00 +0000</pubDate>
			<guid isPermaLink="true">https://broken-by-design.fr/posts/instant-msg/</guid>
			<description>&lt;p&gt;Telegram, WhatsApp, Signal, OTR&amp;hellip; et autant de protocoles de messagerie quasi
instantanée, de modèles de sécurité et de protocoles cryptographiques : lesquels
choisir ? Et si la solution idéale n’était pas dans la liste précédente ? Cet
article évoque les limites de plusieurs de ces solutions, et présente le cœur
cryptographique de Signal, WhatsApp et du protocole OMEMO. Il met finalement en
exergue, par une analyse comparative, certaines limites de Signal et des
qualités d’OMEMO.&lt;/p&gt;
&lt;p&gt;Chiffrement des messages de bout en bout ou chiffrement du canal, qualité des
algorithmes cryptographiques et de l’authentification des pairs, confidentialité
persistante (&lt;abbr title=&#34;Perfect Forward Secrecy&#34;&gt;PFS&lt;/abbr&gt;) ou non, fiabilité de l’équipement faisant tourner la solution, limitation de
l’exposition des métadonnées, fuite du carnet d’adresses, localisation des
serveurs, capacité à dénier l’envoi d’un message : des critères rarement
considérés par les utilisateurs de messagerie. Leurs véritables critères de
sélection sont souvent la taille du réseau social joignable, la facilité
d’utilisation, l’accessibilité de la solution sur l’équipement de l’utilisateur
ou encore la liste des services annexes. Un constat compréhensible, puisque la
première liste est formée de critères abscons et rarement absolus, tandis que la
seconde liste affecte l&amp;rsquo;usage quotidien.&lt;/p&gt;
&lt;p&gt;Certains utilisateurs restent néanmoins soucieux de leur vie privée ou sont
contraints par la nature de leurs activités en ligne à un niveau de sécurité
plus élevé. Ils disposent alors d’une myriade d’options, dont Telegram,
WhatsApp, Signal, ou Apple iMessage. Ils peuvent aussi se tourner vers des
solutions de messagerie instantanées traditionnelles augmentées du protocole
&lt;!-- raw HTML omitted --&gt;OTR&lt;!-- raw HTML omitted --&gt; &lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; ou encore des e-mails augmentés
grâce à OpenPGP &lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Se pose alors la question de séparer le bon grain de l’ivraie ; une tâche qui
est simplifiée par la forte concentration des applications autour des protocoles
X3DH &lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; et Double Ratchet &lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;. Ces deux protocoles, spécifiés récemment
dans le domaine public par les auteurs de Signal, sont employés par plusieurs
vendeurs, dont Signal et WhatsApp. En outre, la communauté de XMPP, un protocole
de messagerie quasi instantanée, a également choisi X3DH+Double Ratchet, afin de
remplacer leur usage d’OpenPGP et OTR.&lt;/p&gt;
&lt;p&gt;La combinaison X3DH+Double Ratchet n’est cependant qu’une partie de la solution
pour sécuriser les communications. Plus spécifiquement, ces protocoles
permettent, respectivement, la négociation des clés et leur rafraîchissement.
L’utilisation de ces clés, afin de créer des sessions cryptographiques entre les
utilisateurs, est dévolue à d’autres composants : le protocole Signal, dans le
cas de Signal et de WhatsApp, et le protocole OMEMO &lt;sup id=&#34;fnref:5&#34;&gt;&lt;a href=&#34;#fn:5&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;, dans le cas de
XMPP.&lt;/p&gt;
&lt;p&gt;X3DH+Double Ratchet, OMEMO et Signal sont étudiés dans la suite de cet article.&lt;/p&gt;
&lt;p&gt;Pour le lecteur intéressé, la sécurité de Telegram a fait l’objet de discussions
&lt;sup id=&#34;fnref:6&#34;&gt;&lt;a href=&#34;#fn:6&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;6&lt;/a&gt;&lt;/sup&gt; et d’études &lt;sup id=&#34;fnref:7&#34;&gt;&lt;a href=&#34;#fn:7&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;7&lt;/a&gt;&lt;/sup&gt; et l’université de Johns Hopkins a étudié celle
d’Apple iMessage &lt;sup id=&#34;fnref:8&#34;&gt;&lt;a href=&#34;#fn:8&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;8&lt;/a&gt;&lt;/sup&gt;. WeChat ou encore Slack sont hors sujet, puisqu’ils ne
proposent pas de chiffrement de bout en bout.&lt;/p&gt;
&lt;h1 id=&#34;1-les-protocoles-inadéquats-pour-la-messagerie-quasi-instantanée&#34;&gt;1. Les protocoles inadéquats pour la messagerie quasi instantanée&lt;/h1&gt;
&lt;h2 id=&#34;11-openpgp&#34;&gt;1.1. OpenPGP&lt;/h2&gt;
&lt;p&gt;OpenPGP est un format de stockage de messages et de clés cryptographiques,
spécifié dans sa version la plus récente en 2007 &lt;sup id=&#34;fnref1:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;. Il est notamment
employé pour sécuriser des messages électroniques. Ce format étant agnostique
vis-à-vis de la nature des messages, il convient pour des réseaux de messagerie
décentralisés ou lorsque le destinataire est hors-ligne (protocole non
interactif). Il permet également d’assurer de la protection de bout en bout,
puisque ce sont les messages qui sont chiffrés et non le canal de transport de
ces derniers.&lt;/p&gt;
&lt;p&gt;En outre, il est possible d’utiliser OpenPGP pour envoyer des messages à un
groupe d’utilisateurs. Pour ce faire, la clé de chiffrement du message est
chiffrée avec les clés publiques de chacun des destinataires. Les clés publiques
ainsi utilisées doivent être préalablement créées, et stockées dans des
certificats OpenPGP. Ces certificats permettent d’associer des identités —
éventuellement des pseudonymes — à ces clés publiques. Ces certificats sont
transmis ponctuellement aux autres utilisateurs grâce à des annuaires ou par une
remise en main propre.&lt;/p&gt;
&lt;p&gt;OpenPGP présente cependant des limites, en regard de solutions alternatives
spécialisées pour le chiffrement de messagerie quasi instantanée. Ainsi, il
n’offre pas, de manière inhérente, de confidentialité persistante du fait de la
transmission ponctuelle des certificats : le rafraîchissement des clés est du
ressort de l’utilisateur. En outre, pour la protection en intégrité des
messages, l’utilisateur n’a le choix qu’entre des solutions imparfaites. L’une
est sujette à des attaques par dégradation du niveau de sécurité (&lt;em&gt;downgrade
attack&lt;/em&gt;) &lt;sup id=&#34;fnref:9&#34;&gt;&lt;a href=&#34;#fn:9&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;9&lt;/a&gt;&lt;/sup&gt; et l’autre use de signatures cryptographiques non répudiables,
ce qui n’est pas toujours souhaitable.&lt;/p&gt;
&lt;h2 id=&#34;12-off-the-record&#34;&gt;1.2. Off-the-Record&lt;/h2&gt;
&lt;p&gt;Le protocole &lt;em&gt;Off-the-Record&lt;/em&gt; a été spécifié, pour la première fois, en 2004 ;
sa version la plus récente date de 2012. Ce mécanisme permet l’échange de clés
et de messages sécurisés de bout en bout. L’établissement de la session protégée
est effectué entre deux parties de manière interactive. Autrement dit, il est
nécessaire que les participants soient en ligne simultanément pour
l’établissement de cette session. Cette propriété exclut un usage asynchrone, et
restreint donc ce protocole à la messagerie instantanée. Une variante, appelée
mpOTR &lt;sup id=&#34;fnref:10&#34;&gt;&lt;a href=&#34;#fn:10&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;10&lt;/a&gt;&lt;/sup&gt;, permet d’échanger des messages au sein d’un groupe d’utilisateurs.&lt;/p&gt;
&lt;p&gt;Avec OTR, les utilisateurs sont identifiés par des clés publiques à long terme.
Les clés à long terme servent à signer/authentifier des échanges de clés
Diffie-Hellman (DH) éphémères. Ces clés éphémères servent, à leur tour, à
générer les clés protégeant les messages. Il convient de noter que les
signatures émises par les clés à long terme affectent la vie privée ; elles
constituent, en effet, une preuve non répudiable qu’une conversation a eu lieu
entre deux parties, même si le contenu de la conversation reste inconnu d’un
observateur.&lt;/p&gt;
&lt;p&gt;Une fois la négociation de clés initiale accomplie, de nouvelles biclés DH sont
introduites à chaque nouveau message. Cela permet ainsi de rafraîchir les
secrets et d’apporter la confidentialité persistante. En effet, la compromission
d’une clé privée DH n’affecte la confidentialité que d’un unique message ; de
même, la compromission de la clé à long terme n’affecte que les futurs messages.&lt;/p&gt;
&lt;p&gt;Le protocole &lt;em&gt;Off-the-Record&lt;/em&gt; présente également une propriété de sécurité qui
serait favorable à la vie privée. Ainsi, &lt;em&gt;Off-the-Record&lt;/em&gt; permettrait à un
expéditeur de dénier le contenu d’un message, tout en garantissant au
destinataire la légitimité et l’intégrité du message reçu. Pour ce faire, les
clés utilisées pour calculer des motifs d’intégrité de messages sont divulguées
en clair après réception et vérification de ces messages. Conjuguée à un mode de
chiffrement malléable et à un clair connu, cette méthode peut permettre à un
observateur de forger un message chiffré et intègre arbitraire. Cet observateur
serait cependant incapable de prouver à un tiers l’authenticité d’un message
qu’il détient. L’efficacité de ce mécanisme fait néanmoins débat parmi les
experts, car il n’a jamais été éprouvé dans le cadre d’un procès, afin de
décrédibiliser une conversation enregistrée et utilisée comme preuve
incriminante.&lt;/p&gt;
&lt;p&gt;Malgré ses nombreux avantages, le protocole &lt;em&gt;Off-the-Record&lt;/em&gt;, tel que spécifié
dans sa version la plus récente (3.4), souffre d’un problème d’obsolescence
cryptographique. En effet, l’absence d’un mécanisme de négociation des
algorithmes fait d’&lt;em&gt;Off-the-Record&lt;/em&gt; un musée des algorithmes cryptographiques
des années 2000. Sont notamment employés l’algorithme de signature DSA, des
empreintes cryptographiques avec SHA-1, ou encore des échanges DH sur corps
entiers de 1536 bits avec un groupe fixé par la spécification. L’usage de cette
cryptographie datée est contraire aux bonnes pratiques actuellement reconnues.&lt;/p&gt;
&lt;h1 id=&#34;2-x3dhdouble-ratchet&#34;&gt;2. X3DH+Double Ratchet&lt;/h1&gt;
&lt;p&gt;Les protocoles X3DH et Double Ratchet ont été inventés par Trevor Perrin et
Moxie Marlinspike. En 2013, il s’agissait, en fait, d’un seul et même protocole
connu sous le nom d’Axolotl. Ce n’est qu’en 2016 qu’Axolotl fut divisé et que
ses parties furent renommées afin de mettre fin à des confusions fréquentes
entre Axolotl et le protocole Signal. Il faut dire que le protocole Signal, qui
fait usage d’une variante d’Axolotl, n’a, à ce jour, jamais été spécifié ou
documenté et que la frontière entre les deux protocoles était donc pour le moins
floue. Les spécifications complètes de X3DH et Double Ratchet ont finalement été
publiées en novembre 2016. Cette publication a également permis de mettre fin à
de récurrentes menaces judiciaires que les auteurs de Signal ont pu proférer
contre des vendeurs prétendant implémenter le protocole Signal, alors qu’ils
utilisaient réellement Double Ratchet &lt;sup id=&#34;fnref:11&#34;&gt;&lt;a href=&#34;#fn:11&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;11&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;X3DH est responsable de la négociation de clés cryptographiques. Celle-ci prend
place lors d’une phase initiale. Les clés évoluent ensuite par dérivations,
selon le protocole Double Ratchet. Ce dernier rafraîchit les clés à l’aide de
cryptographie symétrique, ainsi que par l’apport régulier de nouveaux éléments
secrets asymétriques.&lt;/p&gt;
&lt;p&gt;Pour effectuer ces opérations sur les clés, les deux protocoles emploient de la
cryptographie moderne : XEdDSA, une extension à EdDSA, sur les courbes
elliptiques curve25519 ou curve448 &lt;sup id=&#34;fnref:12&#34;&gt;&lt;a href=&#34;#fn:12&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;12&lt;/a&gt;&lt;/sup&gt;, SHA2 et HKDF &lt;sup id=&#34;fnref:13&#34;&gt;&lt;a href=&#34;#fn:13&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;13&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h2 id=&#34;21-x3dh&#34;&gt;2.1. X3DH&lt;/h2&gt;
&lt;p&gt;Chaque utilisateur du protocole X3DH doit générer et publier un ensemble de
biclés cryptographiques. Ces clés doivent être compatibles avec les fonctions
X25519 ou X448 de XEdDSA.&lt;/p&gt;
&lt;p&gt;La première biclé est appelée clé à long terme. Elle sert dans le cadre
d’échanges DH, mais elle est également employée pour signer d’autres biclés,
appelées clés à moyen terme. Des biclés à usage supposément unique sont
également générées en grande quantité ; Signal et Conversations en génèrent
ainsi une centaine. Générer autant de clés à usage unique permet qu’un grand
nombre de sessions puissent être établies avec la confidentialité persistante
dès le premier message, et ce alors que le destinataire n’est pas en ligne.&lt;/p&gt;
&lt;p&gt;La génération de ces trois types de biclés (à long et moyen termes et à usage
unique) doit être répétée pour chacun des périphériques avec lesquels un
utilisateur est susceptible d’accéder à ses messages. L’utilisateur disposant
d’un PC, d’une tablette et d’un téléphone portable se retrouve ainsi rapidement
avec plusieurs centaines de biclés associées à son identifiant. Seule la clé à
long terme de chaque équipement nécessite cependant une vérification
d’authenticité par les autres utilisateurs.&lt;/p&gt;
&lt;p&gt;Ces biclés sont utilisées afin d’établir des sessions entre un expéditeur et
l’ensemble des périphériques des destinataires. Ces périphériques peuvent être
possédés par un même destinataire ou par plusieurs destinataires, dans le cadre
d’une discussion de groupe. La liste des périphériques destinataires peut même
contenir les équipements de l’expéditeur, afin de permettre la synchronisation
des messages émis entre équipements.&lt;/p&gt;
&lt;p&gt;Autant de sessions sont créées qu’il y a d’équipements destinataires. Cette
étape n’a cependant besoin de se produire qu’une seule fois, lors de la première
conversation entre deux périphériques. Ces sessions ont, en effet, une durée de
vie illimitée.&lt;/p&gt;
&lt;p&gt;Pour établir une session, la première étape consiste à récupérer les clés
publiques des périphériques destinataires. La manière dont elles sont publiées
et récupérées est laissée ici volontairement abstraite ; elle varie d’une
implémentation à l’autre, comme le détaillera la section 3 de cet article.&lt;/p&gt;
&lt;p&gt;Une fois les clés publiques des destinataires en possession de l’expéditeur, ce
dernier effectue les mêmes étapes avec les clés de chaque périphérique pour
lequel une session doit être établie. La première étape consiste à générer une
nouvelle biclé DH éphémère. Trois à quatre échanges DH sont ensuite effectués,
entre les clés de l’équipement expéditeur et celles de l’équipement
destinataire. L’appariement des clés publiques DH est détaillé dans la figure 1.&lt;/p&gt;
&lt;p&gt;
  &lt;figure&gt;
    &lt;img src=&#34;./X3DH.jpg&#34; alt=&#34;Illustration d&amp;amp;rsquo;un échange de clé avec X3DH&#34;&gt;
    &lt;figcaption&gt;Fig. 1 : Illustration des échanges de clés DH effectués dans le cadre de X3DH. Le trait en pointillé représente un échange optionnel, qui n’a lieu que si une clé à usage unique est disponible pour l’équipement destinataire.&lt;/figcaption&gt;
  &lt;/figure&gt;

&lt;/p&gt;
&lt;p&gt;La variabilité du nombre d’échanges DH résulte de la capacité à récupérer une
des clés à usage unique pour l’équipement destinataire. Certains dépôts de clés
tiennent, en effet, une comptabilité afin d’assurer qu’une clé à usage unique
n’est bien distribuée qu’une seule fois. Si toutes les clés ont été distribuées,
aucune n’est fournie à l’expéditeur et seuls trois échanges DH sont opérés. Ceci
peut affecter la confidentialité persistante, car le destinataire ne fournit
alors que des clés qui sont partagées entre plusieurs sessions. Dans la section
2.2 traitant de Double Ratchet, il sera détaillé comment cette faiblesse est
cicatrisée dès la réception d’un message de la part de l’équipement
destinataire.&lt;/p&gt;
&lt;p&gt;L’ensemble des secrets résultant des échanges DH est ensuite concaténé et passé
à travers la fonction HKDF pour former une valeur secrète, appelée secret racine
de la session.&lt;/p&gt;
&lt;p&gt;Cet échange de clés a la particularité de négocier un secret tout en préservant
la capacité des deux parties de nier avoir tenu une conversation ensemble. Cette
propriété est dérivée de l’hypothèse de difficulté calculatoire de DH
(Computational DH Assumption). La signature XEdDSA des clés à moyen terme, qui
elle est non répudiable, ne prévient pas cette propriété puisqu’elle est
totalement décorrélée de l’échange de clés et n’intervient que pour « certifier
» la clé à moyen terme.&lt;/p&gt;
&lt;h2 id=&#34;22-double-ratchet&#34;&gt;2.2. Double Ratchet&lt;/h2&gt;
&lt;p&gt;Double Ratchet repose sur deux mécanismes de rafraîchissement des clés. Ces deux
mécanismes confèrent son nom à cet algorithme, puisqu’ils utilisent tous deux, à
l’instar d’une roue à rochet, des fonctions cryptographiques à sens unique pour
faire « évoluer » des secrets.&lt;/p&gt;
&lt;p&gt;Le premier, représenté sur fond jaune dans la figure 2, utilise exclusivement la
cryptographie symétrique. Il permet de générer les clés secrètes protégeant les
messages. Avec ce mécanisme, chaque message bénéficie d’une clé secrète à usage
unique. Cette clé de protection d’un message est obtenue par dérivation d’une
clé, tirée d’un ensemble appelé chaîne de clés. Cette chaîne est formée par des
dérivations successives de secrets. Le secret initial de cette chaîne est le
secret racine actuel. La notion d’actualité du secret racine provient du second
mécanisme de rafraîchissement des clés.&lt;/p&gt;
&lt;p&gt;Ce second mécanisme, représenté sur fond vert dans la figure 2, utilise de la
cryptographie asymétrique. Il vise à faire évoluer la clé racine qui a été
négociée initialement, par exemple avec X3DH. Avec ce mécanisme, une nouvelle
biclé DH est tirée aléatoirement chaque fois qu’un périphérique s’apprête à
envoyer un message consécutif à la réception d’un message par un autre
périphérique. La clé publique de cette nouvelle biclé DH est jointe à l’ensemble
des messages envoyés par ce périphérique jusqu’à la réception d’un message de la
part d’un autre périphérique. Cette gymnastique est représentée dans la figure
3.&lt;/p&gt;
&lt;p&gt;La nouvelle clé DH fraîchement tirée est utilisée dans un échange DH en
conjonction avec les clés publiques les plus récentes reçues dans des messages
émis par les autres périphériques. Le résultat de cet échange est ensuite «
mélangé » avec le secret racine actuel à l’aide de la fonction HKDF. Le résultat
de cette opération devient le nouveau secret racine actuel.&lt;/p&gt;
&lt;p&gt;
  &lt;figure&gt;
    &lt;img src=&#34;./DR.jpg&#34; alt=&#34;Illustration de l’algorithme Double Ratchet&#34;&gt;
    &lt;figcaption&gt;Fig. 2 : Illustration de l’algorithme Double Ratchet. Les clés composant la chaîne de clés sont représentées dans des diamants. Les clés de messages sont représentées dans des ellipses. Les algorithmes sont dessinés dans des boîtes roses aux bords arrondis. Les composants sur fond vert représentent la roue à rochet asymétrique. Les composants sur fond jaune représentent la roue à rochet symétrique.&lt;/figcaption&gt;
  &lt;/figure&gt;

&lt;/p&gt;
&lt;p&gt;
  &lt;figure&gt;
    &lt;img src=&#34;./msgflow.jpg&#34; alt=&#34;Illustration d’un enchaînement de messages avec un protocole de messagerie employant Double Ratchet&#34;&gt;
    &lt;figcaption&gt;Fig. 3 : Illustration d’un enchaînement de messages avec un protocole de messagerie employant Double Ratchet. De nouvelles clés asymétriques sont générées juste avant l’envoi d’un message faisant suite à une réponse. Cette clé asymétrique est répétée dans tous les messages suivants.&lt;/figcaption&gt;
  &lt;/figure&gt;

&lt;/p&gt;
&lt;p&gt;L’utilisation de ces deux mécanismes de rafraîchissement de clés permet de
bénéficier de clés secrètes uniques pour chaque message envoyé, y compris
lorsqu’un des participants se lance dans un monologue de plusieurs messages. La
compromission d’une clé symétrique ne mène alors qu’à la compromission d’un seul
message. La réception d’un message de la part de l’autre participant permet
ensuite de rafraîchir le secret racine. Ceci permet ainsi de prévenir la
compromission de plus d’un monologue en cas de compromission d’une clé
asymétrique.&lt;/p&gt;
&lt;p&gt;Outre ces propriétés, les protocoles de messageries sécurisées reposant sur
Double Ratchet peuvent également se montrer tolérants vis-à-vis de la perte de
messages ou de la livraison de messages dans le désordre. Il suffit à ces
applications de conserver les différentes chaînes de clés, et de « sauter » les
messages encore non reçus, en appliquant plusieurs fois de suite la fonction
HMAC-SHA256 avec la « constante 2 » de la figure 2. Il convient néanmoins de
noter que conserver ainsi les clés, au lieu de les supprimer dès que possible,
peut mettre en péril la confidentialité persistante, en cas de compromission
d’un équipement.&lt;/p&gt;
&lt;h2 id=&#34;23-intégration-de-x3dhdouble-ratchet-dans-omemo&#34;&gt;2.3. Intégration de X3DH+Double Ratchet dans OMEMO&lt;/h2&gt;
&lt;p&gt;La première version d’OMEMO a été spécifiée par Andreas Straub en 2015, avec
l’aide de Daniel Gultsch, développeur principal du client XMPP Conversations. En
décembre 2016, OMEMO a été officiellement acceptée comme extension expérimentale
du protocole XMPP (XEP-0384).&lt;/p&gt;
&lt;p&gt;Avec XMPP, chaque utilisateur est identifié par un &lt;!-- raw HTML omitted --&gt;JID&lt;!-- raw HTML omitted --&gt;. Il s’agit d’un identifiant qui ressemble fort à une adresse
e-mail, mais il est suivi d’une barre oblique (&lt;em&gt;slash&lt;/em&gt;) et du nom d’un
équipement ou d’un logiciel. &lt;code&gt;florian@im.x-cli.eu/phone&lt;/code&gt; est, par exemple, le
JID de l’auteur de cet article lorsqu’il est connecté avec son téléphone. À
l’instar des adresses e-mail, la partie précédant l’arobase désigne un
utilisateur local, tandis que la partie suivant l’arobase et jusqu’à la barre
oblique désigne le serveur sur lequel est hébergé cet utilisateur. XMPP est donc
un système fédéré, où chaque utilisateur choisit son fournisseur de service.&lt;/p&gt;
&lt;p&gt;Les messages à destination d’un utilisateur, désigné par son bare JID (c.-à-d.
son JID sans le nom de l’équipement), sont délivrés au dernier périphérique
actif de cet utilisateur. Ce fonctionnement peut être altéré grâce aux
extensions &lt;em&gt;Carbon Messages&lt;/em&gt; (XEP-0280) et &lt;em&gt;Message Archive Management&lt;/em&gt;
(XEP-0313) afin que tous les équipements d’un utilisateur aient accès à tous les
messages reçus. En outre, si un utilisateur est hors-ligne, ses messages peuvent
être stockés sur le serveur responsable du compte de l’utilisateur. Ces messages
lui seront alors délivrés lors de sa prochaine connexion. Par ailleurs, des
informations relatives à un utilisateur peuvent être stockées, en clair, sur le
serveur responsable de son compte, grâce à l’extension XMPP XEP-0163, appelée
&lt;em&gt;Personal Eventing Protocol&lt;/em&gt; (PEP). Ce mécanisme, lui-même extensible, permet
ainsi à un utilisateur connecté ou hors-ligne de mettre à la disposition
d’autres utilisateurs diverses informations comme son avatar, son dernier
message de statut, ou encore sa « carte de visite ».&lt;/p&gt;
&lt;p&gt;OMEMO utilise ces différentes extensions XMPP pour offrir une méthode de
chiffrement de bout en bout à l’ergonomie moderne. Chaque équipement, lorsqu’il
active OMEMO, génère sa clé à long terme, sa clé à moyen terme et d’une
vingtaine à une centaine de clés à usage « unique ». Les jeux de clés de chaque
équipement sont stockés dans le profil PEP utilisateur. Lorsqu’un expéditeur
souhaite établir une nouvelle session, il récupère toutes les clés auprès du
serveur responsable du compte du destinataire. Ensuite, il effectue un échange
de clés en suivant le protocole X3DH. Par équipement avec lequel une session
doit être établie, il sélectionne aléatoirement une clé à « usage unique ».
Cette sélection aléatoire permet de s’affranchir du risque qu’un serveur
malveillant dégrade la confidentialité persistante en diffusant sciemment une
clé à usage unique déjà employée par ailleurs. Le risque de dégradation de la
confidentialité persistante n’est cependant pas totalement évité. Il est, en
effet, possible que plusieurs sessions soient établies pendant qu’un
périphérique est hors-ligne, et que la sélection aléatoire provoque une
collision. Plus un périphérique tarde à remplacer les clés utilisées, et plus le
risque de collision grandit. Cette collision a une portée limitée puisqu’elle
n’a un impact que sur tout ou partie du premier monologue d’un utilisateur. Si
l’équipement, dont l’une des clés à usage unique a été réutilisée, se connecte
et détecte cette situation, il est alors en mesure de rétablir la
confidentialité persistante. Il lui suffit d’envoyer un message « de service »
dont le seul objet est de rafraîchir le secret racine. Cette situation semble,
dans tous les cas, préférable à l’absence totale du quatrième échange DH.&lt;/p&gt;
&lt;h1 id=&#34;3-des-divergences-entre-signal-et-le-protocole-omemo&#34;&gt;3. Des divergences entre Signal et le protocole OMEMO&lt;/h1&gt;
&lt;p&gt;Signal et le protocole OMEMO sont par certains aspects très similaires.
Certaines implémentations d’OMEMO utilisent, en effet, la bibliothèque
cryptographique libsignal &lt;sup id=&#34;fnref:14&#34;&gt;&lt;a href=&#34;#fn:14&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;14&lt;/a&gt;&lt;/sup&gt; d’Open Whisper Systems, la société éditrice de
Signal. Ses usages sont cependant cantonnés aux échanges de clés X3DH et à la
maintenance des secrets avec Double Ratchet. Les points de divergences entre
Signal et les implémentations d’OMEMO se situent donc sur les points suivants :
les identifiants et l’architecture réseau, l’infrastructure de gestions de clés,
l’usage qui est fait de ces clés, l’existence de documentation de qualité et la
capacité à auditer le protocole.&lt;/p&gt;
&lt;h2 id=&#34;31-les-identifiants-et-linfrastructure-réseau&#34;&gt;3.1. Les identifiants et l’infrastructure réseau&lt;/h2&gt;
&lt;p&gt;Alors qu&amp;rsquo;OMEMO utilise une infrastructure répartie, où chaque utilisateur
choisit son fournisseur de services, grâce au réseau fédéré XMPP, Signal préfère
une infrastructure centralisée. Les auteurs de Signal ont, en effet, exprimé une
opinion très négative sur les notions de fédération et d’interopérabilité, les
qualifiant de causes génératrices de l’ossification des protocoles &lt;sup id=&#34;fnref:15&#34;&gt;&lt;a href=&#34;#fn:15&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;15&lt;/a&gt;&lt;/sup&gt;. Au
diable donc l’Internet ouvert, le succès de HTTP ou encore celui des courriers
électroniques. Moxie Marlinspike a même demandé à des clones (fork) de Signal de
ne pas employer les serveurs opérés par Open Whisper Systems, quand bien même le
protocole employé était le même &lt;sup id=&#34;fnref:16&#34;&gt;&lt;a href=&#34;#fn:16&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;16&lt;/a&gt;&lt;/sup&gt;. Signal est donc un système clos ; la
porte de la fédération a été fermée à clé, clé qui est maintenant au fond d’un
lac.&lt;/p&gt;
&lt;p&gt;Signal utilise les numéros de téléphone des utilisateurs comme identifiants.
Cette pratique a certainement pour origine l’usage des SMS/MMS comme première
méthode de transport des messages de Signal. En 2015, les développeurs ont
cependant décidé arbitrairement d’arrêter de prendre en charge le transport par
SMS/MMS, et d’utiliser, à la place, exclusivement les serveurs d’Open Whisper
Systems, situés aux États-Unis. Cette décision a fait réagir une fraction de la
communauté qui a créé un clone de l’application, désormais appelé Silence
&lt;sup id=&#34;fnref:17&#34;&gt;&lt;a href=&#34;#fn:17&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;17&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Le choix d’Open Whisper Systems d’arrêter la prise en charge des SMS/MMS n’a
cependant pas causé l’arrêt de l’usage des numéros de téléphone comme
identifiants. Il en résulte un problème de vie privée, dû au fait que les
métadonnées relatives aux expéditeurs et destinataires ne sont pas chiffrées par
le protocole Signal. En effet, ces identifiants pourraient permettre aux
opérateurs d’Open Whisper Systems de tracer le graphe social des utilisateurs,
ou encore de les géolocaliser, grâce au réseau SS7 &lt;sup id=&#34;fnref:18&#34;&gt;&lt;a href=&#34;#fn:18&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;18&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Le choix des numéros de téléphone comme identifiant est également fortement
discutable depuis la publication de Signal Desktop. Ce logiciel permet aux
utilisateurs de converser depuis des PC avec les utilisateurs Signal ; il n’est
cependant pas possible d’employer ce logiciel sans s’être enrôlé préalablement
sur téléphone portable !&lt;/p&gt;
&lt;p&gt;Pour finir, cette centralisation du service présente également des risques
topologiques. En effet, la géolocalisation aux États-Unis de la société Open
Whisper Systems et de ses serveurs signifie qu’elle est soumise à l’arsenal
légal américain. Celui-ci a d’ailleurs déjà été mis en œuvre à l’encontre de
Signal &lt;sup id=&#34;fnref:19&#34;&gt;&lt;a href=&#34;#fn:19&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;19&lt;/a&gt;&lt;/sup&gt;. En outre, la centralisation facilite la censure administrative
du service, comme cela s’est déjà produit plusieurs fois au Brésil pour WhatsApp
&lt;sup id=&#34;fnref:20&#34;&gt;&lt;a href=&#34;#fn:20&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;20&lt;/a&gt;&lt;/sup&gt;, et en Égypte pour Signal &lt;sup id=&#34;fnref:21&#34;&gt;&lt;a href=&#34;#fn:21&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;21&lt;/a&gt;&lt;/sup&gt;. Une technique expérimentale &lt;sup id=&#34;fnref:22&#34;&gt;&lt;a href=&#34;#fn:22&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;22&lt;/a&gt;&lt;/sup&gt;,
inspirée du module &lt;em&gt;meek&lt;/em&gt; pour Tor et appelée &lt;em&gt;Domain Fronting&lt;/em&gt;, a été déployée en
réponse à ce dernier blocage. Son déploiement hâtif laisse cependant en suspens
des questions de vie privée, de confidentialité et d’intégrité, eu égard à
l’absence de protection de bout en bout de certaines (méta-)données transitant
par Google AppEngine lors du &lt;em&gt;Domain Fronting&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;En comparaison, les JID de XMPP/OMEMO peuvent être des pseudonymes n’offrant
aucune corrélation avec un utilisateur particulier. Les utilisateurs les plus
prudents peuvent même se connecter à XMPP au travers de Tor, ou utiliser des
hidden services XMPP sur Tor. En outre, les identifiants ne sont pas liés à un
type d’équipements. Ils peuvent ainsi être utilisés sur PC ou téléphone
exclusivement ou sur un mélange des deux. Finalement, pour la géolocalisation
des serveurs, l’infrastructure répartie de XMPP permet de jongler à volonté avec
la localisation administrative et juridique des serveurs.&lt;/p&gt;
&lt;h2 id=&#34;32-linfrastructure-de-gestion-de-clés&#34;&gt;3.2. L’infrastructure de gestion de clés&lt;/h2&gt;
&lt;p&gt;Les serveurs gérés par Open Whisper Systems sont responsables du stockage des
clés publiques de tous les utilisateurs, et de distribuer ces clés aux nouveaux
utilisateurs. Ainsi, lorsqu’un nouvel utilisateur installe Signal, le logiciel
prélève les numéros de téléphone de l’intégralité du carnet d’adresses de
l’utilisateur, et les envoie aux serveurs de Signal, qui retournent en échange
les clés des utilisateurs connus &lt;sup id=&#34;fnref:23&#34;&gt;&lt;a href=&#34;#fn:23&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;23&lt;/a&gt;&lt;/sup&gt;. Les utilisateurs figurant dans le
carnet de contacts sont également notifiés qu’un de leurs contacts vient
d’installer Signal.&lt;/p&gt;
&lt;p&gt;En vue de protéger la vie privée des utilisateurs, les numéros de téléphone des
contacts sont hachés avec une fonction cryptographique et le résultat est
tronqué ; cette technique s’avère cependant insuffisante et une recherche
exhaustive permet de recouvrer ces numéros de téléphone.&lt;/p&gt;
&lt;p&gt;Pour chaque utilisateur du carnet d’adresses ayant Signal, les serveurs d’Open
Whisper Systems retournent donc une clé à long terme, une clé à moyen terme et
optionnellement une clé à usage unique. Cette méthode de distribution
centralisée des clés exige de faire confiance aux serveurs. Ces derniers
peuvent, en effet, dégrader sciemment la confidentialité persistante en ne
retournant pas de clé à usage unique. Ils peuvent, en outre, tout simplement
fournir de fausses clés, en vue d’effectuer une interception de messages. Cette
éventualité peut être contrée si les utilisateurs effectuent une vérification
des clés retournées et les valident. L’usage des clés préalable à cette
vérification n’est cependant pas empêché, et nombre d’utilisateurs font donc
probablement une confiance aveugle aux serveurs de Signal.&lt;/p&gt;
&lt;p&gt;Les utilisateurs méfiants qui voudraient effectuer cette vérification ne sont
malheureusement pas dotés d’outils adaptés. Ainsi, s’il était auparavant
possible de vérifier la clé du destinataire d’un message, les développeurs de
Signal ont dégradé cette possibilité en novembre 2016. Au nom d’études sur
l’expérience utilisateur, ils ont ainsi remplacé la vérification d’empreintes
cryptographiques des clés par la comparaison de « nombres de sûretés » (&lt;em&gt;safety
number&lt;/em&gt;) &lt;sup id=&#34;fnref:24&#34;&gt;&lt;a href=&#34;#fn:24&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;24&lt;/a&gt;&lt;/sup&gt;, supposément plus faciles à comparer. Cette opération a ainsi
réduit la sécurité de l’empreinte de 256 bits à 100 bits. Plus incompréhensible
encore, l’empreinte a également été réduite dans le QRCode utilisé pour la
comparaison des clés, alors qu’il ne peut y avoir d’impact sur l’expérience
utilisateur, que l’on photographie un QRCode de 100 ou 256 bits de sécurité !
Pour finir, la vérification des empreintes est impossible lors d’une
conversation de groupe &lt;sup id=&#34;fnref:25&#34;&gt;&lt;a href=&#34;#fn:25&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;25&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Pour enfoncer le dernier clou, Signal envisage de réviser à la baisse son
mécanisme de sécurité concernant le signalement d’un changement de clés d’un
pair &lt;sup id=&#34;fnref1:24&#34;&gt;&lt;a href=&#34;#fn:24&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;24&lt;/a&gt;&lt;/sup&gt;. Auparavant, lorsqu’un utilisateur changeait de clé à long terme
(une opération rarissime), une notification était affichée et une confirmation
manuelle était exigée. Avec la nouvelle option, dont il est envisagé qu&amp;rsquo;elle
soit activée par défaut, seule une petite ligne sera affichée au milieu de la
conversation.&lt;/p&gt;
&lt;p&gt;En comparaison, les clés OMEMO sont récupérées auprès d’un serveur au choix du
destinataire. Avec le logiciel Conversations, par défaut depuis la version 1.15
de novembre 2016, les clés peuvent être employées sans avoir été vérifiées ; un
indicateur visuel différencie cependant les échanges avec les clés vérifiées et
les échanges sans vérification &lt;sup id=&#34;fnref:26&#34;&gt;&lt;a href=&#34;#fn:26&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;26&lt;/a&gt;&lt;/sup&gt;. De plus, dès qu’une première clé d’un
utilisateur est vérifiée, seules ses clés vérifiées sont utilisables. Dans le
cas où plusieurs périphériques seraient destinataires, chaque clé doit être
individuellement validée au premier usage, à l’aide d’une empreinte
cryptographique de 256 bits. Il existe un risque d’utiliser plusieurs fois une
clé à usage unique, mais le protocole prévoit une contre-mesure pour raccourcir
la durée de l’incident.&lt;/p&gt;
&lt;h2 id=&#34;33-usage-des-clés-symétriques&#34;&gt;3.3. Usage des clés symétriques&lt;/h2&gt;
&lt;p&gt;Signal chiffre les messages à l’aide d’AES256 en mode CBC et ses motifs
d’intégrité sont calculés avec HMAC-SHA256 dont le résultat est tronqué à 64
bits.&lt;/p&gt;
&lt;p&gt;Ces choix peuvent faire débat. Ainsi, bien que Signal use d’une composition
chiffrement/intégrité satisfaisante (&lt;em&gt;Encrypt-then-Mac&lt;/em&gt;), l’implémentation
incorrecte du mode CBC s’est révélée à l’origine de nombreuses vulnérabilités au
fil des années. Cela a été notamment le cas dans TLS. En conséquence,
l’existence de meilleures alternatives, tant en performances qu’en sécurité, a
valu à ce mode d’être déconseillé par les auteurs du RFC de HTTP/2 &lt;sup id=&#34;fnref:27&#34;&gt;&lt;a href=&#34;#fn:27&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;27&lt;/a&gt;&lt;/sup&gt;. La
prochaine version de TLS ne la prend même tout simplement pas en charge &lt;sup id=&#34;fnref:28&#34;&gt;&lt;a href=&#34;#fn:28&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;28&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;En outre, si l’algorithme HMAC-SHA256 est, à ce jour, irréprochable, la
troncature du motif d’intégrité à 64 bits affaiblit son efficacité de manière
significative. Ce choix tient peut-être sa justification dans l’usage des SMS
comme méthode originelle de transport des messages. À l’heure actuelle, tous les
messages de Signal sont notifiés à l’aide de Firebase Cloud Messaging
(anciennement Google Cloud Messaging), et transportés sur le canal de données
des téléphones portables. Les problèmes de bande passante utile ne peuvent donc
plus constituer une justification. En fait, la grande bande passante désormais
disponible joue même à l’encontre de cette troncature, rendant plus facile le
bombardement de messages frauduleux jusqu’à réussir à forger un motif correct.&lt;/p&gt;
&lt;p&gt;En comparaison, OMEMO emploie AES256 avec le mode de chiffrement authentifié
GCM, considéré à l’état de l’art.&lt;/p&gt;
&lt;h2 id=&#34;34-documentation-et-audits&#34;&gt;3.4. Documentation et audits&lt;/h2&gt;
&lt;p&gt;Signal est une cible mouvante. Jusqu’alors dénué de documentation, par une
volonté affichée de ses développeurs, ce n’est que sur la pression croissante de
la communauté que les algorithmes XEdDSA, X3DH et Double Ratchet ont été
finalement spécifiés et publiés dans le domaine public. Si des études formelles
vont désormais pouvoir être menées sur ces trois protocoles, effectuer ce même
type d’études sur le protocole Signal reste encore un défi. Quelques-uns s’y
sont néanmoins essayés, documentant leurs découvertes du protocole par «
ingénierie inverse du code source », afin de dégager des propriétés de sécurité
&lt;sup id=&#34;fnref:29&#34;&gt;&lt;a href=&#34;#fn:29&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;29&lt;/a&gt;&lt;/sup&gt; &lt;sup id=&#34;fnref:30&#34;&gt;&lt;a href=&#34;#fn:30&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;30&lt;/a&gt;&lt;/sup&gt;. Aucune attaque réellement significative n’a été découverte, à
ce jour.&lt;/p&gt;
&lt;p&gt;En comparaison, le protocole OMEMO est documenté et standardisé dans une
extension expérimentale du protocole XMPP. Il a récemment subi un audit, ayant
révélé divers points d’attention &lt;sup id=&#34;fnref:31&#34;&gt;&lt;a href=&#34;#fn:31&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;31&lt;/a&gt;&lt;/sup&gt;, qui ont été rapidement pris en compte
par le protocole et au moins certaines implémentations.&lt;/p&gt;
&lt;h1 id=&#34;4-conclusion&#34;&gt;4. Conclusion&lt;/h1&gt;
&lt;p&gt;Cet article a détaillé les atouts et inconvénients de plusieurs protocoles
permettant la sécurisation de messageries quasi instantanées. La figure 4
reprend les observations de manière synthétique.&lt;/p&gt;
&lt;p&gt;
  &lt;figure&gt;
    &lt;img src=&#34;./table.jpg&#34; alt=&#34;Synthèse des points forts et faibles de plusieurs protocoles dans le cadre de la messagerie (quasi) instantanée.&#34;&gt;
    &lt;figcaption&gt;Fig. 4 : Synthèse des points forts et faibles de plusieurs protocoles dans le cadre de la messagerie (quasi) instantanée. Les justifications ou références ont été apportées dans l’article.&lt;/figcaption&gt;
  &lt;/figure&gt;

&lt;/p&gt;
&lt;p&gt;Les utilisateurs souhaitant protéger leur messagerie quasi instantanée de bout
en bout disposent d’options valables, comme Signal, WhatsApp, ou encore OMEMO.
Ces outils ont en commun un cœur cryptographique formé des protocoles X3DH et
Double Ratchet, dont il ressort de plusieurs études indépendantes qu’ils
seraient fiables.&lt;/p&gt;
&lt;p&gt;Malgré cela, ces différentes solutions offrent un niveau de protection de la vie
privée et de la confidentialité des messages qui varie de manière significative.
Ainsi, cet article a rappelé, à l’instar d’une conférence lors de la conférence
33c3 &lt;sup id=&#34;fnref:32&#34;&gt;&lt;a href=&#34;#fn:32&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;32&lt;/a&gt;&lt;/sup&gt;, que les numéros de téléphone sont à la fois des identifiants de
compte pratiques, puisque déjà enregistrés dans le téléphone, mais aussi une
donnée personnelle sensible. Outre leur usage éventuel pour géolocaliser des
utilisateurs, ils sont nécessairement transmis en clair, en tant que métadonnées
de tout message : une situation préoccupante lorsque les messages du réseau
doivent passer par une infrastructure centralisée. Cette dernière est, en effet,
en mesure d’observer le graphe social de ses utilisateurs et la fréquence de
leurs échanges, quand bien même leurs concepteurs s’en défendent &lt;sup id=&#34;fnref1:19&#34;&gt;&lt;a href=&#34;#fn:19&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;19&lt;/a&gt;&lt;/sup&gt;. Par
ailleurs, comme cet article l’a présenté, les serveurs de Signal et WhatsApp
sont en charge de la délivrance des clés publiques des contacts d’un
utilisateur. Pour cela, un dérivé cryptographique des numéros de tous les
contacts d’un utilisateur est envoyé aux serveurs, qui répondent avec des clés
publiques associées. Cette dérivation cryptographique est hélas aisément
réversible &lt;sup id=&#34;fnref1:23&#34;&gt;&lt;a href=&#34;#fn:23&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;23&lt;/a&gt;&lt;/sup&gt;, et il est possible de retrouver la liste des contacts d’un
utilisateur de ces applications. En outre, il est à la charge des utilisateurs
de vérifier l’authenticité des clés remises par les serveurs, une étape
probablement rarement effectuée et dont les mécanismes de vérification ont été
récemment dégradés dans Signal, parfois de façon inexplicable &lt;sup id=&#34;fnref2:24&#34;&gt;&lt;a href=&#34;#fn:24&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;24&lt;/a&gt;&lt;/sup&gt;. Pour
WhatsApp, ce mécanisme de distribution de clés a même été à l’origine d’un
tumulte, en janvier 2017, lorsque le journal Guardian a rapporté qu’une
vulnérabilité publique depuis huit mois et non corrigée permet l’interception de
messages en clair &lt;sup id=&#34;fnref:33&#34;&gt;&lt;a href=&#34;#fn:33&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;33&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Finalement, cet article a détaillé le protocole OMEMO, qui utilise le réseau
XMPP pour la distribution des clés et des messages. Le réseau XMPP utilise des
serveurs répartis et des identifiants indépendants de l’identité propre de
l’utilisateur. Chaque utilisateur de XMPP est libre d’employer le serveur de son
choix, dont la sécurité peut être catastrophique ou excellente. Une sécurité
serveur excellente n’exempte cependant pas les utilisateurs de la nécessité de
vérifier les clés cryptographiques.&lt;/p&gt;
&lt;p&gt;Heureusement, grâce à la publication récente dans le domaine public des
spécifications de X3DH et de Double Ratchet par les auteurs de Signal, de
nombreuses applications peuvent s’équiper de ce cœur cryptographique robuste
tout en faisant des choix d’infrastructures plus respectueux de la vie privée
que ne le sont Signal ou WhatsApp.&lt;/p&gt;
&lt;p&gt;Les arguments de l’éditeur de Signal concernant l’agilité d’un écosystème fermé,
soumis aux décisions unilatérales des développeurs, sont certainement fondés. À
l’instar du régime politique démocratique, les réseaux fédérés, comme XMPP,
nécessitent des négociations, des ententes et des compromis. Le résultat peut
cependant, au long cours, se montrer supérieur à la somme des idées exprimées
par les différents intervenants de l’écosystème.&lt;/p&gt;
&lt;p&gt;Ainsi, grâce la stabilité de sa spécification, sa licence ouverte, ses
primitives cryptographiques à l’état de l’art et son architecture répartie,
OMEMO offre aux utilisateurs de XMPP une méthode de communication protégée de
bout en bout efficace, auditable, et potentiellement durable.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Pour le lecteur intéressé, l’application libre Conversations implémente OMEMO et des extensions permettant l’économie de la batterie du périphérique le faisant tourner &lt;sup id=&#34;fnref:34&#34;&gt;&lt;a href=&#34;#fn:34&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;34&lt;/a&gt;&lt;/sup&gt;. Un compte est optionnellement fourni à tout utilisateur faisant l’acquisition de l’application au travers du Google Play Store. Les utilisateurs d’iOS peuvent utiliser ChatSecure &lt;sup id=&#34;fnref:35&#34;&gt;&lt;a href=&#34;#fn:35&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;35&lt;/a&gt;&lt;/sup&gt;. Les utilisateurs PC peuvent, quant à eux, se tourner vers Gajim et son implémentation expérimentale d’OMEMO. Pour les utilisateurs souhaitant effectuer un auto-hébergement de leur serveur XMPP, Prosody &lt;sup id=&#34;fnref:36&#34;&gt;&lt;a href=&#34;#fn:36&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;36&lt;/a&gt;&lt;/sup&gt; implémente la partie serveur des optimisations permettant des économies de batterie. Enfin, la Quadrature du Net fournit un service XMPP ouvert à tous &lt;sup id=&#34;fnref:37&#34;&gt;&lt;a href=&#34;#fn:37&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;37&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id=&#34;5-remerciements&#34;&gt;5. Remerciements&lt;/h1&gt;
&lt;p&gt;Je tiens à remercier mes relecteurs : Piotr Chmielnicki, François Contat, Arnaud
Ebalard, Sarah De Haro, Olivier Levillain, Mickaël Salaün, et Guillaume Valadon.
Les idées exprimées dans cet article ne sauraient les engager.&lt;/p&gt;
&lt;h1 id=&#34;6-réferences&#34;&gt;6. Réferences&lt;/h1&gt;
&lt;p&gt;Publié par les &lt;a href=&#34;https://connect.ed-diamond.com/MISC/misc-090/chiffrement-de-messagerie-quasi-instantanee-a-quel-protocole-se-vouer&#34;&gt;Editions Diamond&lt;/a&gt; sous licence &lt;a href=&#34;https://creativecommons.org/licenses/by-nc-nd/4.0/deed.fr&#34;&gt;CC-BY-NC-ND&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://otr.cypherpunks.ca/&#34;&gt;https://otr.cypherpunks.ca/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.rfc-editor.org/rfc/rfc4880.txt&#34;&gt;https://www.rfc-editor.org/rfc/rfc4880.txt&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref1:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://whispersystems.org/docs/specifications/x3dh/&#34;&gt;https://whispersystems.org/docs/specifications/x3dh/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://whispersystems.org/docs/specifications/doubleratchet/&#34;&gt;https://whispersystems.org/docs/specifications/doubleratchet/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:5&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://xmpp.org/extensions/xep-0384.html&#34;&gt;https://xmpp.org/extensions/xep-0384.html&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:5&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:6&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://news.ycombinator.com/item?id=6913456&#34;&gt;https://news.ycombinator.com/item?id=6913456&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:6&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:7&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://cs.au.dk/~jakjak/master-thesis.pdf&#34;&gt;https://cs.au.dk/~jakjak/master-thesis.pdf&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:7&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:8&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://isi.jhu.edu/~mgreen/imessage.pdf&#34;&gt;https://isi.jhu.edu/~mgreen/imessage.pdf&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:8&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:9&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.ssi.gouv.fr/uploads/2015/05/format-Oracles-on-OpenPGP.pdf&#34;&gt;https://www.ssi.gouv.fr/uploads/2015/05/format-Oracles-on-OpenPGP.pdf&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:9&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:10&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.cypherpunks.ca/~iang/pubs/mpotr.pdf&#34;&gt;https://www.cypherpunks.ca/~iang/pubs/mpotr.pdf&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:10&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:11&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://moderncrypto.org/mail-archive/messaging/2016/002275.html&#34;&gt;https://moderncrypto.org/mail-archive/messaging/2016/002275.html&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:11&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:12&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://whispersystems.org/docs/specifications/xeddsa/&#34;&gt;https://whispersystems.org/docs/specifications/xeddsa/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:12&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:13&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.rfc-editor.org/rfc/rfc5869.txt&#34;&gt;https://www.rfc-editor.org/rfc/rfc5869.txt&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:13&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:14&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/WhisperSystems/libsignal-protocol-java&#34;&gt;https://github.com/WhisperSystems/libsignal-protocol-java&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:14&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:15&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://whispersystems.org/blog/goodbye-encrypted-sms/&#34;&gt;https://whispersystems.org/blog/goodbye-encrypted-sms/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:15&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:16&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/LibreSignal/LibreSignal/issues/37&#34;&gt;https://github.com/LibreSignal/LibreSignal/issues/37&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:16&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:17&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://silence.im/&#34;&gt;https://silence.im/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:17&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:18&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=lQ0I5tl0YLY&#34;&gt;https://www.youtube.com/watch?v=lQ0I5tl0YLY&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:18&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:19&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://whispersystems.org/bigbrother/eastern-virginia-grand-jury/&#34;&gt;https://whispersystems.org/bigbrother/eastern-virginia-grand-jury/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:19&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref1:19&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:20&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://techcrunch.com/2016/07/19/whatsapp-blocked-in-brazil-again/&#34;&gt;https://techcrunch.com/2016/07/19/whatsapp-blocked-in-brazil-again/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:20&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:21&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://whispersystems.org/blog/doodles-stickers-censorship/&#34;&gt;https://whispersystems.org/blog/doodles-stickers-censorship/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:21&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:22&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.bamsoftware.com/papers/fronting/&#34;&gt;https://www.bamsoftware.com/papers/fronting/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:22&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:23&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://whispersystems.org/blog/contact-discovery/&#34;&gt;https://whispersystems.org/blog/contact-discovery/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:23&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref1:23&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:24&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://whispersystems.org/blog/safety-number-updates/&#34;&gt;https://whispersystems.org/blog/safety-number-updates/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:24&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref1:24&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref2:24&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:25&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://support.whispersystems.org/hc/en-us/articles/213134107-How-do-I-verify-the-person-I-m-sending-messages-to-is-who-they-say-they-are-&#34;&gt;https://support.whispersystems.org/hc/en-us/articles/213134107-How-do-I-verify-the-person-I-m-sending-messages-to-is-who-they-say-they-are-&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:25&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:26&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://gultsch.de/trust.html&#34;&gt;https://gultsch.de/trust.html&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:26&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:27&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.rfc-editor.org/rfc/rfc7540.txt&#34;&gt;https://www.rfc-editor.org/rfc/rfc7540.txt&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:27&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:28&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://tools.ietf.org/html/draft-ietf-tls-tls13-18&#34;&gt;https://tools.ietf.org/html/draft-ietf-tls-tls13-18&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:28&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:29&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://eprint.iacr.org/2014/904.pdf&#34;&gt;https://eprint.iacr.org/2014/904.pdf&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:29&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:30&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://eprint.iacr.org/2016/1013.pdf&#34;&gt;https://eprint.iacr.org/2016/1013.pdf&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:30&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:31&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://conversations.im/omemo/audit.pdf&#34;&gt;https://conversations.im/omemo/audit.pdf&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:31&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:32&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://media.ccc.de/v/33c3-8062-a_look_into_the_mobile_messaging_black_box&#34;&gt;https://media.ccc.de/v/33c3-8062-a_look_into_the_mobile_messaging_black_box&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:32&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:33&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://www.theguardian.com/technology/2017/jan/13/whatsapp-backdoor-allows-snooping-on-encrypted-messages&#34;&gt;https://www.theguardian.com/technology/2017/jan/13/whatsapp-backdoor-allows-snooping-on-encrypted-messages&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:33&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:34&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://conversations.im&#34;&gt;https://conversations.im&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:34&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:35&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://chatsecure.org/blog/chatsecure-v4-released/&#34;&gt;https://chatsecure.org/blog/chatsecure-v4-released/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:35&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:36&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://prosody.im&#34;&gt;https://prosody.im&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:36&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:37&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://jabber.lqdn.fr&#34;&gt;https://jabber.lqdn.fr&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:37&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description>
		</item>
	</channel>
</rss>
