Je suis Charlie

Autres trucs

Accueil

Seulement les RFC

Seulement les fiches de lecture

Mon livre « Cyberstructure »

Ève

Ce blog n'a d'autre prétention que de me permettre de mettre à la disposition de tous des petits textes que j'écris. On y parle surtout d'informatique mais d'autres sujets apparaissent parfois.


RFC 8553: DNS Attrleaf Changes: Fixing Specifications That Use Underscored Node Names

Date de publication du RFC : Mars 2019
Auteur(s) du RFC : D. Crocker (Brandenburg InternetWorking)
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 19 avril 2019


Autrefois, de nombreux services et protocoles Internet avaient « réservé » de manière informelle, et sans enregistrement de cette réservation, des noms préfixés par un tiret bas, comme _submission._tcp.example.net (cf. RFC 6186 pour cet exemple). Comme le RFC 8552 a mis fin à cette activité en créant un registre officiel des noms préfixés, il fallait réviser les normes existantes pour s'aligner sur les nouvelles règles. C'est le but de ce RFC 8553 qui modifie pas moins de trente-trois RFC !

Dans le nouveau registre, les entrées sont indexées par un couple {type d'enregistrement DNS, nom}. Par exemple, {TXT, _dmarc} pour DMARC (RFC 7489).

Les enregistrements SRV (RFC 2782) et URI (RFC 7553) posent un problème supplémentaire puisqu'ils utilisent un autre registre de noms, celui des noms de protocoles et services (dit aussi registre des numéros de ports) décrit dans le RFC 6335.

La section 2 du RFC décrit les usages actuels des noms préfixés par le tiret bas. Les enregistrements de type TXT, par exemple, sont utilisés dans sept RFC différents, comme le RFC 5518. Et les SRV dans bien davantage.

Enfin la section 3 du RFC contient le texte des changements qui est fait aux différentes spécifications utilisant les noms préfixés. (Il s'agit essentiellement de faire référence au nouveau registre du RFC 8552, il n'y a pas de changement technique.)


Téléchargez le RFC 8553


L'article seul

RFC 8552: Scoped Interpretation of DNS Resource Records through "Underscored" Naming of Attribute Leaves

Date de publication du RFC : Mars 2019
Auteur(s) du RFC : D. Crocker (Brandenburg InternetWorking)
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 19 avril 2019


Une convention répandue pour les noms de domaine est de préfixer les services par un tiret bas, par exemple _xmpp-client._tcp.jabber.ietf.org. Cette pratique n'avait jamais été documentée mais c'est désormais fait. Et il existe désormais un registre IANA des noms ainsi préfixés.

Bien sûr, on peut mettre des ressources sous n'importe quel nom. Le DNS n'impose aucune restriction pour cela, et vous pouvez décider que le service X sera sous le nom $X%.example.com (si vous ne me croyez pas, relisez le RFC 1035 et RFC 2181). Mais les humains aiment les conventions, par exemple pour les machines, comme www comme préfixe d'un serveur Web (préfixe d'ailleurs contesté, souvent pour de mauvaises raisons) ou mail pour un serveur de messagerie. Ce ne sont que des conventions, le DNS s'en moque, et on peut mettre un serveur Web en mail.example.com si on veut, cela ne perturbera que les humains. D'autant plus qu'on peut utiliser n'importe quel type de données avec n'importe quel nom (par exemple un enregistrement MX pour www.example.org).

La convention du tiret bas initial est répandue, notamment parce qu'elle évite toute confusion avec les noms de machines, qui ne peuvent pas comporter ce caractère (RFC 952). Elle est donc très commune en pratique. Cette convention permet de restreindre explicitement une partie de l'arbre des noms de domaine pour certains usages. Comme ce RFC ne fait que documenter une convention, il ne nécessite aucun changement dans les logiciels.

Une alternative au tiret bas serait d'utiliser un type de données spécifique. Quant aux types « généralistes » comme TXT, ils ont l'inconvénient qu'on récupère, lors de la résolution DNS, des informations inutiles, par exemple les TXT des autres services. Bref, vous créez un nouveau service, mettons X, vous avez le choix, pour le cas du domaine parent example.org, entre :

  • Un nouveau type d'enregistrements DNS, nommons-le par exemple TYPEX (en pratique, c'est long et compliqué, et sans déploiement garanti, cf. RFC 5507),
  • Un type d'enregistrement générique comme TXT cité plus haut ou bien le URI du RFC 7553, menant à des ensembles d'enregistrements (RRset) potentiellement assez gros, problème détaillé en section 1.2,
  • Une convention de nommage comme x.example.org,
  • Une convention de nommage avec un tiret bas (_x.example.org), l'objet de ce RFC 8552.

Un exemple d'un service réel utilisant la convention avec le tiret bas est DKIM (RFC 6376), avec le préfixe _domainkey :


% dig +short TXT mail._domainkey.gendarmerie.interieur.gouv.fr
"v=DKIM1; k=rsa; t=y; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIgwhYZeeZgM94IofX9uaGAwQ+tynFX7rYs/igs+d1afqrrjMaoKay11IMprRyqhcVurQtJwGfk7PAWrXRjB+KpdySH9lqzvbisB3GrSs1Sf4uWscAbZ+saapw3/QD8YFyfYbsXunc6HROJQuQHM+U56OOcoiAiPHpfepAmuQyFQIDAQAB"
      
    

Comme beaucoup de choses, la convention « tiret bas » s'entend mal avec les jokers du DNS. D'abord, on ne peut pas utiliser les jokers entre le préfixe et le reste du nom (_x.*.example.net ne marche pas), ensuite, un joker couvre également les noms avec tiret bas donc *.example.net va répondre positivement pour _x.example.net même si on ne le voulait pas.

La section 1.5 de notre RFC détaille l'histoire de la convention « tiret bas au début ». Beaucoup de services utilisaient cette convention mais sans coordination, et sans qu'il existe une liste complète. Du fait de l'existence de plusieurs choix possibles (énumérés plus haut), ce RFC n'a pas obtenu de consensus immédiatement et les débats ont été longs et compliqués.

La section 2 du RFC explique comment remplir le nouveau registre des noms à tiret bas. On ne met dans ce registre que le nom le plus proche de la racine du DNS. Si un service mène à des noms comme _foo._bar.example.org, seul le _bar sera mis dans le registre. C'est particulièrement important pour le cas des enregistrements SRV qui ont souvent deux niveaux de noms préfixés (par exemple _sip._tcp.cisco.com). Seul le nom le plus proche de la racine, ici _tcp, est enregistré (ici, _sip est quand même enregistré car il peut en théorie être utilisé sans le _tcp mais il me semble que c'est rare en pratique).

Les règles pour les noms plus spécifiques sous le _bar (ou _tcp) sont spécifiées lors de la description du service en question. Par exemple, pour DKIM, le RFC 6376 précise que que sous le nom _domainkey, on trouve un sélecteur dont l'identificateur apparait dans le courrier signé. Donc, pour un message envoyé avec s=mail et d=gendarmerie.interieur.gouv.fr, on cherche les informations DKIM en mail._domainkey.gendarmerie.interieur.gouv.fr.

Le formulaire pour demander l'enregistrement d'un nouveau nom préfixé par un tiret bas figure en section 3 du RFC. Il faut indiquer le type de données DNS (un enregistrement n'est valable que pour un certain type, donc la clé du registre est un couple {type, nom}), le nom et la référence du document décrivant le service en question. Le registre est décrit en section 4 du RFC. L'ajout dans ce registre se fait selon la politique « examen par un expert » (RFC 8126, section 4.5). La section 5 de notre RFC donne quelques indications à l'IANA sur cet examen.

Un ensemble d'entrées à ajouter pour initialiser ce nouveau registre est indiqué. On y trouve par exemple {TXT, _domainkey} pour DKIM, {TLSA, _tcp} pour DANE (RFC 6698), {TXT, _acme-challenge} pour ACME (RFC 8555), etc. Deux cas particuliers : le nom _example est réservé pour tous les types d'enregistrement, lorsqu'on a besoin de donner un exemple, sans spécifier un cas réel, et le nom _ta, qui sert au mécanisme de signalement des clés DNSSEC du RFC 8145, désigne en fait tous les noms commençant par _ta.


Téléchargez le RFC 8552


L'article seul

Cours HTTP au CNAM

Première rédaction de cet article le 18 avril 2019
Dernière mise à jour le 19 avril 2019


Le 17 avril 2019, c'était la première édition de mon cours HTTP de deux heures au CNAM. Pour l'anecdote, c'était dans le bâtiment où il y avait eu l'un des premiers serveurs HTTP publics en France.

Voici les supports de l'exposé :

Tout a été filmé et la vidéo est disponible :

J'ai fait aussi un cours BGP et un cours DNS au même endroit.

Merci à Éric Gressier pour l'idée et l'organisation, et aux élèves pour avoir posé plein de questions pas toujours faciles.


L'article seul

RFC 8574: cite-as: A Link Relation to Convey a Preferred URI for Referencing

Date de publication du RFC : Avril 2019
Auteur(s) du RFC : H. Van de Sompel (Data Archiving and Networked Services), M. Nelson (Old Dominion University), G. Bilder (Crossref), J. Kunze (California Digital Library), S. Warner (Cornell University)
Pour information
Première rédaction de cet article le 18 avril 2019


Ce RFC décrit un nouveau type de liens hypertexte permettant d'indiquer l'URI sous lequel on préfère qu'une ressource soit accédée, à des fins de documentation ou de citation précise.

Imaginons que vous accédez à un article scientifique en ligne. Vous utilisez un URI qui identifie cet article. Vous voulez ensuite citer cet article dans un de vos textes. Allez-vous utiliser l'URI d'accès ? Ce n'est pas forcément le meilleur, par exemple ce n'est pas forcément le plus stable sur le long terme. Le lien « cite avec » permet au serveur d'indiquer l'URI le plus pertinent pour une citation.

Ce RFC s'appuie sur la formalisation du concept de lien faite dans le RFC 8288. « Contexte » et « cible » sont donc utilisés comme dans cette norme, le contexte d'un lien étant le point de départ et la cible l'arrivée. En prime, notre RFC 8574 définit deux termes, l'URI d'accès, celui utilisé pour accéder à une ressource (par exemple une page Web) et l'URI de référence, celui qu'il faudrait utiliser pour la citation.

La section 3 du RFC décrit quelques scénarios d'usage. Le premier est celui des identificateurs stables. Normalement, lorsque le ou la webmestre est compétent(e) et sérieux(se), les URI sont stables, comme précisé dans l'article « Cool URIs don't change. Mais, en pratique, beaucoup de webmestres sont incompétents ou paresseux. Cela a mené à des « solutions » fondées sur la redirection, où il apparait une différence entre URI d'accès et URI de référence. C'est le cas avec des techniques comme les DOI (« use the Crossref DOI URL as the permanent [reference] link »), PURL ou ARK. Dans les trois cas, au lieu de gérer proprement les URI, on utilise un redirecteur supposé plus stable (alors que rien ne le garantit) et on souhaite utiliser comme URI de référence l'URI du redirecteur (donnant ainsi des pouvoirs démesurés à des organisations privées comme l'IDF, qui matraque régulièrement l'importance de n'utiliser que leurs identificateurs).

Un autre scénario d'usage est celui des ressources versionnées. C'est par exemple le cas de Wikipédia. La page Wikipédia sur l'incendie de Notre-Dame de Paris change souvent en ce moment. Comme toutes les pages Wikipédia, chaque version à un identificateur, et on peut se référer à une version particulier. Si https://fr.wikipedia.org/wiki/Incendie_de_Notre-Dame_de_Paris renvoie à la dernière version, sans cesse en mouvement, https://fr.wikipedia.org/w/index.php?title=Incendie_de_Notre-Dame_de_Paris&oldid=158468007 renvoie uniquement à la toute première version, très sommaire et https://fr.wikipedia.org/w/index.php?title=Incendie_de_Notre-Dame_de_Paris&oldid=158478416 à une version intermédiaire déjà très fournie.

Souvent, quand on veut citer un article de Wikipédia, on veut se mettre à l'abri de changements ultérieurs, pas forcément positifs, et on souhaite donc citer exactement une version particulière. On clique donc sur « Lien permanent » (ou bien « Voir l'historique » puis sur la date la plus récente) pour avoir l'URI de la version qu'on vient de regarder. (Notez aussi le très utile lien « Citer cette page ».)

Troisième cas d'usage cité, celui des identifiants sur les réseaux sociaux. M. Toutlemonde a typiquement plusieurs pages le décrivant sur ces réseaux (dans mon cas, https://mastodon.gougere.fr/@bortzmeyer, https://twitter.com/bortzmeyer, https://www.linkedin.com/in/sbortzmeyer/, https://seenthis.net/people/stephane et sans doute bien d'autres que j'ai oubliés, et ceux que j'ai eu la flemme de faire, comme FOAF). Or, on pourrait souhaiter décider qu'un de ces profils est meilleur que les autres, par exemple parce qu'il est plus directement contrôlé par l'utilisateur, ou mieux maintenu. Il serait alors intéressant d'indiquer lors de l'accès à chacun des autres profils quel est le profil de référence. (Le RFC est très irréaliste là-dessus : je vois mal un réseau « social » capitaliste permettre à ses utilisateurs de dire « allez plutôt voir là ».)

Enfin, un dernier cas d'usage est celui d'une publication composée de plusieurs ressources (par exemple un livre où chaque chapitre est accessible séparement, avec son propre URI). On souhaite alors que l'accès à chaque ressource indique, à des fins de citation, l'URI de référence (par exemple la page d'accueil).

La section 4 du RFC présente la solution : un nouveau type de lien, cite-as, qui permet de dire quel est l'URI de référence. (Le RFC recommande d'ailleurs que cet URI soit un URL : le but est d'accéder à la ressource !) Il est évidemment recommandé qu'il n'y ait qu'un seul lien de type cite-as. Ce lien n'interdit pas d'utiliser d'autres URI, il indique seulement quel est l'URI que le webmestre souhaite voir utilisé dans les références webographiques. cite-as est désormais dans le registre IANA des types de liens.

La section 6 du RFC donne des exemples concrets, puisque les liens peuvent se représenter de plusieurs façons. Par exemple, l'article de PLOS One auquel vous accédez en https://journals.plos.org/plosone/article?id=10.1371/journal.pone.0171057 pourrait contenir, en HTML, le lien avec l'attribut rel="cite-as" :


 <link rel="cite-as"
           href="https://doi.org/10.1371/journal.pone.0171057" />    

Cela indiquerait que les auteurs préfèrent être cités par le DOI (une mauvaise idée, mais c'est une autre histoire).

Autre exemple de syntaxe concrète pour les liens, imaginé pour arXiv, pour des articles avec versionnement, un lien dans un en-tête HTTP pour https://arxiv.org/abs/1711.03787, qui pourrait indiquer qu'on est en train de regarder la première version, « v1 » (il existe une « v2 », essayez) :


HTTP/1.1 200 OK
Date: Sun, 24 Dec 2017 16:12:43 GMT
Content-Type: text/html; charset=utf-8
Link: <https://arxiv.org/abs/1711.03787v1> ; rel="cite-as"

    

Comme arXiv garde les différentes versions successives d'un article, cela permettrait de récupérer la version actuelle tout en sachant comment la référencer.

Revenons au HTML pour l'exemple des profils sur les réseaux sociaux, imaginons un utilisateur, John Doe, qui place dans le code HTML de sa page personnelle un lien vers son profil FOAF en Turtle :


<html>
    <head>
    ...
     <link rel="cite-as" href="http://johndoe.example.com/foaf"
           type="text/turtle"/>
    ...
    </head>
    <body>
...

    

Et un dernier exemple, celui d'une publication composée de plusieurs ressources. Ici, l'exemple est Dryad une base de données scientifiques qui permet l'accès à des fichiers individuels, mais où chaque jeu de données a un identificateur canonique. En HTTP, cela donnerait, lorsqu'on accès à https://datadryad.org/bitstream/handle/10255/dryad.98509/PIPFIL_M_BCI.csv (un fichier CSV qui fait partie de cette base de données) :


HTTP/1.1 200 OK
Date: Tue, 12 Jun 2018 19:19:22 GMT
Last-Modified: Wed, 17 Feb 2016 18:37:02 GMT
Content-Type: text/csv;charset=ISO-8859-1
Link: <https://doi.org/10.5061/dryad.5d23f> ; rel="cite-as"

    

Le fichier CSV est membre d'un jeu de données plus général, dont l'URI de référence est https://doi.org/10.5061/dryad.5d23f.

Ainsi, dans un monde idéal, un logiciel qui reçoit un lien cite-as pourrait :

  • Lorsqu'il garde un signet, utiliser l'URI de référence,
  • Identifier plusieurs URI d'accès comme ayant le même URI de référence, par exemple à des fins de comptage,
  • Indexer les ressources par plusieurs URI.

D'autres solutions avaient été proposées pour résoudre ce problème de l'URI de référence. La section 5 de notre RFC les énumère. Il y avait notamment cinq autres types de liens qui auraient peut-être pu convenir, alternate, duplicate, related, bookmark et canonical.

Les trois premiers sont vite éliminés. alternate (RFC 4287) décrit une autre représentation de la même ressource (par exemple la même vidéo mais encodée différemment). duplicate (RFC 6249) désigne une reproduction identique (et cela ne traite donc pas, par exemple, le cas d'une publication composée de plusieurs ressources). Quant à related (RFC 4287), sa sémantique est bien trop vague. Un article des auteurs du RFC décrit en détail les choix de conceptions et explique bien le problème. (Je trouve cet article un peu gâché par les affirmations sans preuves comme quoi les DOI seraient « permanents ». Si le registre disparait ou fait n'importe quoi, il y aura le même problème avec les DOI qu'avec n'importe quelle autre famille d'identificateurs.)

Le cas de bookmark (normalisé par le W3C) est plus compliqué. Il est certainement proche en sémantique de cite-as mais ne peut pas être présent dans les en-têtes HTTP ou dans la tête d'une page HTML, ce qui en réduit beaucoup l'intérêt. Le cas compliqué de bookmark est décrit dans un autre article des auteurs du RFC.

Enfin, le cas de canonical (RFC 6596). Ce dernier semble trop restreint d'usage pour les utilisations prévues pour cite-as. Et il n'a pas vraiment la même sémantique. Par exemple, pour les ressources versionnées, canonical indique la plus récente, exactement le contraire de ce qu'on voudrait avec cite-as. Et c'est bien ainsi que l'utilise Wikipédia. Si je récupère https://fr.wikipedia.org/w/index.php?title=Incendie_de_Notre-Dame_de_Paris&oldid=158478416 :

      
<link rel="canonical" href="https://fr.wikipedia.org/wiki/Incendie_de_Notre-Dame_de_Paris"/>

    

On voit que canonical renvoie à la dernière version. Le cas de canonical fait lui aussi l'objet d'un article détaillé.

Je n'ai pas mis de tels liens sur ce blog, ne voyant pas de cas où ils seraient utiles.


Téléchargez le RFC 8574


L'article seul

RFC 8509: A Root Key Trust Anchor Sentinel for DNSSEC

Date de publication du RFC : Décembre 2018
Auteur(s) du RFC : G. Huston, J. Damas (APNIC), W. Kumari (Google)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 14 avril 2019


On le sait, le premier changement de la clé DNSSEC de la racine du DNS s'est déroulé sans encombre le 11 octobre dernier. Ce qu'on sait moins est que ce changement a été précédé par des nombreuses études, pour tenter de prévoir les conséquences du changement. Une question importante était « combien de résolveurs DNS n'ont pas vu la nouvelle clé, depuis sa publication, et vont donc avoir des problèmes lorsque l'ancienne sera retirée du service ? » Ce RFC décrit une des techniques qui avaient été développées pour répondre à cette question, technique qui continuera à être utile pour les discussions actuellement en cours sur une éventuelle systématisation et accélération du rythme des changements de clé.

La question de cette systématisation a fait par exemple l'objet d'un débat à la dernière réunion IETF à Prague le 28 mars. L'idée est de voir si on peut passer de changements exceptionnels et rares à des changements réguliers, banalisés. Pour cela, il faut avoir une idée de ce que voient les résolveurs DNS, du moins ceux qui valident avec DNSSEC, technique dont l'importance avait encore été démontré par les attaques récentes. Mais comment savoir ce que voient les résolveurs et, notamment, quelle(s) clé(s) de départ de la validation (trust anchor) ils utilisent ? La solution de la sentinelle, spécifiée dans ce nouveau RFC, peut permettre de répondre à cette question. L'idée est que les résolveurs reconnaitront une requête « spéciale », dont le nom commence par root-key-sentinel-is-ta ou root-key-sentinel-not-ta, nom qui sera suivi de l'identificateur (key tag) de la clé (ta = Trust Anchor). La réponse du résolveur dépendra de s'il utilise cette clé ou pas comme point de départ de la validation. Un logiciel client pourra alors tester si son résolveur a bien vu le changement de clé en cours, et est prêt. L'utilisateur peut alors savoir si ce résolveur fonctionnera lors du changement. (Cela peut aussi aider l'administrateurice système mais celui-ci ou celle-là a d'autres moyens pour cela, comme d'afficher le fichier contenant la clé de départ de la validation. Par contre, les sentinelles sont utiles pour les chercheurs qui récoltent des données automatiquement, comme dans l'article de Huston cité à la fin.)

Ce mécanisme de sentinelle est complémentaire de celui du RFC 8145, où le résolveur signale aux serveurs faisant autorité les clés qu'il utilise comme trust anchor. Ici, la cible est le client du résolveur, pas les serveurs faisant autorité que contacte le résolveur. Ce mécanisme de sentinelle permet à tout utilisateur de savoir facilement la(es) clé(s) utilisée(s) par son résolveur DNS.

Petit rappel sur DNSSEC d'abord : comme le DNS, DNSSEC est arborescent. La validation part en général de la racine, et, via les enregistrements DS, arrive à la zone qu'on veut valider. Les clés sont identifiées par un key tag qui est un condensat de la clé. La clé qui est le point de départ de la validation se nomme le trust anchor et est stockée par le résolveur. Si on a la mauvaise clé, la validation échouera. Le trust anchor est géré manuellement par l'administrateur système en charge du résolveur, ou peut être mise à jour automatiquement en suivant la technique du RFC 5011. Aujourd'hui, le résolveur sur la machine où j'écris cet article utilise la trust anchor ayant le key tag 20326, la clé publique de la racine IANA (le résolveur est un Unbound) :

% cat /var/lib/unbound/root.key
...
.	172800	IN	DNSKEY	257 3 8 AwEAAaz/tAm8y...1AkUTV74bU= ;{id = 20326 (ksk), size = 2048b} ;;state=2 [  VALID  ] ;;count=0 ;;lastchange=1502474052 ;;Fri Aug 11 19:54:12 2017
    

Le id = 20326 indique l'identificateur de la clé.

La section 2 expose le cœur du RFC. Un résolveur DNS, validant avec DNSSEC (RFC 4035) et qui met en œuvre ce RFC, doit reconnaitre comme spéciaux, les noms de domaine demandés qui commencent par root-key-sentinel-is-ta-NNNNN et root-key-sentinel-not-ta-NNNNN où NNNNN est un identificateur de clé. Voyons un exemple avec un domaine de test, dans lequel on trouve root-key-sentinel-is-ta-20326.ksk-test.net et root-key-sentinel-not-ta-20326.ksk-test.net (20326 est l'identificateur de la clé actuelle de la racine). Tout résolveur validant qui utilise la clé 20326 va pouvoir récupérer et valider le premier nom :

      
% dig root-key-sentinel-is-ta-20326.ksk-test.net  
...
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 23817
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 3, ADDITIONAL: 1
...
;; ANSWER SECTION:
root-key-sentinel-is-ta-20326.ksk-test.net. 30 IN A 204.194.23.4

    

Ici, le ad dans les résultats indique que l'enregistrement a bien été validé (AD = Authentic Data). Si le résolveur ne valide pas, on n'aura évidemment pas le ad. Maintenant, que se passe-t-il avec le second nom, celui avec not-ta ? Un résolveur validant, mais qui ne met pas en œuvre notre RFC 8509 va récupérer et valider ce nom :


% dig root-key-sentinel-not-ta-20326.ksk-test.net  
...
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 20409
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 3, ADDITIONAL: 1
...
;; ANSWER SECTION:
root-key-sentinel-not-ta-20326.ksk-test.net. 30	IN A 204.194.23.4

    

En revanche, un résolveur validant et qui met en œuvre ce RFC 8509 (ici, le résolveur Knot) va renvoyer un SERVFAIL (Server Failure) :


% dig root-key-sentinel-not-ta-20326.ksk-test.net     
...
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 37396
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0

    

On voit comment on peut utiliser le mécanisme de ce RFC pour découvrir si le résolveur utilise ou pas la clé 20326. Avec un client DNS, et une zone qui dispose des sentinelles :

  • Si on peut récupérer root-key-sentinel-not-ta-20326 et qu'on n'a pas le bit ad, c'est que le résolveur ne valide pas,
  • Si on peut récupérer et valider root-key-sentinel-not-ta-20326, c'est que le résolveur valide mais ne gère pas le mécanisme des sentinelles,
  • Si on peut récupérer et valider root-key-sentinel-is-ta-20326 mais pas root-key-sentinel-not-ta-20326, c'est que le résolveur valide, gère le mécanisme des sentinelles, et utilise la clé 20326,
  • Si on peut récupérer et valider root-key-sentinel-not-ta-20326 mais pas root-key-sentinel-is-ta-20326, c'est que le résolveur valide, gère le mécanisme des sentinelles, et n'utilise pas la clé 20326. (Ce test ne marche pas forcément, cela dépend de comment est configurée la zone de test.)

L'annexe A de notre RFC détaille comment on utilise le mécanisme de sentinelle.

La beauté du mécanisme est qu'on peut l'utiliser sans client DNS, depuis une page Web. On crée une page qui essaie de charger trois images, une depuis invalid.ZONEDETEST (enregistrement mal signé), une depuis root-key-sentinel-is-ta-20326.ZONEDETEST et une depuis root-key-sentinel-not-ta-20326.ZONEDETEST. On teste en JavaScript si les images se sont chargées :

  • Si toutes se chargent, c'est que le résolveur de l'utilisateur ne valide pas,
  • Si la première (invalid) ne charge pas mais que les deux autres chargent, c'est que le résolveur ne connait pas les sentinelles, on ne peut donc pas savoir quelle(s) clé(s) il utilise,
  • Si la première (invalid) et la troisième (root-key-sentinel-not-ta-20326) ne se chargent pas mais que la deuxième (root-key-sentinel-is-ta-20326) se charge, c'est que le résolveur connait les sentinelles, et utilise la clé 20326.
  • Si la première (invalid) et la deuxième (root-key-sentinel-is-ta-20326) ne se chargent pas mais que la troisième (root-key-sentinel-not-ta-20326) se charge, c'est que le résolveur connait les sentinelles, et n'utilise pas la clé 20326. Soit il utilise une autre racine que celle de l'ICANN, soit il a gardé une ancienne clé et aura des problèmes lors du remplacement.

Notez que le choix des préfixes avait été chaudement discuté à l'IETF. À un moment, l'accord s'était fait sur les préfixes _is-ta ou _not-ta, le tiret bas convenant bien à ces noms spéciaux. Mais comme ce même tiret bas rendait ces noms ilégaux comme noms de machine, cela rendait difficile certains tests. Autant _is-ta ou _not-ta étaient utilisables depuis dig, autant on ne pouvait pas les tester depuis un navigateur Web, ce qui rendait difficile des tests semi-automatisés, sous formes d'images qu'on charge depuis une page Web et de JavaScript qui regarde le résultat. D'où les noms root-key-sentinel-is-ta-NNNNN et root-key-sentinel-not-ta-NNNNN. Ce n'est pas une solution satisfaisante que de prendre des noms ne commençant pas par un tiret bas, mais cela a semblé le meilleur compromis possible. Le nom est suffisamment long et alambiqué pour que le risque de collisions avec des noms existants soit faible.

Donc, que doit faire le résolveur quand on l'interroge pour un nom commençant par root-key-sentinel-is-ta-NNNNN ou root-key-sentinel-not-ta-NNNNN ? Si et seulement si le type demandé est A (adresse IPv4) ou AAAA (adresse IPv6), et que la réponse est validée par DNSSEC, le résolveur doit extraire le key tag du nom et déterminer s'il corresponde à une des clés de départ de la validation pour la racine. (Les serveurs faisant autorité, eux, n'ont rien de particulier à faire, ils fonctionnent comme aujourd'hui.)

  • Si le nom demandé commençait par root-key-sentinel-is-ta et que l'identificateur de clé est celui d'une trust anchor, alors on renvoie la réponse originale,
  • Si le nom demandé commençait par root-key-sentinel-is-ta et que l'identificateur n'est pas celui d'une trust anchor, alors on renvoie le code d'erreur SERVFAIL,
  • Si le nom demandé commençait par root-key-sentinel-not-ta et que l'identificateur est celui d'une trust anchor, alors on renvoie le code d'erreur SERVFAIL,
  • Si le nom demandé commençait par root-key-sentinel-not-ta et que l'identificateur n'est pas celui d'une trust anchor, alors on renvoie la réponse originale.

Le principe est simple, les sections suivantes du RFC décrivent comment déduire l'état du résolveur avec ce principe. Par exemple, la section 3 décrit le cas où on n'a qu'un seul résolveur. Si on veut connaitre la situation de la clé 12345, et que les noms nécessaires sont présents dans le domaine xxx.example, que le domaine broken.xxx.example est cassé, question DNSSEC, on cherche à résoudre les noms root-key-sentinel-is-ta-12345.xxx.example, root-key-sentinel-not-ta-12345.xxx.example et broken.xxx.example. Pour un résolveur validant, et qui met en œuvre ce RFC, seule la première requête doit réussir. Si la troisième réussit, c'est que le résolveur ne valide pas. Si la deuxième réussit, c'est qu'il ne connait pas le système sentinelle de notre RFC 8509. (L'algorithme détaillé est dans la section 3 du RFC, il y a quelques cas vicieux.)

Notez bien qu'on n'a pas besoin d'un client DNS complet pour ces tests. Une résolution de nom en adresse normale suffit, ce qui permet de faire ces tests depuis un navigateur Web, ce qui était bien le but. Par exemple en HTML :


     <ul>
      <li><a href="http://invalid.ksk-test.net/invalid.gif">"http://invalid.ksk-test.net/invalid.gif"</a></li>
      <li><a href="http://root-key-sentinel-is-ta-20326.ksk-test.net/is-ta.gif">"http://root-key-sentinel-is-ta-20326.ksk-test.net/is-ta.gif"</a></li>
      <li><a href="http://root-key-sentinel-not-ta-20326.ksk-test.net/not-ta.gif">"http://root-key-sentinel-not-ta-20326.ksk-test.net/not-ta.gif"</a></li>
    </ul>

    

Et avec du JavaScript pour vérifier :

      
      if (img_invalid.height === 0) {invalid = false;}
      if (img_is_ta.height === 0) {is_ta = false;}
      if (img_not_ta.height === 0) {not_ta = false;}

      switch (true) {
        case invalid === true:
          result="You are not DNSSEC validating, and so will be fine!";
        break;
        case (is_ta === true && not_ta === true):
          result="You are using a legacy resolver (or updated resolvers, with some new and some old), we cannot determine your fate!";
        break;
        case (not_ta === true):
           result="WARNING!: Your resolvers do not have the new KSK. Your Internet access will break!"; 
        break;
        case (is_ta === true):
           result="Congratulations, you have the new key. You will be fine.";
        break;
      }

    

Si la machine a plusieurs résolveurs, le cas est plus compliqué par la bibliothèque qui fait la résolution de noms va typiquement passer au résolveur suivant en cas de réponse SERVFAIL. La section 4 décrit un algorithme qui peut permettre, sinon de déterminer la situation exacte de chacun des résolveurs utilisés, en tout cas de voir si une clé donnée a des chances de fonctionner avec cet ensemble de résolveurs.

Quels résolveurs ont ce mécanisme de sentinelle ? BIND l'a depuis la version 9.13, Knot a également ce mécanisme, activé par défaut, depuis la version 2.0 (et le documente), Unbound en dispose depuis la version 1.7.1 et c'est activé par défaut. Parmi les résolveurs DNS publics, Cloudflare et Quad9 ne gèrent apparemment pas les sentinelles de notre RFC 8509.

Côté client, on peut tester son résolveur avec dig, ou bien avec les services Web http://www.ksk-test.net, http://test.kskroll.dnssec.lab.nic.cl/, http://sentinel.research.icann.org/ (le code derrière ce service est publié, notez que les résultats sont présentés en utilisant des codes spécifiques au RFC, pas très lisibles) ou http://www.bellis.me.uk/sentinel/ (utilise le domaine ksk-test.net). La lecture des sources de ces pages est recommandée.

On peut aussi regarder, parmi les sondes RIPE Atlas, lesquelles utilisent un résolveur avec sentinelles :

    
% blaeu-resolve --displayvalidation --type A --requested 100 --dnssec root-key-sentinel-not-ta-20326.ksk-test.net                                             
[ (Authentic Data flag)  204.194.23.4] : 30 occurrences 
[ERROR: SERVFAIL] : 12 occurrences 
[ (Authentic Data flag)   (TRUNCATED - EDNS buffer size was 4096 )  204.194.23.4] : 1 occurrences 
[204.194.23.4] : 52 occurrences 
Test #20692175 done at 2019-04-13T16:32:15Z

% blaeu-resolve --displayvalidation --type A --requested 100 --old_measurement 20692175 --dnssec root-key-sentinel-is-ta-20326.ksk-test.net                                                   
[ERROR: SERVFAIL] : 1 occurrences 
[ (Authentic Data flag)  204.194.23.4] : 38 occurrences 
[204.194.23.4] : 56 occurrences 
Test #20692176 done at 2019-04-13T16:33:56Z

Le premier test montre 52 sondes utilisant un résolveur non validant, 30 utilisant un validant sans sentinelles (ou bien utilisant une autre clé que 20326), et 12 utilisant un résolveur validant avec sentinelles. Le second test, effectué avec exactement les mêmes sondes, montre que les sondes utilisant un résolveur validant à sentinelles utilisent bien la clé 20326 (sauf une, qui a un SERVFAIL). Notez que les nombres ne coïncident pas parfaitement (30 + 12 - 1 ne fait pas 38), sans doute parce que certaines sondes ont plusieurs résolveurs DNS configurés, ce qui complique sérieusement l'analyse.

Un exemple d'utilisation de ce mécanisme de sentinelles figure dans cet article de Geoff Huston et cet autre.


Téléchargez le RFC 8509


L'article seul

RFC 8544: Organization Extension for the Extensible Provisioning Protocol (EPP)

Date de publication du RFC : Avril 2019
Auteur(s) du RFC : L. Zhou (CNNIC), N. Kong (Consultant), J. Wei, J. Yao (CNNIC), J. Gould (Verisign)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF regext
Première rédaction de cet article le 12 avril 2019


Le RFC 8543 étendait le format utilisé par le protocole d'avitaillement EPP, afin d'ajouter le concept d'« organisation », une entreprise, association ou agence qui joue un rôle dans la création et gestion d'objets enregistrés, notamment les noms de domaine. Ce RFC 8544 ajoute une extension au protocole EPP pour affecter ces organisations à un domaine, contact ou autre objet enregistré.

Prenons l'exemple le plus connu (quoique EPP puisse servir à d'autres), celui de l'industrie des noms de domaine. Souvent, le registre reçoit des demandes d'un BE, via le protocole EPP. Mais d'autres organisations peuvent jouer un rôle, en plus du BE. Il y a par exemple l'hébergeur DNS (qui n'est pas forcément le BE) ou bien un revendeur du BE, ou bien un « anonymisateur » qui, pour protéger la vie privée des participants, est placé entre le participant et le monde extérieur. Ces différents acteurs (cf. RFC 8499, section 9, pour la terminologie) sont décrits par les nouvelles classes d'objets du RFC 8543. Notre RFC 8544 permet d'utiliser ces classes. Une fois les objets « organisation » créés au registre, on peut les attacher à un nom de domaine ou à un contact, par exemple pour dire « ce nom de domaine a été acheté via le revendeur X ».

L'espace de noms XML est urn:ietf:params:xml:ns:epp:orgext-1.0 (et est enregistré dans le registre IANA). L'extension à EPP est notée dans le registre des extensions EPP. Dans les exemples qui suivent, l'espace de noms est abrégé orgext. Les organisations ont un identificateur (le <org:id> du RFC 8543), et cet identificateur sera un attribut <orgext:id> des objets comme par exemple le domaine. Pour chaque rôle (revendeur, hébergeur DNS, etc, cf. RFC 8543, section 7.3), le domaine a au plus un attribut identifiant une organisation.

La section 4 du RFC décrit les ajouts aux commandes et réponses EPP. Par exemple, pour <info>, la commande ne change pas mais la réponse a désormais en plus des attributs <orgext:id>. Voici un exemple :


<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
  <response>
   <result code="1000">
      <msg lang="en-US">Command completed successfully</msg>
    </result>
    <resData>
      <domain:infData
        xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
        <domain:name>example.com</domain:name>
        ...
    </resData>
    <extension>
      <orgext:infData
        xmlns:orgext="urn:ietf:params:xml:ns:epp:orgext-1.0">
        <orgext:id role="reseller">reseller1523</orgext:id>
        <orgext:id role="privacyproxy">proxy2935</orgext:id>
      </orgext:infData>
    </extension>
    <trID>
      <clTRID>ngcl-IvJjzMZc</clTRID>
      <svTRID>test142AWQONJZ</svTRID>
    </trID>
  </response>
</epp>

    

Ici, le domaine a été avitaillé via le revendeur « reseller1523 » et est protégé par l'« anonymisateur » « proxy2935 ».

Bien sûr, la commande EPP <create> est également modifiée, pour pourvoir créer un domaine avec les organisations associées. Ici, le revendeur « reseller1523 » crée un domaine :


<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
  <command>
    <create>
      <domain:create
        xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
        <domain:name>example.com</domain:name>
        <domain:period unit="y">3</domain:period>
        ...
    </create>
    <extension>
      <orgext:create
        xmlns:orgext="urn:ietf:params:xml:ns:epp:orgext-1.0">
        <orgext:id role="reseller">reseller1523</orgext:id>
      </orgext:create>
    </extension>
  </command>
</epp>

De le même façon, on peut mettre à jour les organisations associées à un objet, avec <update>. Ici, on ajoute un « anonymiseur » :

      
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
  <command>
    <update>
      <domain:update
        xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
        <domain:name>example.com</domain:name>
      </domain:update>
    </update>
    <extension>
      <orgext:update
        xmlns:orgext="urn:ietf:params:xml:ns:epp:orgext-1.0">
        <orgext:add>
            <orgext:id role="privacyproxy">proxy2935</orgext:id>
        </orgext:add>
      </orgext:update>
    </extension>
  </command>
</epp>

    

Et ici on retire le revendeur (pas besoin d'indiquer son identificateur, rappelez-vous qu'il ne peut y avoir qu'une seule organisation par rôle) :


<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
  <command>
    <update>
      <domain:update
        xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
        <domain:name>example.com</domain:name>
      </domain:update>
    </update>
    <extension>
      <orgext:update
        xmlns:orgext="urn:ietf:params:xml:ns:epp:orgext-1.0">
        <orgext:rem>
          <orgext:id role="reseller"/>
        </orgext:rem>
      </orgext:update>
    </extension>
  </command>
</epp>

La syntaxe complète (au format XML Schema) figure dans la section 5 du RFC.

Question mise en œuvre, cette extension est dans le SDK de Verisign, accessible avec leurs autres logiciels pour registres. CNNIC a également inclus cette extension, dans leur code interne.


Téléchargez le RFC 8544


L'article seul

RFC 8543: Extensible Provisioning Protocol (EPP) Organization Mapping

Date de publication du RFC : Mars 2019
Auteur(s) du RFC : L. Zhou (CNNIC), N. Kong (Consultant), G. Zhou, J. Yao (CNNIC), J. Gould (Verisign)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF regext
Première rédaction de cet article le 12 avril 2019


L'industrie des noms de domaine est d'une grande complexité. Les utilisateurs s'y perdent facilement entre registres, bureaux d'enregistrement, hébergeurs DNS, revendeurs divers, sociétés qui développent des sites Web, prête-noms pour protéger la vie privée, etc. Cette complexité fait qu'il est difficile de savoir qui est responsable de quoi. Dans le contexte d'EPP, protocole d'avitaillement de noms de domaine (création, modification, suppression de noms), il n'y avait jusqu'à présent pas de moyen de décrire ces acteurs. Par exemple, l'ajout d'un enregistrement DS dépend d'actions de l'hébergeur DNS, qui n'est pas forcément le BE. Mais ces hébergeurs DNS n'étaient pas définis et connus. Désormais, avec ce nouveau RFC, on peut utiliser EPP pour l'avitaillement d'objets « organisation ».

EPP (RFC 5730) est le protocole standard d'avitaillement de noms de domaine, permettant à un client (en général le BE) de créer des objets dans un registre, en parlant au serveur EPP. EPP permettait déjà des objets de type « contact » RFC 5733, identifiant les personnes ou les organisations qui assuraient certaines fonctions pour un nom de domaine. Par exemple, le contact technique était la personne ou l'organisation à contacter en cas de problème technique avec le nom de domaine.

Désormais, avec notre nouveau RFC 8543, une nouvelle catégorie (mapping) d'objets est créée, les organisations. On peut ainsi utiliser EPP pour enregistrer l'hébergeur DNS d'un domaine (qui peut être le titulaire du domaine, mais ce n'est pas toujours le cas, ou qui peut être le BE, mais ce n'est pas systématique). Ce nouveau RFC décrit donc une extension à EPP, qui figure désormais dans le registre des extensions (cf. RFC 7451).

EPP utilise XML et tout ici va donc être spécifié en XML, avec un nouvel espace de noms XML, urn:ietf:params:xml:ns:epp:org-1.0, abrégé en org dans le RFC (mais rappelez-vous que le vrai identificateur d'un espace de noms XML est l'URI, pas l'abréviation). Le nouvel espace de noms est désormais dans le registre des espaces de noms.

La section 3 de notre RFC décrit les attributs d'une organisation (notez que le vocabulaire est trompeur : ils s'appellent attributs mais ne sont pas des attributs XML). Mais commençons par un exemple, décrivant le BE nommé « Example Registrar Inc. » :


<org:infData
    xmlns:org="urn:ietf:params:xml:ns:epp:org-1.0">
    <org:id>registrar1362</org:id>
    <org:roid>registrar1362-REP</org:roid>
    <org:role>
      <org:type>registrar</org:type>
      <org:status>ok</org:status>
      <org:status>linked</org:status>
      <org:roleID>1362</org:roleID>
    </org:role>
    <org:status>ok</org:status>
    <org:postalInfo type="int">
      <org:name>Example Registrar Inc.</org:name>
      <org:addr>
        <org:street>123 Example Dr.</org:street>
        <org:city>Dulles</org:city>
        <org:sp>VA</org:sp>
        <org:cc>US</org:cc>
      </org:addr>
    </org:postalInfo>
    <org:voice x="1234">+1.7035555555</org:voice>
    <org:email>contact@organization.example</org:email>
    <org:url>https://organization.example</org:url>
    <org:contact type="admin">sh8013</org:contact>
    <org:contact type="billing">sh8013</org:contact>
    <org:contact type="custom"
       typeName="legal">sh8013</org:contact>
    <org:crID>ClientX</org:crID>
    <org:crDate>1999-04-03T22:00:00.0Z</org:crDate>
    <org:upID>ClientX</org:upID>
    <org:upDate>1999-12-03T09:00:00.0Z</org:upDate>
</org:infData>

Voyons maintenant quelques-uns des attributs possibles.

Une organisation a un identificateur, indiqué par l'élément XML <org:id>, attribué par le registre (c'est registrar1362 dans l'exemple). Il a aussi un ou plusieurs rôles, dans l'élement XML <org:role>. Un même acteur peut avoir plusieurs rôles (par exemple il est fréquent que les BE soient également hébergeurs DNS). Le rôle inclut un type, qui peut valoir :

  • registrar : BE, comme dans le cas ci-dessus,
  • reseller : revendeur, par exemple l'organisation à laquelle le titulaire du nom de domaine achète un domaine n'est pas toujours un « vrai » BE, ce peut être un revendeur,
  • privacyproxy : un prête-nom qui, en se mettant devant l'utilisateur, permet de protéger sa vie privée,
  • et enfin dns-operator, l'hébergeur DNS.

D'autres types pourront apparaitre dans le futur, ils sont indiqués dans un registre IANA, des nouveaux types seront ajoutés en suivant la procédure « Examen par un expert » du RFC 8126.

Notez qu'au début du travail à l'IETF sur cette extension, seul le cas des revendeurs était prévu. Après des discussions sur l'importance relative des différents acteurs, il a été décidé de prévoir d'autres types que les seuls revendeurs.

Il y a aussi dans l'objet un ou plusieurs état(s), <org:status>, qui peut valoir notamment :

  • ok, l'état normal, celui du BE dans l'exemple ci-dessus,
  • terminated, quand l'organisation va être retirée de la base et ne peut plus être utilisée (c'est le cas d'un BE qui n'est plus accrédité),
  • linked, qui indique que cette organisation est liée à d'autres objets, et ne doit donc pas être supprimée.

Il existe également un attribut <org:parent>, qui indique une relation avec une autre organisation. Par exemple, un revendeur aura une relation <org:parent> vers le BE dont il est revendeur. (Dans l'exemple plus haut, il n'y a pas de <org:parent>.)

La section 4 du RFC présente ensuite les commandes EPP qui peuvent être appliquées à ces objets « organisation ». <check> permet au client EPP de savoir s'il pourra créer un objet, <info> lui donnera les moyens de s'informer sur une oranisation (l'exemple en XML ci-dessus était le résultat d'une commande EPP <info>) et bien sûr une commande <create> et une <delete>. Voici <create> en action, pour créer un objet de rôle « revendeur » (notez que, cette fois, il a un parent) :


<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
  <command>                                                                                                           
    <create>                                                                                                          
      <org:create                                                                                                     
        xmlns:org="urn:ietf:params:xml:ns:epp:org-1.0">                                                               
        <org:id>res1523</org:id>                                                                                      
        <org:role>                                                                                                    
          <org:type>reseller</org:type>                                                                               
        </org:role>                                                                                                   
        <org:parentId>1523res</org:parentId>                                                                          
        <org:postalInfo type="int">                                                                                   
          <org:name>Example Organization Inc.</org:name>                                                              
          <org:addr>                                                                                                  
            <org:street>123 Example Dr.</org:street>                                                                  
            <org:city>Dulles</org:city>                                                                               
            <org:sp>VA</org:sp>                                                                                       
            <org:cc>US</org:cc>                                                                                       
          </org:addr>                                                                                                 
        </org:postalInfo>                                                                                             
        <org:voice x="1234">+1.7035555555</org:voice>                                                                 
        <org:email>contact@organization.example</org:email>                                                           
        <org:url>https://organization.example</org:url>                                                               
        <org:contact type="admin">sh8013</org:contact>                                                                
        <org:contact type="billing">sh8013</org:contact>                                                              
      </org:create>                                                                                                   
    </create>                                                                                                         
  </command>                                                                                                          
</epp>                                                                                                                

  

Le schéma complet, en syntaxe XML Schema, figure dans la section 5 du RFC.

Question mise en œuvre de cette extension EPP, Verisign l'a ajouté dans son SDK, disponible en ligne. CNNIC a une implémentation, mais non publique.


Téléchargez le RFC 8543


L'article seul

RFC 8555: Automatic Certificate Management Environment (ACME)

Date de publication du RFC : Mars 2019
Auteur(s) du RFC : R. Barnes (Cisco), J. Hoffman-Andrews (EFF), D. McCarney (Let's Encrypt), J. Kasten (University of Michigan)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF acme
Première rédaction de cet article le 11 avril 2019


Une grande partie de la sécurité du Web, et d'ailleurs de plein d'autres chose sur l'Internet, repose sur des certificats où une Autorité de Certification (AC) garantit que vous êtes bien ce que vous prétendez être. Traditionnellement, l'émission d'un certificat se faisait selon un processus manuel, lent et coûteux, à part dans quelques AC automatisées et gratuites comme CAcert. Mais il n'existait pas de mécanisme standard pour cette automatisation. (Et CAcert n'a pas d'API, même non-standard.) Un tel mécanisme standard existe désormais, avec le protocole ACME, normalisé dans ce RFC. Son utilisateur le plus connu est l'AC Let's Encrypt.

Pour comprendre ACME, il faut d'abord revenir aux utilisations des certificats. La norme technique pour les certificats utilisés sur l'Internet se nomme PKIX et est normalisée dans le RFC 5280. PKIX est un profil (une restriction d'une norme beaucoup plus large - et bien trop large, comme le sont souvent les normes des organismes comme l'UIT ou l'ISO) de X.509. Un certificat PKIX comprend, entre autres :

  • Une clé cryptographique publique, le titulaire du certificat étant supposé conserver avec soin et précaution la clé privée correspondante,
  • Le nom du titulaire du certificat (X.509 l'appelle le sujet),
  • Une signature de l'émetteur du certificat (l'AC).
  • Des métadonnées dont notamment la date d'expiration du certificat, qui sert à garantir qu'en cas de copie de la clé privée, le copieur ne pourra pas profiter du certificat éternellement.

On note que le certificat est public. N'importe qui peut récupérer le certificat de, par exemple, un site Web. Voici un exemple avec OpenSSL et www.labanquepostale.fr pour un certificat de type EV :

% openssl s_client -connect www.labanquepostale.fr:443 -showcerts | openssl x509 -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            0d:8f:ec:dd:d8:7b:83:b8:a0:1e:eb:c2:a0:2c:10:9b
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert SHA2 Extended Validation Server CA
        Validity
            Not Before: Sep  5 00:00:00 2018 GMT
            Not After : Sep  4 12:00:00 2020 GMT
        Subject: businessCategory = Private Organization, jurisdictionC = FR, serialNumber = 421 100 645, C = FR, L = PARIS, O = LA BANQUE POSTALE SA, OU = DISFE, CN = www.labanquepostale.fr
...
    

et un avec GnuTLS pour un certificat DV (Domain Validation), mamot.fr :

% gnutls-cli mamot.fr
 - subject `CN=mamot.fr', issuer `CN=Let's Encrypt Authority X3,O=Let's Encrypt,C=US', serial 0x035516154ab9120c186e9211d0da6296af62, RSA key 2048 bits, signed using RSA-SHA256, activated `2019-01-13 23:00:32 UTC', expires `2019-04-13 23:00:32 UTC', key-ID `sha256:ef62c4aae2a9a99c00c33f2bbac9c40b980c70400a056e2a8042885e501ce283'
...

D'ailleurs, des services comme Certificate Transparency (RFC 6962), accessible entre autres en https://crt.sh/, donnent accès facilement à tous les certificats émis par les AC participantes.

Du fait que seul le titulaire connait la clé privée, la capacité à signer des messages vérifiables avec la clé publique permet d'authentifier le partenaire avec lequel on communique. Grâce à la signature de l'AC, quiconque fait confiance à cette AC particulière peut être sûr que le certificat appartient bien au titulaire. Dans l'exemple avec OpenSSL, le certificat de la Banque Postale était signé par DigiCert, si on fait confiance à DigiCert, on sait qu'on est bien connecté à la Banque Postale.

Qui sont les AC ? Ce sont la plupart du temps des entreprises commerciales qui sont payées par les titulaires de certificat, et elles sont censées vérifier la sincérité de leurs clients. Cette vérification peut être manuelle, partiellement ou totalement automatique. Normalement, les certificats de type EV (Extended Validation), comme celui de la Banque Postale plus haut, font l'objet d'une vérification manuelle. Cela permet de vérifier l'identité officielle (celle gérée par l'État) du titulaire. Les certificats DV (Domain Validation), comme celui de mamot.fr, eux, peuvent être validés automatiquement, ils assurent uniquement le fait que le titulaire contrôle bien le nom de domaine utilisé comme sujet. (Pour avoir tous les horribles détails, y compris les certificats OV - Organization Validated - dont je n'ai pas parlé, on peut consulter les « Baseline Requirements for the Issuance and Management of Publicly-Trusted Certificates » du CA/Browser Forum.) Ainsi, pour CAcert, on doit prouver le contrôle du domaine en répondant aux courriers envoyés aux adresses publiques de contact pour le domaine.

Les certificats peuvent servir à de nombreux protocoles de sécurité mais le plus connu est TLS (normalisé dans le RFC 8446). Comme il n'est pas le seul protocole pour lequel on a des certificats, il est erroné de parler de « certificats TLS » ou, pire encore, de « certificats SSL ». TLS est un protocole client/serveur, où le client authentifie le serveur mais où le serveur authentifie rarement le client. Il est à la base de la sécurisation d'un grand nombre de services sur l'Internet, à commencer par le Web avec HTTPS (RFC 2818). L'authentification du serveur par le client est faite en vérifiant (attention, je vais simplifier) :

  • Que le partenaire avec qui on parle a la clé privée (il peut signer des messages) correspondant au certificat présenté,
  • Que le certificat n'a pas expiré,
  • Que le certificat est signé par une AC connue du client (la clé publique de l'AC est dans le magasin du client),
  • Que le nom indiqué par le client correspond à un des noms disponibles dans le certificat. Dans le cas du Web, c'est le nom de domaine dans l'URL choisi (RFC 6125).

Une fois cette authentification faite, TLS assure l'intégrité et la confidentialité de la communication.

Attention, on parle bien d'authentification, pas de confiance. Malgré ce que vous pourrez lire dans les « La sécurité pour les nuls », le fameux « cadenas vert » ne signifie pas du tout que vous pouvez faire vos achats en ligne en toute sécurité. Il indique seulement que le partenaire a bien le nom que vous avez demandé, et qu'un tiers ne pourra pas écouter ou modifier la conversation. Il n'indique pas que le partenaire soit digne de confiance ; l'AC ne peut pas vérifier cela ! Ainsi, dans l'exemple plus haut, TLS et l'authentification par certificat garantissent bien qu'on se connecte au serveur HTTPS de la Maison-Blanche, www.whitehouse.gov, mais pas que Trump dise la vérité !

J'ai parlé du magasin où se trouvent les clés des AC à qui on fait confiance. Qui décide du contenu de ce magasin ? C'est une question complexe, il n'y a pas une liste d'AC faisant autorité. La plupart des systèmes d'exploitation ont une liste à eux, créée en suivant des critères plus ou moins opaques. Les applications (comme le navigateur Web) utilisent ce magasin global du système ou, parfois, ont leur propre magasin, ce qui aggrave encore la confusion. Les utilisateurs peuvent (c'est plus ou moins facile) ajouter des AC ou bien en retirer.

Et comment obtient-on un certificat ? Typiquement, on crée d'abord une demande de certificat (CSR pour Certificate Signing Request, cf. RFC 2986). Avec OpenSSL, cela peut se faire avec :

% openssl req  -new -nodes -newkey rsa:2048 -keyout server.key -out server.csr
    

On se connecte ensuite au site Web de l'AC choisie, et on lui soumet le CSR. Ici, un exemple avec CAcert : cacert-csr.png

L'AC doit alors faire des vérifications, plus ou moins rigoureuses. Par exemple, l'AC fait une requête whois, note l'adresse de courrier du domaine, envoie un message contenant un défi et le client de l'AC doit y répondre pour prouver qu'il a bien accès à cette adresse et contrôle donc bien le domaine. L'AC crée ensuite le certificat qu'elle vous renvoie. Il faut alors l'installer sur le serveur (HTTPS, par exemple). L'opération est complexe, et beaucoup d'utilisateurs débutants cafouillent.

C'est ce processus non-standard et compliqué que le protocole ACME vise à normaliser et à automatiser. Ce RFC a une longue histoire mais est déjà déployé en production par au moins une AC.

Le principe d'ACME est simple : l'AC fait tourner un serveur ACME, qui attend les requêtes des clients. Le client ACME (un logiciel comme dehydrated ou certbot) génère la CSR, se connecte au serveur, et demande un certificat signé pour un nom donné. Le serveur va alors renvoyer un défi qui va permettre au client de prouver qu'il contrôle bien le nom de domaine demandé. Il existe plusieurs types de défis, mais le plus simple est un nom de fichier que le serveur ACME choisit, demandant au client ACME de mettre un fichier de ce nom sur son site Web. Si le nom de fichier était Vyzs0Oqkfa4gn4skMwszORg6vJaO73dvMLN0uX38TDw, le serveur ACME va devenir client HTTP et chercher à récupérer http://DOMAIN/.well-known/acme-challenge/Vyzs0Oqkfa4gn4skMwszORg6vJaO73dvMLN0uX38TDw. S'il y réussit, il considère que le client ACME contrôle bien le nom de domaine, et il signe alors le certificat, qui est renvoyé au client lorsque celui-ci soumet la CSR.

Le modèle idéal d'utilisation d'ACME est présenté dans la section 2. (En pratique, il n'est pas vraiment réalisé, notamment parce qu'il n'existe pratiquement qu'une seule AC utilisant ACME, Let's Encrypt. Il n'y a donc pas encore beaucoup de diversité.) L'espoir est qu'un jour, on puisse faire comme suit :

  • On installe un serveur Web (avec des services comme le CMS),
  • La procédure d'installation vous demande le nom de domaine à utiliser (ce point là n'est pas automatisable, sans même parler de la procédure de location du nom de domaine),
  • Le logiciel vous propose une liste d'AC parmi lesquelles choisir (on a vu qu'il n'y en avait qu'une actuellement ; dans le futur, s'il y en a plusieurs, l'utilisateur aura sans doute autant de mal à choisir qu'il ou elle en a aujourd'hui à choisir un BE),
  • Le logiciel fait tout le reste automatiquement : requête à l'AC choisie en utilisant le protocole ACME normalisé dans notre RFC, réponse au défi de l'AC via le serveur HTTP installé, récupération du certificat et configuration de TLS,
  • Par la suite, c'est le logiciel qui effectuera automatiquement les demandes de renouvellement de certificat (aujourd'hui, avec les logiciels existants, c'est le point qui est le plus souvent oublié ; combien de sites Web ont annoncé fièrement qu'ils étaient désormais protégés par HTTPS, pour afficher un certificat expiré trois mois après…)

Ainsi, une procédure manuelle et pénible pourra devenir assez simple, encourageant une présence en ligne plus sécurisée. Cela pourrait devenir aussi simple que d'avoir un certificat auto-signé.

La section 4 du RFC expose de manière générale le protocole ACME (le RFC complet fait 94 pages, car il y a beaucoup de détails à spécifier). Rappelez-vous avant de la lire que, pour ACME, le client est celui qui demande le certificat (c'est donc typiquement un serveur Internet, par exemple un serveur HTTPS) et le serveur ACME est l'AC. Quand je dirais « client » ou « serveur » tout court, il s'agira du client et du serveur ACME.

ACME encode ses messages en JSON (RFC 8259). Le client doit d'abord avoir un compte auprès du serveur (avec Let's Encrypt, cela peut être fait automatiquement sans que l'utilisateur s'en rende compte). Par exemple, avec dehydrated, cela se fait ainsi :

% dehydrated --register --accept-terms 
+ Generating account key...
+ Registering account key with ACME server...
+ Done!

Et on trouve dans le répertoire accounts/ la clé privée du compte, et les informations du compte :

% cat accounts/aHR0cHM6Ly9...9yeQo/registration_info.json 
{
  "id": 5...1,
  "key": {
    "kty": "RSA",
    "n": "wv...HCk",
    "e": "AQAB"
  },
  "contact": [],
  "initialIp": "2001:4b98:dc0:41:216:3eff:fe27:3d3f",
  "createdAt": "2019-03-12T19:32:20.018154799Z",
  "status": "valid"
}

Pour certbot, on peut le faire tourner avec l'option -v pour avoir les mêmes informations. certbot affiche également des messages d'ordre administratif comme :

Enter email address (used for urgent renewal and security notices) (Enter 'c' to
cancel): stephane+letsencrypt@bortzmeyer.org
...
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must
agree in order to register with the ACME server at
https://acme-v02.api.letsencrypt.org/directory
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(A)gree/(C)ancel: A

JWS payload:
b'{\n  "contact": [\n    "mailto:stephane+letsencrypt@bortzmeyer.org"\n  ],\n  "termsOfServiceAgreed": true,\n  "resource": "new-reg"\n}'
{
  "id": 53367492,
  "key": { ...
  "contact": [
    "mailto:stephane+letsencrypt@bortzmeyer.org"
  ],
  "createdAt": "2019-03-15T16:07:58.29914038Z",
  "status": "valid"
}

Reporting to user: Your account credentials have been saved in your Certbot configuration directory at /etc/letsencrypt. You should make a secure backup of this folder now. This configuration directory will also contain certificates and private keys obtained by Certbot so making regular backups of this folder is ideal.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing to share your email address with the Electronic Frontier
Foundation, a founding partner of the Let's Encrypt project and the non-profit
organization that develops Certbot? We'd like to send you email about our work
encrypting the web, EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: No
...
   

Le compte sera authentifié en utilisant une biclé (clé privée et clé publique). Il y aura ensuite quatre étapes :

  • Demander un certificat,
  • Répondre au défi (notez bien qu'ACME permet plusieurs types de défis possibles),
  • Envoyer le CSR,
  • Récupérer le certificat signé.

Mais comment transporte-t-on ces messages en JSON ? La section 6 du RFC répond à cette question : on utilise HTTPS. En prime, les messages sont signés avec JWS (RFC 7515), en utilisant la clé privée du client pour les requêtes. Voici par exemple la réponse d'un serveur ACME lorsqu'on l'interroge sur un défi en cours :

{
  "type": "http-01",
  "status": "pending",
  "url": "https://acme-v02.api.letsencrypt.org/acme/challenge/7TAkQBMmFqm8Rhs6Sn8SFCne2MoZXoEHCz0Px7f0dpE/13683685175",
  "token": "mMXGXjEijKBZXl2RuL0rjlektPPpy-ozJpZ2vB4w6Dw"
}     
    

Les messages d'erreur utilisent le RFC 7807. En voici un exemple :

{
  "type": "http-01",
  "status": "invalid",
  "error": {
    "type": "urn:acme:error:unauthorized",
    "detail": "Invalid response from http://mercredifiction.bortzmeyer.org/.well-known/acme-challenge/rE-rIfjjCfMlivxLfoJmMbRyspwmld97Xnxmy7K0-JA: \"\u003c!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\"\u003e\n\u003chtml\u003e\u003chead\u003e\n\u003ctitle\u003e404 Not Found\u003c/title\u003e\n\u003c/head\u003e\u003cbody\u003e\n\u003ch1\u003eNot Found\u003c/h1\u003e\n\u003cp\"",
    "status": 403  ...
   [Le message d'erreur indique également typiquement l'URL demandé,
   et les adresses IP utilisées, ce qui est crucial si le serveur HTTP
   a plusieurs adresses IP, par exemple une en IPv4 et une en IPv6. Il
   faut donc bien lire tout le message d'erreur.]
     

Une liste des erreurs possibles est enregistrée à l'IANA. Voici par exemple une erreur CAA (RFC 6844) :

  "error": {
    "type": "urn:acme:error:caa",
    "detail": "CAA record for mercredifiction.bortzmeyer.org prevents issuance",
    "status": 403
  },
     

Comment un client ACME trouve-t-il les URL pour les différentes opérations ? Il y a un URL à connaitre, le répertoire (directory). Une requête à cet URL (par exemple curl https://acme-v02.api.letsencrypt.org/directory va renvoyer un objet JSON qui contient la liste des autres URL (section 7, une des plus cruciales du RFC). Voici un exemple chez Let's Encrypt :

{ ...
  "meta": {
    "caaIdentities": [
      "letsencrypt.org"
    ],
    "termsOfService": "https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf",
    "website": "https://letsencrypt.org"
  },
  "newAccount": "https://acme-v02.api.letsencrypt.org/acme/new-acct",
  "newNonce": "https://acme-v02.api.letsencrypt.org/acme/new-nonce",
  "newOrder": "https://acme-v02.api.letsencrypt.org/acme/new-order",
  "revokeCert": "https://acme-v02.api.letsencrypt.org/acme/revoke-cert"
}
    

On peut ensuite créer un compte (le champ newAccount dans l'exemple ci-dessus) puis demander des certificats (champ newOrder dans l'exemple ci-dessus), ici (Let's Encrypt) en écrivant à https://acme-v02.api.letsencrypt.org/acme/new-order :

{
  "payload": "ewogICJpZGVudGlmaWVycyI6IFsKICAgIHsKICAgICAgInR5cGUiOiAiZG5zIiwKICAgICAgInZhbHVlIjogInRlc3QtYWNtZS5ib3J0em1leWVyLmZyIgogICAgfQogIF0KfQ",
  "protected": "eyJhbGciOiAiUlMyNTYiLCAidXJsIjogImh0dHBzOi8vYWNtZS12MDIuYXBpLmxldHNlbmNyeXB0Lm9yZy9hY21lL25ldy1vcmRlciIsICJraWQiOiAiaHR0cHM6Ly9hY21lLXYwMi5hcGkubGV0c2VuY3J5cHQub3JnL2FjbWUvYWNjdC81MzE3NzA1MCIsICJub25jZSI6ICJyZXNXTXFtQkJYbVZrZ2JfSnVQU3VEcmlmQzhBbDZrTm1JeDZuNkVwRDFZIn0",
  "signature": "MP9rXTjX4t1Be-y6dhPOP7JE3B401wokydUlG8gJGWqibTM_gydkUph1smtrUZ5W4RXNTEnlmiFwoiU4eHLD-8MzN5a3G668VbgzKd0VN7Y1GxQBGtsj9fShx4VMjSGLzVq1f7bKCbdX3DYn0LaiRDApgNXiMfoEnPLltu5Ud7RBNOaWY8zE0yAV7e3NFlF9Wfaii5Ff9OT1ZCD8LusOHP-gA4VkimQ9ofYr32wZYgsUFu6G--QflP0tjc5eKYMe1cKlgpyKZsDtBurWwvKlj2cU_PUdOZvjXSBbHX18jVlwglzfFnu0xTaDGTTvOuMBfjnWJCWpr-oA7Ih48dL-Jg"
}
    

Eh oui, tout est signé, en JWS (RFC 7515) et base64isé (cf. section 7.4 du RFC). Ici, le décodage Base64 nous dira que la requête était :

{
 {
  "identifiers": [
    {
      "type": "dns",
      "value": "test-acme.bortzmeyer.fr"
    }
  ]
  }
  , {"alg": "RS256", "url":
  "https://acme-v02.api.letsencrypt.org/acme/new-order", "kid":
  "https://acme-v02.api.letsencrypt.org/acme/acct/53177050", "nonce":
  "resWMqmBBXmVkgb_JuPSuDrifC8Al6kNmIx6n6EpD1Y"}
}
    

Donc, une demande de certificat pour test-acme.bortzmeyer.fr.

Les autres opérations possibles avec un serveur ACME sont enregistrées à l'IANA. Par exemple, on peut révoquer un certificat.

La réponse sera :

{
  "status": "pending",
  "expires": "2019-03-19T19:50:41.434669372Z",
  "identifiers": [
    {
      "type": "dns",
      "value": "test-acme.bortzmeyer.fr"
    }
  ],
  "authorizations": [
    "https://acme-v02.api.letsencrypt.org/acme/authz/FVMFaHS_oWjqfR-rWd6eBKMlt1EWfIcf6i7D4wU_swM"
  ],
  "finalize": "https://acme-v02.api.letsencrypt.org/acme/finalize/53177050/352606317"
}      
    

Le client ACME va alors télécharger l'autorisation à l'URL indiqué, récupérant ainsi les défis qu'il devra affronter (section 7.5 du RFC). Une fois qu'il a fait ce qui lui était demandé par le serveur, il utilise l'URL donné dans le champ finalize pour indiquer au serveur que c'est bon, que le serveur peut vérifier. La commande certbot avec l'option -v vous permettra de voir tout ce dialogue.

Le protocole ACME peut être utilisé par d'autres AC que Let's Encrypt. Avec le client dehydrated, il suffira, quand de telles AC seront disponibles, de mettre CA=URL dans le fichier de configuration (l'URL par défaut est https://acme-v02.api.letsencrypt.org/directory). Un exemple d'autre AC utilisant ACME est BuyPass (pas testé).

Mais en quoi consistent exactement les défis, dont j'ai déjà parlé plusieurs fois ? La section 8 les explique. L'idée de base d'un défi ACME est de permettre de prouver qu'on contrôle réellement un identificateur, typiquement un nom de domaine. ACME ne normalise pas un type de défi particulier. Le cadre est ouvert, et de nouveaux défis pourront être ajoutés dans le futur. Le principe est toujours le même : demander au client ACME de faire quelque chose que seul le vrai titulaire de l'identificateur pourrait faire. Un défi, tel qu'envoyé par le serveur ACME, a un type (le plus utilisé aujourd'hui, est de loin, est le défi http-01), un état (en attente ou bien, au contraire, validé) et un texte d'erreur, au cas où la validation ait échoué. Plusieurs défis, comme http-01 ont également un jeton, un cookie, un texte généré par le serveur, et non prévisible par le client ou par le reste du monde, et qu'il faudra placer quelque part où le serveur pourra le vérifier. Le serveur ACME ne testera que lorsque le client lui aura dit « c'est bon, je suis prêt, j'ai fait tout ce que tu m'as défié de faire ». Le RFC demande également au serveur de réessayer après cinq ou dix secondes, si la vérification ne marche pas du premier coup, au cas où le client ait été trop rapide à se dire prêt.

Le plus connu et le plus utilisé des défis, à l'heure actuelle, est http-01. Le client ACME doit configurer un serveur HTTP où une page (oui, je sais, le terme correct est « ressource ») a comme nom le contenu du jeton. Le serveur ACME va devenir client HTTP pour récupérer cette page et, s'il y arrive, cela prouvera que le client contrôlait bien le nom de domaine qu'il avait indiqué. De manière surprenante, et qui déroute beaucoup de débutants, le défi se fait bien sur HTTP et pas HTTPS, parce que beaucoup d'hébergements Web partagés ne donnent pas suffisamment de contrôle à l'hébergé.

Le jeton est une chaîne de caractères utilisant le jeu de caractères de Base64, pour passer partout. Voici un exemple de défi HTTP envoyé par le serveur :

{
  "identifier": {
    "type": "dns",
    "value": "test-acme.bortzmeyer.fr"
  },
  "status": "pending",
  "expires": "2019-03-19T19:50:41Z",
  "challenges": [
    {
      "type": "http-01",
      "status": "pending",
      "url": "https://acme-v02.api.letsencrypt.org/acme/challenge/FVMFaHS_oWjqfR-rWd6eBKMlt1EWfIcf6i7D4wU_swM/13574068498",
      "token": "4kpeqw7DVMrY6MI3tw1-tTq9oySN2SeMudaD32IcxNM"
    } ...
    

L'URL qu'utilisera le serveur est http://DOMAINE-DEMANDÉ/.well-known/acme-challenge/JETON (ou, en syntaxe du RFC 6570, http://{domain}/.well-known/acme-challenge/{token}). Comme expliqué plus haut, c'est bien http:// et pas https://. Les URL avec .well-known sont documentés dans le RFC 5785 et acme-challenge est désormais dans le registre.

Imaginons qu'on utilise le serveur HTTP Apache et qu'on veuille répondre à ce défi. Le plus simple est de configurer le serveur ainsi :

      
<VirtualHost *:80>
   Alias /.well-known/acme-challenge /var/lib/dehydrated/acme-challenges
   <Directory /var/lib/dehydrated/acme-challenges>
        Options None
        AllowOverride None
	...

    

Cela indique à Apache que les réponses aux défis seront dans le répertoire /var/lib/dehydrated/acme-challenges, répertoire où le client ACME dehydrated va mettre ses fichiers. Avec le serveur HTTP Nginx, le principe est le même :

server {
    location ^~ /.well-known/acme-challenge {
         alias /var/lib/dehydrated/acme-challenges;
    }
}

Bien sûr, de nombreuses autres solutions sont possibles. Le serveur HTTP peut intégrer le client ACME, par exemple. Autre exemple, le client ACME certbot inclut son propre serveur HTTP, et peut donc répondre aux défis tout seul, sans Apache.

Ensuite, on lance le client ACME, éventuellement en lui spécifiant où il doit écrire la réponse aux défis :

% certbot certonly --webroot -w /usr/share/nginx/html -d MONDOMAINE.eu.org
    

certbot va mettre le certificat généré et signé dans son répertoire, typiquement /etc/letsencrypt/live/MONDOMAINE.eu.org/fullchain.pem. Et on programme son système (par exemple avec cron) pour relancer le client ACME tous les jours (les clients ACME typique vérifient la date d'expiration du certificat, et n'appellent l'AC que si cette date est proche.) Notez bien qu'il est crucial de superviser l'expiration des certificats. On voit fréquemment des sites Web utilisant Let's Encrypt devenir inaccessibles parce que le certificat a été expiré. Beaucoup d'administrateurs système croient que parce que Let's Encrypt est « automatique », il n'y a aucun risque. Mais ce n'est pas vrai : non seulement la commande de renouvellement peut ne pas être exécutée, ou bien mal se passer mais, même si le certificat est bien renouvellé, cela ne garantit pas que le serveur HTTP soit rechargé.

Petite anecdote personnelle : pour le blog que vous êtes en train de lire, cela avait été un peu plus compliqué. En effet, le blog a deux copies, sur deux machines différentes. J'ai donc du rediriger les vérifications ACME sur une seule des deux machines. En Apache :

        ProxyRequests Off
        ProxyPass /.well-known/acme-challenge/ http://MACHINE-DE-RÉFÉRENCE.bortzmeyer.org/.well-known/acme-challenge/
        ProxyPreserveHost On

À noter qu'un serveur HTTP paresseux qui se contenterait de répondre 200 (OK) à chaque requête sous /.well-known/acme-challenge n'arriverait pas à répondre avec succès aux défis HTTP. En effet, le fichier doit non seulement exister mais également contenir une chaîne de caractères faite à partir d'éléments fournis par le serveur ACME (cf. section 8.3).

Un autre type de défi répandu est le défi dns-01, où le client doit mettre dans le DNS un enregistrement TXT _acme-challenge.DOMAINE-DEMANDÉ contenant le jeton. Cela nécessite donc un serveur DNS faisant autorité qui permette les mises à jour dynamiques, via le RFC 2136 ou bien via une API. Notez que le RFC recommande (section 10.2) que l'AC fasse ses requêtes DNS via un résolveur qui valide avec DNSSEC. (Le serveur ACME ne demande pas directement aux serveurs faisant autorité, il passe par un résolveur. Attention donc à la mémorisation par les résolveurs des réponses, jusqu'au TTL.)

On peut utiliser le défi DNS avec des jokers (pour avoir un certificat pour *.MONDOMAINE.fr) mais c'est un peu plus compliqué (section 7.1.3 si vous voulez vraiment les détails).

D'autres types de défis pourront être ajouté dans le futur. Un registre IANA en garde la liste. Notez que des types de défis peuvent également être supprimés comme tls-sni-01 et tls-sni-02, jugés à l'usage pas assez sûrs.

Le but de ce RFC est la sécurité, donc toute faiblesse d'ACME dans ce domaine serait grave. La section 10 du RFC se penche donc sur la question. Elle rappelle les deux objectifs de sécurité essentiels :

  • Seul·e l·e·a vrai·e titulaire d'un identificateur (le nom de domaine) peut avoir une autorisation pour un certificat pour cet identificateur,
  • Une fois l'autorisation donnée, elle ne peut pas être utilisée par un autre compte.

Le RFC 3552 décrit le modèle de menace typique de l'Internet. ACME a deux canaux de communication, le canal ACME proprement dit, utilisant HTTPS, et le canal de validation, par lequel se vérifient les réponses aux défis. ACME doit pouvoir résister à des attaques passives et actives sur ces deux canaux.

ACME n'est qu'un protocole, il reçoit des demandes, envoie des requêtes, traite des réponses, mais il ne sait pas ce qui se passe à l'intérieur des machines. Les défis, par exemple, peuvent être inutiles si la machine testée est mal gérée (section 10.2). Si, par exemple, le serveur HTTP est sur un serveur avec plusieurs utilisateurs, et où tout utilisateur peut bricoler la configuration HTTP, ou bien écrire dans le répertoire .well-known, alors tout utilisateur sur ce serveur pourra avoir un certificat. Idem évidemment si le serveur est piraté. Et, si on sous-traite le serveur de son organisation à l'extérieur, le sous-traitant peut également faire ce qu'il veut et obtenir des certificats pour son client (« il n'y a pas de cloud, il y a juste l'ordinateur de quelqu'un d'autre »).

ACME permet d'obtenir des certificats DV et ceux-ci dépendent évidemment des noms de domaine et du DNS. Un attaquant qui peut faire une attaque Kaminsky, par exemple, peut envoyer les requêtes du serveur ACME chez lui. Plus simple, même si le RFC n'en parle guère (il se focalise sur les attaques DNS, pas sur celles portant sur les noms de domaine), un attaquant qui détourne le nom de domaine, comme vu fin 2018 au Moyen-Orient, peut évidemment obtenir les certificats qu'il veut, contrairement à la légende répandue comme quoi TLS protègerait des détournements.

Comment se protéger contre ces attaques ? Le RFC recommande d'utiliser un résolveur DNS validant (vérifiant les signatures DNSSEC) ce que peu d'AC font (Let's Encrypt est une exception), de questionner le DNS depuis plusieurs points de mesure, pour limiter l'efficacité d'attaques contre le routage (cf. celle contre MyEtherWallet en avril 2018), et pourquoi pas d'utiliser TCP plutôt qu'UDP pour les requêtes DNS (ce qui présente l'avantage supplémentaire de priver de certificat les domaines dont les serveurs de noms sont assez stupides pour bloquer TCP). Voir aussi la section 11.2, qui revient sur ces conseils pratiques. Par exemple, une AC ne doit évidemment pas utiliser le résolveur DNS de son opérateur Internet, encore moins un résolveur public.

ACME est un protocole, pas une politique. L'AC reste maitresse de sa poltique d'émission des certificats. ACME ne décrit donc pas les autres vérifications qu'une AC pourrait avoir envie de faire :

  • Acceptation par le client d'un contrat,
  • Restrictions supplémentaires sur le nom de domaine,
  • Autorisation ou pas des jokers dans le nom demandé,
  • Liste noire de noms considérés comme sensibles, par exemple parce désignant telle ou telle marque puissante,
  • Tests avec la PSL,
  • Tests techniques sur la cryptographie (par exemple rejeter les clés pas assez fortes, ou bien utilisant des algorithmes vulnérables),
  • Présence d'un enregistrement CAA (RFC 6844).

Les certificats DV (ceux faits avec ACME) sont sans doute moins fiables que les EV (les DV n'ont qu'une vérification automatique, avec peu de sécurité puisque, par exemple, DNSSEC n'est pas obligatoire) et il est donc prudent de limiter leur durée de validité. Let's Encrypt fait ainsi des certificats à courte durée de vie, seulement trois mois, mais ce n'est pas trop grave en pratique, puisque le renouvellement peut être complètement automatisé.

Quels sont les mises en œuvre disponibles d'ACME ? Comme le RFC est publié longtemps après les premiers déploiements, il y en a déjà pas mal. Let's Encrypt maintient une liste de clients. Personnellement, j'ai pratiqué certbot et dehydrated mais il en existe d'autres, comme acme-tiny, qui semble simple et compréhensible. Un avantage que je trouve à dehydrated est qu'il est bien plus simple de garde sa clé lors des renouvellements, par exemple pour DANE : il suffit de mettre PRIVATE_KEY_RENEW="no" dans le fichier de configuration. En revanche, dehydrated est à la fois pas assez et trop bavard. Pas assez car il n'a pas d'option permettant de voir la totalité du dialogue en JSON avec le serveur (contrairement à certbot) et trop car il affiche des messages même quand il n'a rien fait (parce que le certificat était encore valide pour assez longtemps). Pas moyen de le faire taire, et rediriger la sortie standard ne marche pas car on veut savoir quand il y a eu renouvellement effectif.

On dispose également de bibliothèques permettant au programmeur ou à la programmeuse de développer plus facilement un client ACME. (Par exemple Protocol::ACME (encore que j'ai l'impression qu'il n'est plus maintenu, un programmeur Perl disponible pour évaluer ce qui existe ?). Pour les programmeures Python, il y a le module acme qui est celui utilisé par le client certbot, mais qui est aussi distribué indépendamment. En Go, il y a LeGo. Mais on peut aussi mettre le client ACME dans le serveur HTTP, comme le permet Apache

Et les serveurs ACME ? Évidemment, peu de gens monteront une AC mais, si vous voulez le faire, le serveur de Let's Encrypt, Boulder, est en logiciel libre.

Notez que ce RFC ne parle que de la validation de noms de domaines mais ACME pourra, dans le futur, être utilisé pour valider la « possession » d'une adresse IP, ou d'autres identifiants.

Et si vous voulez un résumé rapide d'ACME par ses auteurs, allez lire cet article sur le blog de l'IETF.


Téléchargez le RFC 8555


L'article seul

Deux « bots » de plus pour le fédivers

Première rédaction de cet article le 7 avril 2019


Je viens de mettre en service deux « bots », sur le réseau social « fédivers ». Ce court article est là pour documenter les techniques utilisées, si vous voulez vous-même réaliser un tel « agent logiciel autonome » sur ce réseau.

Un « bot », dans le contexte des réseaux sociaux, est simplement un logiciel qui, sans intervention humaine, va écrire sur le réseau social, parfois en réponse à des demandes des humains. C'est un concept très ancien (il y en avait déjà sur IRC) mais je vais me focaliser ici sur des bots participant au fédivers (également écrit fedivers, fediverse, féediverse, etc). J'avais déjà documenté en anglais un bot qui répondait à des requêtes DNS, les deux bots décrits ici en français sont plus simples, ils n'écoutent pas les messages, ils ne font qu'écrire. Cela permet de ne pas avoir un démon tournant en permanence (et qu'il faut superviser, redémarrer, etc) mais juste de les lancer de temps en temps depuis cron : ils écrivent puis retournent se coucher.

Ces deux bots sont balladependus, qui écrit le texte du poème « La ballade des pendus », de François Villon, et voirapp, qui récite la chanson « Voir » de Jacques Brel. À quoi ça sert d'envoyer des poèmes sur le fédivers ? À rien, mais plusieurs bots le font déjà, comme LInternationale qui nous réveille avec les paroles de l'Internationale (une version préliminaire, pas les paroles les plus connues).

Les deux bots sont hébergés par l'instance fédivers botsin.space, spécialisée dans les bots.

Le premier, balladependus, est écrit en shell, le second, voirapp, en Python. Voyons d'abord le premier.

Le code source de balladependus est distribué ici. Il repose sur l'excellent programme madonctl, qui permet d'accéder au fédivers depuis la ligne de commande. madonctl utilise l'API du serveur Mastodon (botsin.space est un Mastodon). Normalement, Pleroma gère également cette API et donc madonctl devrait marcher avec Pleroma, mais je n'ai jamais essayé. Autrement, que fait le programme ? En commençant du début :

  • Il récupère sur la ligne de commande ses deux arguments, le fichier contenant le poème, et le nom du fichier de configuration (le même programme peut être utilisé pour plusieurs poèmes et plusieurs comptes).
  • Il lit un fichier de configuration, contenant les paramètres spécifiques à un compte fédivers, notamment le jeton d'autorisation ; ce fichier a été créé avec madonctl config dump -i YOURINSTANCE -L YOURID -P YOURPASSWORD > ~/.config/madonctl/YOURCONFIG.yml. Il faut donc s'être créé un compte sur l'instance préalablement (en n'oubliant pas de cocher, dans le profil, la case « Je suis un bot »).
  • Il lit ensuite un fichier d'état ($checkpoint) qui indique à quelle strophe du poème on en est. Le logiciel ne tourne pas en permanence et c'est donc ce fichier d'état qui lui permettra de ne pas partir de zéro à chaque fois. Le même fichier contient un identificateur du pouète (message sur le fédivers) précédemment envoyé, de façon à organiser toutes les strophes du poème en un seul fil.
  • Ensuite, il lit le fichier contenant le poème, une ligne vide indique le passage au pouète suivant. (Le fichier a été créé manuellement avec un éditeur.)
  • Le bot attend ensuite un nombre aléatoire de secondes, pour mettre un peu de variété dans les messages. Notez qu'il n'existe pas de moyen standard en shell de faire des nombres aléatoires.
  • Enfin, on écrit le pouète avec madonctl, qui prend en argument le fichier de configuration de ce compte (paramètre --config) et, sauf pour la première strophe, l'identificateur du pouète précédent (paramètre --in-reply-to). On note en retour l'identificateur (Status ID) du pouète.
  • Enfin, il n'y a plus qu'à écrire identificateur du pouète et numéro de la strophe dans le fichier d'état.

Le programme est lancé automatiquement par cron, envoyant une strophe toutes les trois heures :

    
# Ballade des pendus
35 0,3,6,9,12,15,18,21 * * * ballade-pendus.sh ballade-pendus.txt ballade

Et l'autre programme, celui derrière voirapp ? Il est écrit en Python, pour le plaisir de la variété. Il dépend de la bibliothèque Mastodon.py. Il est plus court que la version shell, en partie parce que Python offre des possibilités supérieures, mais également parce qu'il lui manque certaines fonctions. Par exemple, il est moins générique, le nom du poème est en dur dans le code. Le source est également disponible.

Comment fonctionne ce programme ? Il ressemble beaucoup au précédent. Il ouvre le fichier d'état (CHECKPOINT), y lit l'identificateur du pouète précédent et le numéro de la strophe. Il lit le fichier contenant la chanson (même formatage que pour le script en shell), et attend une durée aléatoire avant d'envoyer, et enfin écrit le nouveau fichier d'état. Pour envoyer, il se connecte à une instance Mastodon (mastodon = Mastodon(...)) et envoie le pouète via mastodon.status_post(...). Avant cela, il aura fallu s'enregistrer auprès de l'instance, pour fabriquer les fichiers contenant les lettres de créance (voirapp_clientcred.secret et voirapp_usercred.secret). Cet enregistrement peut également se faire en Python (une fois suffit, les lettres de créance seront enregistrées) :

Mastodon.create_app(
     'voirapp',
     api_base_url = 'https://botsin.space/',
     to_file = 'voirapp_clientcred.secret'
)
mastodon = Mastodon(
    client_id = 'voirapp_clientcred.secret',
    api_base_url = 'https://botsin.space/'
)
mastodon.log_in(
    USER,
    PASSWORD,
    to_file = 'voirapp_usercred.secret'
)
   

Le programme est ensuite lancé depuis cron, comme le précédent.


L'article seul

Exposé sur DoH (DNS sur HTTPS) aux JDLL

Première rédaction de cet article le 7 avril 2019
Dernière mise à jour le 9 avril 2019


Comme chaque année, les Journées du Logiciel Libre à Lyon ont été passionnantes et très bien organisées. J'y ai fait un petit exposé sur une technique qui a fait un peu de bruit récemment, DoH (DNS sur HTTPS).

DoH a été normalisé dans le RFC 8484. Cette technique permet de chiffrer le trafic DNS, afin d'échapper à la surveillance et à la modification du trafic. (DNSSEC permet de détecter ces modifications mais pas d'y échapper.) Elle suscite donc les réactions de ceux qui avaient pris l'habitude de regarder le trafic DNS, voire de changer les réponses.

Mais le déploiement de DoH soulève une autre question. Un acteur important, Mozilla, a choisi de configurer DoH par défaut dans son navigateur Firefox (ce qui se défend) mais également de désigner comme résolveur par défaut celui d'un GAFA, Cloudflare. Question vie privée, passer d'une surveillance et d'une censure par le FAI à une surveillance et peut-être demain une censure, par une entreprise capitaliste états-unienne n'est pas forcément un progrès… Il est donc important et urgent que des résolveurs DoH vraiment libres soient déployés par des acteurs non-GAFA, par exemple des chatons.

Les supports de mon exposé sont disponibles ici (ainsi que leur source). La conférence a été filmée et la vidéo est sur PeerTube chez Benzo (cf. son article) et chez GoogleTube.

La démonstration de DoH a été faite avec un serveur DoH écrit en Python lors d'un hackathon à l'IETF, tournant sur https://doh.bortzmeyer.fr/. Attention : non seulement ce serveur DoH est purement expérimental, et toujours en panne, mais en outre il n'offre aucune vie privée, je regarde tout le trafic. Voici par exemple ce qui s'affiche lorsqu'un client DoH a fait une requête pour jdll.org :

INFO: id 0
opcode QUERY
rcode NOERROR
flags RD
;QUESTION
jdll.org. IN A
;ANSWER
;AUTHORITY
;ADDITIONAL
[2019-04-09 18:55:36,513] 10.251.62.29:35552 GET / 2 200 42 870793
    

Le client DoH de test utilisé (développé au même hackathon, utilisait la méthode HTTP GET. curl, lui, utilise POST. La requête curl --doh-url https://doh.bortzmeyer.fr/ https://jdll.org/ provoque :

INFO: id 0
opcode QUERY
rcode NOERROR
flags RD
;QUESTION
jdll.org. IN AAAA
;ANSWER
;AUTHORITY
;ADDITIONAL
INFO: id 0
opcode QUERY
rcode NOERROR
flags RD
;QUESTION
jdll.org. IN A
;ANSWER
;AUTHORITY
;ADDITIONAL
[2019-04-09 19:01:51,750] 82.251.62.29:35610 POST / 2 200 91 8403
[2019-04-09 19:01:51,750] 82.251.62.29:35608 POST / 2 200 42 6703
    

Notez également que curl a fait deux requêtes, A et AAAA. Voici ce qu'affiche curl de son activité :

      
% curl --doh-url https://doh.bortzmeyer.fr/ https://jdll.org/ 
* Hostname 'doh.bortzmeyer.fr' was found in DNS cache
* Connected to doh.bortzmeyer.fr (193.70.85.11) port 443 (#1)
* ALPN, offering h2
* ALPN, offering http/1.1
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=doh.bortzmeyer.fr
*  start date: Apr  5 12:54:32 2019 GMT
*  expire date: Jul  4 12:54:32 2019 GMT
*  subjectAltName: host "doh.bortzmeyer.fr" matched cert's "doh.bortzmeyer.fr"
*  issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x56448a35af30)
> POST / HTTP/2
Host: doh.bortzmeyer.fr
Accept: */*
Content-Type: application/dns-message
Content-Length: 26

* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
< HTTP/2 200 
< content-type: application/dns-message
< content-length: 42
< cache-control: no-cache
< date: Tue, 09 Apr 2019 17:03:48 GMT
< server: hypercorn-h2

...

<!DOCTYPE html>
<html lang="">
<head>
    <meta charset="utf-8" />
    <title>Accueil | JdLL</title>

    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta property="og:image" content="/user/themes/jd-ll/images/favicon.ico"/>
    <meta name="generator" property="og:description" content="GravCMS" />

    

Sur Firefox, il faut configurer DoH dans un onglet about:config. Le mot-clé est TRR pour Trusted Recursive Resolver. On voit ici les réglages disponibles (2 veut dire « utiliser DoH mais se rabattre sur le DNS normal en cas de problème », 3 serait « uniquement DoH » et 0 « pas de DoH du tout ») : firefox-trr.png

Merci aux organisat·eur·rice·s. On peut trouver de jolies photos des JDLL. Merci à Syst et Marne pour leur excellent exposé sur « Le vrai coût écologique de la publicité en ligne ». J'ai modestement contribué à la lutte contre les panneaux de surveillance publicitaire en installant une copie de la page de désinscription. Autre exposé très utile, celui d'Oriane sur « La Fédération FDN et la fibre optique. Enjeux et perspectives de l'Internet associatif en haut débit. » analysant les chances pour un opérateur Internet « alternatif » de pouvoir utiliser la fibre optique des RIP (Réseaux d'initiative publique). L'énorme travail de récolte d'informations fait par la FFDN montre que ce n'est pas gagné


L'article seul

DNS Extended Error reporting at the IETF hackathon

First publication of this article on 25 March 2019


On 23 and 24 March 2019 took place the now traditional hackathon of the IETF. I worked on a mechanism to report more detailed errors for DNS requests.

This IETF meeting was located in Prague (a very common city for IETF meetings). As we now do at each meeting, there is a hackathon the weekend before. This one was the biggest ever, with more than 350 persons coding in the room.

One of the projects (involving four people, Shane Kerr, Ralph Dolmans, Vladimír Čunát and myself) was to implement the "Extended DNS Errors" Internet-Draft. A long-time problem of the DNS is the fact there is little error reporting to the client. Most standardized return codes are rare or useless and one, SERVFAIL (Server Failure), is used to report almost every possible error. Therefore this draft, which adds a EDNS option to be returned by the server, adding to the normal return code:

  • An "info-code", an integer giving details,
  • Optional "extra-text", a human-readable character string,
  • The "retry" bit, indicating to the clients if it makes sense to retry to another server or not.

My choice for the hackathon was to add this extended reporting system to the Knot resolver, with Vladimír Čunát (Shane Kerr worked on dnsdist and Ralph Dolmans on Unbound). Knot is written in C but a part of the extra modules is in Lua.

Adding an extra EDNS option in the reply is quite simple (the real difficulty is after that, don't stop reading!). I choose a code for the option, 65500, from the range dedicated to experimentations:

#define KNOT_EDNS_OPTION_EXTENDED_ERROR 65500
    

Of course, in the future, this definition will be in libknot, the general DNS library of the Knot authoritative server, library which is also used by the Knot resolver.

I then created a new module for Knot (many functions are not done by the core but by modules), extended_error, with the usual data structures (code is available, you'll see it later). Extended errors are defined as:

struct extended_error_t {
	bool valid; /* Do we have something to report? */
	bool retry;
	uint16_t response_code;
	uint16_t info_code;
	const char *extra_text; /* Can be NULL.  Allocated on the kr_request::pool or static. */
};
    

One small issue: serializing such a data structure in the layout decided by the draft (one bit for retry, four for response_code, matching RFC 1035, section 4.1.1, twelve for the info_code), required me to re-learn bit manipulations in C:

      
uint32_t serialize(struct extended_error_t err) {
	uint32_t result = 0;
	result = (u_int32_t)err.retry << 31;
	result = result + ((err.response_code & 0x0000000F) << 12);
	result = result + (err.info_code & 0x00000FFF);
	return(htonl(result));
}

    

(Je sais, ce n'est pas beau d'utiliser les opérateurs arithmétiques comme le plus, pour des opérations sur des bits. Cela a été corrigé par la suite.)

Now, once the module is done (modules/extended_error/), compiled (Knot uses Meson) and ran, we indeed get the new EDNS option in dig output. (We did not develop a client using extended error codes, just used dig or Wireshark to see what the server returned.) But the real difficulty of the project was not here: it is to extract the correct information from the depths of the DNS resolver. On some resolvers (at least on Knot), the place where the error is noticed can be quite far from the place where the answer is built, with its EDNS options. In practice, we had to add data to the request object kr_request, for the extended error information to be carried to the module that emits the extended error code EDNS option. So, the real difficulty is not in the draft, but in knowing and understanding your resolver.

First example, the case where all the authoritative name servers for a zone are down (or reply wrongly). This is in lib/resolve.c after some search in the code to see where the resolver decided it is time to give in:

      
if (qry->ns.score > KR_NS_MAX_SCORE) {
        request->extended_error.valid = true;
        if (kr_zonecut_is_empty(&qry->zone_cut)) {
             request->extended_error.retry = true;
             request->extended_error.response_code = KNOT_RCODE_SERVFAIL;
             request->extended_error.info_code = KNOT_EXTENDED_ERROR_SERVFAIL_NO_AUTHORITY;
             request->extended_error.extra_text = "no NS with an address"; /* Also used when all authoritative nameservers timeout */      

    

Younger C programmers would use the syntax:


request->extended_error = (struct extended_error_t){
             .valid = true,
             .retry = true,
             .response_code = KNOT_RCODE_SERVFAIL,
             .info_code = KNOT_EXTENDED_ERROR_SERVFAIL_NO_AUTHORITY,
             .extra_text = "no NS with an address",
};

    

Another example is with DNSSEC, because DNSSEC is a very important use case for extended errors since it is important to know if the error is local to the resolver, or due to a broken DNS zone. This is in lib/layer/validate.c and, again, the difficulty was not to write the code but to find where to put it:

    

if (ret != 0) {
        if (ret != kr_error(DNSSEC_INVALID_DS_ALGORITHM) &&
            ret != kr_error(EAGAIN)) {
            req->extended_error.valid = true;
            req->extended_error.retry = false;
            req->extended_error.response_code = KNOT_RCODE_SERVFAIL;
            if (vctx.rrs_counters.expired > 0) {
                   req->extended_error.info_code = KNOT_EXTENDED_ERROR_SERVFAIL_DNSSEC_EXPIRED;
                   req->extended_error.extra_text = "DNSSEC expired signatures";
    
    

One last example, using Knot's policy module. "Policy" means the ability to lie, for instance to block domains used in advertising and tracking (or to implement state censorship). Most Knot modules are in Lua. This one is in modules/policy/policy.lua, and it shows that extended error codes are not only useful for SERVFAIL but here for NXDOMAIN, to allow the lying resolver to explain why it lied:


function policy.DENY_MSG(msg) -- TODO: customizable extended error info code
    return function (_, req)
...
          req.extended_error.valid = true
          req.extended_error.retry = true
          req.extended_error.response_code = kres.rcode.NXDOMAIN
          req.extended_error.info_code = 1 -- "Blocked" TODO KNOT_EXTENDED_ERROR_NXDOMAIN_BLOCKED

With this code, we can configure the resolver to load the "extended error" module, and we block a domain, to check the policy module. Here is the configuration (itself a Lua file):

    

modules = {
   'hints', 'nsid', 'extended_error'
   }
...
policy.add(policy.suffix(policy.DENY_MSG("No tracking"), {todname('googleanalytics.com.')}))

Let's try it with dig:


% dig  @::1 A brk.internautique.fr
...
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 15368
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
; OPT=65500: 80 00 20 07 6e 6f 20 4e 53 20 77 69 74 68 20 61 6e 20 61 64 64 72 65 73 73 (".. .no NS with an address")
;; QUESTION SECTION:
;brk.internautique.fr.	IN A
...

   

We get a SERVFAIL, which is expected for this broken zone, plus an extended error code, displayed in hexadecimal by dig. We get the retry bit (such error might be temporary, or it may be server-dependent, for instance because of a local routing problem), and the "info code" 7 ("SERVFAIL Extended DNS Error Code 7 - No Reachable Authority").

Another example, with a zone which has a DNSSEC problem (in that case, deliberately introduced, for testing):

      
% dig  @::1 A expired.caatestsuite-dnssec.com 
...
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 38360
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
; OPT=65500: 00 00 20 02 44 4e 53 53 45 43 20 65 78 70 69 72 65 64 20 73 69 67 6e 61 74 75 72 65 73 (".. .DNSSEC expired signatures")
;; QUESTION SECTION:
;expired.caatestsuite-dnssec.com. IN A
...

    

This time, no "retry" bit (using another resolver won't help) and info code 2, KNOT_EXTENDED_ERROR_SERVFAIL_DNSSEC_EXPIRED.

One last example, showing the effect of the policy declared in the configuration file:

      
% dig  @::1 -p 9053 A googleanalytics.com   
...
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 46242
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 2

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
; OPT=65500: 80 00 30 01 4e 6f 20 74 72 61 63 6b 69 6e 67 ("..0.No tracking")
;; QUESTION SECTION:
;googleanalytics.com.	IN A

;; AUTHORITY SECTION:
googleanalytics.com.	10800 IN SOA googleanalytics.com. nobody.invalid. (
				1          ; serial
				3600       ; refresh (1 hour)
				1200       ; retry (20 minutes)
				604800     ; expire (1 week)
				10800      ; minimum (3 hours)
				)

;; ADDITIONAL SECTION:
explanation.invalid.	10800 IN TXT "No tracking"

    

Note the retry bit (if you don't approve the lie, you may go to another resolver), the forged SOA record, and the extra text which contains the message indicated in the configuration file.

If you want to see the full code, it is on the public site, in Git branch extended_error. A merge has been requested.

Thanks to Vladimír Čunát for a nice collaboration and for answering my (not always clever) questions, to Sara Dickinson for presenting the results, and to the organisers of the hackathon: a useful event!


L'article seul

« Keynote » sur Internet et les droits humains à BreizhCamp

Première rédaction de cet article le 22 mars 2019


Le 21 mars 2019, j'ai eu le plaisir et l'honneur et tout ça de faire la keynote d'ouverture à la conférence de développeurs BreizhCamp à Rennes. Le thème était « Internet et droits humains, il y a vraiment un rapport ? ».

Si vous voulez consulter les transparents, les voici, et vous avez droit également à leur source. La keynote a été filmée et la vidéo devrait donc être disponible un de ces jours, par exemple sur le canal YouTube de BreizhCamp. J'ai un peu parlé de mon livre « Cyberstructure », et pu faire une intéressante séance de dédicace après.

Et Pierre Tibulle a fait une excellente sketchnote de mon exposé : internet-droits-humains-breizhcamp-sketchnote1.jpg

Même chose de la part de Sarah : internet-droits-humains-breizhcamp-sketchnote2.jpg

J'ai également suivi :

  • L'atelier de Nicolas Savois sur le langage de programmation Elixir. Ce n'était pas juste un cours magistral mais également un apprentissage par la pratique, les matériaux de l'atelier sont en ligne. J'ai apprécié cette formule, où on a le temps de pratiquer. Très convaincant, cela donnait envie de faire de l'Elixir. Comme on est en Bretagne, les exemples du formateur utilisaient un module nommé Creperie.
  • Les bricolages d'enfer de Xavier Moulet, qui construit une console de jeu en partant de zéro, avec le fer à souder, et qui termine par sa programmation (« il n'y a pas de système d'exploitation donc ça démarre plus vite »). Voyez la page Web du projet. Les plans étant disponibles, environ cinquante consoles de ce modèle ont été construites par des passionnés. « La gestion de la mémoire est simple : la mémoire est là, on l'utilise. »
  • L'intéressant exposé de Marc Audefroy et Éric Vergne sur le projet humoristique de créer un TLD .breizhcamp. Évidemment, il s'agissait d'une plaisanterie, mais le but était d'introduire le monde des noms de domaines (premier exemple, crepe-saucisse.bzh…), et la création de nouveaux TLD par l'ICANN. Environ 300 000 € pour votre TLD, selon l'estimation des orateurs (le dépôt initial n'est qu'une partie des frais). C'est bien plus cher s'il y a plusieurs candidatures et qu'il faut faire des enchères : 6,7 M$ pour .tech, 19 M$ pour .blog, 25 M$ pour .app, 41 M$ pour .shop et 135 M$ pour .web.
  • L'exposé d'Antoine Cailly sur Scuttlebutt. Le monde des réseaux sociaux décentralisés est bouillonnant, avec plein de nouveautés tout le temps. Dans Scuttlebutt, l'identité est une clé cryptographique. Et tous les messages sont signés. Pas très convivial mais sûr. Les données sont stockées sur sa machine et sur les machines des relations. Pour trouver un correspondant à partir de sa clé publique, on utilise des machines spéciales, les « pubs ». Si elles sont injoignables, Scuttlebutt peut encore fonctionner en échangeant les données sur le réseau local, ou même via une clé USB.
  • Les exposés avec démonstration à vif, ce qui est toujours courageux, de Jérôme Marchand sur le système de vérification d'identité Keycloak et de Sébastien Lecacheur sur le processeur JSON jq (au passage, j'ai fait un article sur ce logiciel). Avec comme exemple un gros JSON décrivant tous les personnages de Star Wars. La démo de group_by permet de voir qu'il y a beaucoup plus d'hommes que de femmes.
  • J'ai dû partir le vendredi matin et je n'ai donc pas pu voir les exposés du dernier jour.

Merci à Marc Audefroy pour m'avoir proposé de faire cette keynote, et merci à toute l'équipe d'organisation qui a fait un énorme travail bénévole. N'hésitez pas à venir à la prochaine édition, tout est très bien organisé ! (Et on a bien mangé.)


L'article seul

RFC 8490: DNS Stateful Operations

Date de publication du RFC : Mars 2019
Auteur(s) du RFC : R. Bellis (ISC), S. Cheshire (Apple), J. Dickinson (Sinodun), S. Dickinson (Sinodun), T. Lemon (Nibbhaya Consulting), T. Pusateri
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 18 mars 2019


Autrefois, le DNS était toujours cité comme exemple d'un protocole sans état. On envoie une requête, on reçoit une réponse, et le client et le serveur oublient aussitôt qu'ils ont échangé, ils ne gardent pas de trace de cette communication. Mais, dans certains cas, maintenir un état sur une durée plus longue qu'un simple échange requête/réponse peut être utile. Ce nouveau RFC propose un mécanisme pour des sessions DNS, le mécanisme DSO (DNS Stateful Operations). Il introduit donc une nouvelle notion dans le DNS, la persistance des sessions.

Ne pas avoir d'état a de nombreux avantages : cela simplifie les programmes, cela augmente les performances considérablement (pas besoin de chercher dans une table l'état actuel d'un dialogue, le contenu de la requête est suffisant pour donner une réponse, on peut répondre à la vitesse de l'éclair) et cela permet de résister aux DoS, qui réussissent souvent lorsqu'elles arrivent à épuiser le système qui dépend d'un état. (C'est pour cela que c'est souvent une mauvaise idée de mettre un pare-feu à état devant un serveur Internet, et c'est même franchement absurde quand il s'agit d'un serveur DNS.) Le DNS « habituel », tournant sur UDP et sans maintenir d'état, doit une partie de son succès à son caractère sans état.

Mais ne pas avoir d'état a aussi des inconvénients : toutes les options, tous les choix doivent être répétés dans chaque requête. Et cela rend impossible de négocier des paramètres entre les deux parties, par exemple dans le cas d'une session cryptographiquement protégée. Bref, dans certains cas, on aimerait bien avoir une vraie session, de durée relativement longue (plusieurs secondes, voire plusieurs minutes). Le DNS a un mécanisme de connexion de longue durée, en utilisant TCP (RFC 7766), et peut utiliser TLS pour sécuriser cette communication (DoT, « DNS over TLS », RFC 7858) mais les requêtes à l'intérieur de cette connexion n'en profitent pas, elles ne savent pas qu'elles sont liées par le fait qu'elles sont dans la même connexion. D'où ce nouveau système.

Le principe de DSO (DNS Stateful Operations) est de permettre à une requête DNS de créer une session, avec des paramètres communs à toute la session (comme la durée maximale d'inactivité). La session est balisée par des requêtes DNS utilisant l'opcode DSO, de numéro 6 (la création d'un nouvel opcode est très rare). Les paramètres sont encodés en TLV (une nouveauté dans le monde DNS ; les traditionnels Query count et Answer count, avec les sections correspondantes, ne sont pas utilisés). La longueur du message DSO est indiquée par les deux premiers octets du message. Les messages DSO peuvent solliciter une réponse (même si c'est un simple accusé de réception) ou pas. Cette sollicitation est faite par un Message ID différent de zéro. Si, par contre, le Message ID DNS est à zéro, il s'agit d'un message DSO unidirectionnel (retenez ce terme, il va souvent servir dans ce RFC), qui n'attend pas de réponse. (Rappelez-vous que le Message ID sert à faire correspondre requêtes et réponses DNS. Si on n'attend pas de réponse, pas besoin d'un Message ID. Si par contre le message est bidirectionnel, il doit mettre un Message ID non nul.)

DSO (DNS Stateful Operations, sessions - avec état, donc - pour le DNS) ne s'applique qu'avec certains transports sous-jacents (section 4 du RFC). UDP est évidemment exclu, car il faut maintenir l'ordre des messages, et il faut qu'il y ait une connexion à gérer. Cela peut être TCP (RFC 1035, section 4.2.2 et RFC 7766) ou DoT (DNS sur TLS, RFC 7858). DoH (DNS sur HTTPS, RFC 8484) est par contre exclu car HTTP a ses propres mécanimes de gestion de session. (D'autre part, la section 9.2 décrit les conséquences que cela a pour l'anycast.)

Deux importantes utilisations de DSO sont prévues :

  • Gestion de sessions et des paramètres associés : DSO va permettre de définir des paramètres comme les durées maximales d'inactivité avant qu'on ne coupe la connexion de transport sous-jacente. Dans ce cas, DSO est une alternative au RFC 7828.
  • Abonnements de longue durée à des services comme la découverte (RFC 6763).

La section 5 est le gros du RFC, elle décrit tous les détails du protocole. Pour établir une session DSO, il faut :

  • Établir une connexion avec un protocole comme TCP ; on est alors connecté (on peut envoyer des messages DNS et recevoir des réponses) mais sans session DSO,
  • On envoie une demande DSO,
  • Si le correspondant est d'accord, on reçoit une réponse DSO, et la session est établie, et les paramètres comme la durée d'inactivité maximale sont désormais contrôlés par DSO ; on peut envoyer des messages DSO unidirectionnels (non sollicités, et ne demandant pas de réponse),
  • Si par contre le correspondant refuse DSO, on continue avec une connexion normale.

Si on sait à l'avance que le correspondant gère DSO, on peut se considérer comme en session dès l'établissement de la connexion. Mais, souvent on ne sait pas ou on n'est pas sûr et il faut donc explicitement ouvrir une session. Cela se fait avec un message DSO (un message où l'opcode DNS vaut 6 ; ces opcodes sont décrits dans le RFC 1035, section 4.1.1). L'acceptation prend la forme d'un message DSO avec un Message ID qui correspond et un code de réponse 0 (rcode = NOERROR). Si le code de réponse est autre chose que NOERROR (par exemple 4, NOTIMP, « type de requête inconnu » ou 5, REFUSED, « je connais peut-être DSO mais je n'ai pas envie d'en faire »), c'est que notre correspondant ne peut pas ou ne veut pas établir une session.

Il n'y a pas de message DSO dédié à l'ouverture de session. On envoie un message DSO de n'importe quel type (par exemple Keepalive). Il peut donc arriver que le copain en face connaisse DSO mais pas ce type particulier. Dans ce cas, il va répondre DSOTYPENI (DSO Type Not Implemented, code 11, une nouveauté dans le registre). La session n'est pas établie et le client doit recommencer avec un autre type (comme Keepalive, qui a l'avantage d'être normalisé depuis le début et d'être obligatoire, donc il marchera partout).

Il y a des cas plus gênants : un serveur qui couperait la connexion de transport sous-jacente, ou bien qui ne répondrait pas aux messages DSO. Ce cas risque de se produire si un boitier intermédiaire bogué est sur le trajet. Il peut être alors nécessaire d'adopter des mesures de contournement comme celles qu'utilisaient les résolveurs DNS avec les serveurs ne gérant pas bien EDNS, mesures de contournement qui ont été abandonnées récemment avec le DNS Flag Day.

Si, par contre, tout se passe bien, la session DSO est établie, et des paramètres comme le délai d'inactivité doivent désormais suivre les règles de DSO et plus celles de normes précédentes comme le RFC 7766 (c'est pour cela que notre RFC met à jour le RFC 7766).

La section 5 détaille également le format des messages DSO. Ce sont des messages DNS ordinaires, commençant par le Message ID sur deux octets, avec l'opcode qui vaut DSO (code numérique 6). Les champs qui indiquent le nombre d'enregistrements dans les différentes sections doivent tous être mis à zéro. Les données DSO sont situées après l'en-tête DNS standard, et sont sous forme de TLV. Le logiciel peut donc analyser ces données même s'il ne connait pas un type DSO spécifique. Dans une requête DSO, il y a toujours au moins un TLV, le « TLV primaire », qui indique le type d'opérations. Les autres éventuels TLV (« TLV additionnels ») sont là pour préciser le message. Rappelons qu'il y a deux sortes de messages DSO, les unidirectionnels et les autres. Les unidirectionnels ont le Message ID à zéro et n'ont jamais de réponse. (Avec le Message ID à zéro, on ne saurait de toute façon pas à quelle demande correspond une réponse.)

Chaque TLV comprend trois champs :

  • Le type, sur deux octets (la liste des types possibles figure dans un registre IANA créé par ce RFC),
  • La longueur des données, sur deux octets,
  • Les données.

Notez que la définition de chaque type doit préciser s'il est censé être utilisé en TLV primaire ou additionnel. Pour une réponse, il peut n'y avoir aucun TLV présent.

Toutes les sections « normales » d'un message DNS sont vides, y compris la section additionnelle qu'utilise EDNS (le champ ARCOUNT doit être à zéro). Il ne peut donc pas y avoir d'options EDNS dans un message DSO (pour éviter la confusion qui se produirait si une option EDNS et un message DSO donnaient des valeurs différentes au même service). Si on veut le service équivalent à une option EDNS, il faut créer un nouveau type DSO (section 10.3 du RFC pour les détails) et le faire enregistrer.

Combien de temps durent les sessions DSO ? D'un côté, il faut qu'elles soient aussi longues que possible, pour amortir le coût de créer et de maintenir des sessions sur un grand nombre de requêtes, d'un autre, il ne faut pas gaspiller des ressorces à maintenir une session ouverte si elle ne sert plus à rien. La section 6 du RFC discute cette question. DSO a un délai maximal d'inactivité et, quand le délai est dépassé sans activité, le client DSO est censé couper la connexion. (S'il ne le fait pas, le serveur le fera, après un délai plus long.) Le client a évidemment le droit de couper la session avant l'expiration du délai, s'il sait qu'il n'en aura plus besoin.

Le délai maximal d'inactivité est fixé par les messages DSO de type 1. Deux cas spéciaux : zéro indique qu'on doit fermer la connexion immédiatement après la première requête, et 0xFFFFFFFF indique que la session peut être gardée ouverte aussi longtemps qu'on le souhaite.

DSO permet également de spécifier l'intervalle de génération des messages keepalives, messages envoyés périodiquement uniquement pour que les boitiers de traduction d'adresse gardent leur état et ne suppriment pas une correspondance adresse interne <-> adresse externe en pensant qu'elle ne sert plus. Si on sait qu'il n'y a pas de NAT sur le trajet, on peut mettre un intervalle très élevé. Le client peut aussi se dire « j'ai une adresse RFC 1918, le serveur a une adresse IP publique, il y a donc sans doute un machin NAT sur le trajet, je demande des keepalives fréquents ».

Enfin, le client doit être préparé à ce que le serveur ferme la session à sa guise, parce que le serveur estime que le client exagère (il ne ferme pas la session alors que le délai d'inactivité est dépassé, et qu'il n'envoie pas de requêtes), ou bien parce que le serveur va redémarrer. Normalement, c'est le client DSO qui ferme la session mais, dans certains cas, le serveur peut décider de le faire.

La section 7 du RFC décrit les trois TLV de base qui doivent être présents dans toutes les mises en œuvre de DSO : keepalive, délai avant de réessayer, et remplissage. La section 8.2 indique dans quels cas ils peuvent être utilisés par le client ou par le serveur.

Le TLV keepalive contrôle l'envoi de messages servant uniquement à indiquer que la session est toujours ouverte, afin notamment de rassurer les routeurs NAT. Ce même TLV sert également à indiquer le délai d'inactivité maximal. Comme ce type de TLV est obligatoire, c'est un bon candidat pour le message initial d'ouverture de session (il n'y a pas de message particulier pour cette ouverture : on envoie juste un message ordinaire). Il a le type 1 et comprend deux champs de données, le délai maximal d'inactivité, en millisecondes, sur quatre octets, et l'intervalle d'émission des keepalives, également en millisecondes, et sur quatre octets. Il peut être utilisé comme TLV primaire, et il requiert une réponse, le Message ID doit donc être différent de zéro. La valeur du délai maximal d'inactivité émise par le client est un souhait, la valeur à utiliser est celle qui figure dans la réponse du serveur. Si le client ne la respecte pas par la suite, le serveur aura le droit de fermer la session. Notez qu'EDNS avait déjà un mécanisme équivalent, pour définir une durée d'inactivité maximale dans les connexions TCP, normalisé dans le RFC 7828. Mais les limites d'EDNS, comme le fait que les options EDNS ne s'appliquent normalement qu'au message en cours, rendent cette solution peu satisfaisante. Cet ancien mécanisme ne doit donc pas être utilisé avec DSO, qui dispose, d'un autre système, celui utilisant les valeurs spécifiées par un message portant le TLV Keepalive.

Une fois la durée d'émission des keepalives fixée, les messages de keepalive seront des messages unidirectionnels (pas de réponse) et donc envoyés avec un Message ID nul.

Deuxième type de TLV obligatoire, le délai avant de réessayer de se connecter, qui a le code 2. C'est un message unidirectionnel, envoyé par le serveur pour indiquer qu'il va couper et qu'il ne faut pas réessayer avant la durée indiquée en valeur du TLV.

Et enfin, le troisième type (code 3) qui doit être présent dans toute mise en œuvre de DSO est le remplissage. Le but est d'améliorer la protection de la vie privée en insérant des données bidon dans les messages DNS, pour rendre plus difficile l'analyse des données chiffrées. Il n'a évidemment de sens que si la session sous-jacente est chiffrée, par exemple avec le RFC 7858. Pour la longueur du remplissage à choisir, voir le RFC 8467.

Comme toujours sur l'Internet, une grande partie des problèmes opérationnels viendront des middleboxes. Le RFC rappelle à juste titre que la meilleure solution serait de ne pas avoir de middleboxes mais, comme c'est un idéal lointain, en attendant, il faut se pencher sur ce que font ces fichus boitiers intermédiaires, qui se permettent parfois d'intercepter automatiquement le trafic DNS et de le modifier. Si le boitier gère DSO et répond correctement aux spécifications de ce RFC, tout va bien. Si le boitier ne comprend pas DSO et renvoie un NOTIMP ou équivalent, cela empêche d'utiliser DSO mais, au moins, cela ne viole pas la norme : le client réagira comme si le serveur ne connait pas DSO. Si le boitier ne connait pas le DNS, et n'essaie pas de le comprendre, ça devrait marcher si, bien sûr, il établit bien une connexion et une seule pour chaque connexion entrante (c'est ce que fait un routeur NAT qui ne regarde pas les couches supérieures).

Dès que le boitier ne respecte pas ces règles, on peut prévoir des ennuis, et qui seront très difficiles à déboguer. Par exemple si un répartiteur de charge DNS reçoit des connexions TCP, les ouvre, et envoie chaque requête DNS qu'elles contenaient à un serveur différent, le client DSO va certainement souffrir. Il croira avoir une session alors qu'il n'en est rien.

Autre problème pratique qui se posera peut-être : les optimisations de TCP. Deux d'entre elles ont des chances sérieuses de créer des ennuis, l'algorithme de Nagle et les accusés de réception retardés (on attend un peu de voir si un autre segment arrive, pour pouvoir accuser réception des deux avec un seul paquet, RFC 1122, section 4.2.3.2). Pour les messages DSO bidirectionnels, pas de problème. Pour les unidirectionnels, en revanche, le retard de l'accusé de réception pourra atteindre 200 millisecondes, ce qui est énorme dans un centre de données typique, avec des liens qui peuvent débiter plus d'un gibabit par seconde. L'algorithme de Nagle fera qu'on n'enverra pas de données tout de suite, attendant s'il n'y a pas quelque chose à transmettre et, avec l'accusé de réception retardé, la combinaison des deux retardera sérieusement l'envoi.

Débrayer l'algorithme de Nagle, ou bien les accusés de réception retardés, résoudrait le problème mais ferait perdre d'utiles optimisations. En fait, la seule solution propre serait que les API permettent aux applications de dire à TCP « il n'y aura pas de réponse à ce message, envoie l'accusé de réception tout de suite ».

Enfin, un petit mot sur la sécurité pour finir. DSO nécessite des connexions permanentes et, potentiellement, cela peut consommer pas mal de ressources sur le serveur. Pour se protéger, le serveur a donc parfaitement le droit de limiter le nombre de connexions maximal, et de fermer des sessions quand ça lui chante.

Toujours sur la sécurité, DSO permet des établissements de connexion sans aller-retour, avec TCP Fast Open (RFC 7413) et TLS 1.3 (RFC 8446). C'est très rapide, c'est très bien mais les données envoyées avec le premier paquet (early data) ne sont pas forcément bien sécurisées et la définition de chaque type de TLV doit donc indiquer s'il est sûr ou pas de l'utiliser dans le premier paquet.

Il semble qu'à l'heure actuelle, il n'y a pas encore de mise en œuvre de cette technique DSO.


Téléchargez le RFC 8490


L'article seul

Conférence « Vie privée et Internet : derrière les derniers scandales » à la bibliothèque de Limoges

Première rédaction de cet article le 9 mars 2019


Aujourd'hui, conférence sur la vie privée à Limoges, à la bibliothèque francophone multimédia.

Splendide bibliothèque, pleine de livres dans un cadre exceptionnel. On a envie d'y passer ses journées à lire. Mais je n'étais pas là pour ça mais, dans le cadre du Mois du Logiciel Libre, je venais parler de la vie privée sur l'Internet. Il y a régulièrement des scandales liés à une fuite de données personnelles, ou à une utilisation dégueulasse des données, par exemple dans l'affaire Cambridge Analytica. Qu'est-ce que ces scandales nous apprennent ? Quel est l'état de la protection des données personnelles ? Quand se décidera-t-on enfin à minimiser les données collectées ? Va-t-il falloir brouiller délibérement les données ? (Réponse : oui.)

Voici les transparents utilisés : d'abord une version PDF, vie-privee-bfm-limoges.pdf, puis le source en LaTeX, vie-privee-bfm-limoges.tex. La conférence a été filmée donc il y a des chances que la vidéo apparaisse un jour sur l'Internet.

Merci à Guillaume Lair pour l'organisation de la conférence, et à tou·te·s les libristes qui sont venus au bistrot après. Grâce à vous, la liberté finira par gagner.


L'article seul

Détails techniques sur les récentes attaques contre les noms de domaine

Première rédaction de cet article le 27 février 2019


Au cours du dernier trimestre 2018, mais peut-être depuis plus longtemps, un certain nombre d'attaques contre les noms de domaine ont eu lieu, apparemment toutes perpétrées par le même groupe. Dans un autre article, j'ai essayé d'expliquer à un public assez large ce qu'étaient ces attaques et leurs conséquences. Dans l'article que vous êtes en train de lire, je détaille un certain nombre de points techniques. Au contraire du premier, cet article est fait pour un public de technicien·ne·s.

Quelques avertissements sont sans doute utiles :

  • L'auteur de cet article (moi) ne sait pas tout. Autant que possible, j'ai essayé de ne parler que de ce qui était public, et que chacun pouvait vérifier mais, en sécurité, ça n'est pas toujours possible. Et, évidemment, vous ne trouverez pas ici d'informations confidentielles.
  • Les gens qui savent quelque chose, et qui connaissent le sujet sont presque toujours employés par une organisation qui ne leur permet pas de tout raconter à l'extérieur.
  • Le monde de la cybersécurité est très fermé, les informations ne circulent que dans des cercles restreints. Ce qui est publié n'est souvent que de vagues résumés, parfois délibérement déformés à des fins commerciales ou politiques. C'est une des raisons pour lesquelles la cybersécurité progresse si lentement, et pourquoi les légendes ont la vie dure : le baratin est libre alors que la vérité a les mains liées.

Cet article est basé en grande partie sur les rares articles techniques sérieux publiés sur le sujet (dans l'ordre chronologique) :

  • L'article de Talos, qui fut apparemment le premier, à un moment où l'ampleur de la campagne n'était pas encore évidente,
  • Celui de Fireye (que je trouve peu détaillé, et dont les explications DNS sont confuses),
  • Celui de CrowdStrike qui, sauf erreur, a été le premier à donner des IOC (élements précis qu'on peut vérifier, les adresses IP utilisées, par exemple), IOC que j'utilise par la suite,
  • L'article de Brian Krebs, le plus complet.

Cet article sera malheureusement assez décousu, sautant d'un sujet à l'autre. l'idée est d'expliquer en français quelques points techniques subtils sur ces attaques.

Donc, d'abord, un résumé. La série d'attaques qui a eu lieu au moins d'octobre à décembre 2018 reposait en grande partie sur le détournement de noms de domaine. Le détournement (hijacking, d'ailleurs un collègue me dit que ça peut s'écrire highjacking) de noms de domaine consiste à usurper l'identité d'un titulaire ou d'un autre responsable d'un nom de domaine pour changer les informations associées à un nom. Voici par exemple le panneau de contrôle Web de Gandi : gandi-gestion-dns.png

Ce panneau est protégé par un mot de passe, auquel on peut ajouter un deuxième facteur d'authentification. Si quelqu'un peut mettre la main sur ces mécanismes d'authentification, il peut se faire passer pour le vrai responsable du nom, et changer les informations. On voit que cette attaque n'est pas une attaque DNS, le protocole DNS n'y ayant joué aucun rôle. Il s'agit d'une attaque contre le système d'avitaillement des noms de domaine (leur création et modification). Par contre, elle va avoir des conséquences sur le DNS. Et c'est encore plus vrai si le nom détourné est le nom d'un serveur de noms faisant autorité. On voit également que cette attaque n'était pas de haute technologie, et reposait probablement sur des méthodes de hameçonnage et d'ingénierie sociale classiques.

Les attaques par détournement de nom de domaine sont classiques et anciennes. Sur ce blog, j'avais déjà parlé en détail de celle contre le New York Times en 2013 et de celle contre Wikileaks en 2017. Il y en a eu d'autres commes celles contre Canal + et Météo France en 2016. La nouveauté des attaques de 2018, si nouveauté il y a, est dans leur caractère plus systématique et professionnel, probablement au sein d'un groupe unique. (Ne me demandez pas qui ; je n'en sais rien.)

Je m'aperçois que je m'emballe, j'ai déjà parlé du DNS alors que je voulais garder cela pour plus tard. Le DNS est à la fois une technologie indispensable de l'Internet, et une des plus mal connues. La lecture des articles qui parlent de DNS est souvent déprimante, en raison du nombre d'erreurs. Donc, pour lire la suite de cet article, il vaut mieux être au courant du vocabulaire des noms de domaine et du DNS, tel que compilé dans le RFC 8499. Il est notamment crucial de noter que parler de « serveur DNS » tout court est fortement déconseillé. Il y a les résolveurs et il y a les serveurs faisant autorité et ce sont deux choses très différentes. Dans le RFC 8499, vous allez également devoir réviser les notions de bailliage et de colle.

Après les préliminaires, lançons-nous dans les attaques de 2018. D'abord, peut-on vérifier les faits mentionnés dans les articles cités plus haut, ou bien devons-nous faire une confiance aveugle ? L'article de Crowdstrike ou celui de Krebs donnent des détails techniques précis, qu'on peut vérifier. (Je classe automatiquement les articles qui ne donnent aucun nom, aucune adresse IP, dans la catégorie « pas sérieux ».) Comme ces articles concernent des événements passés, on ne peut pas utiliser les clients DNS comme dig aujourd'hui, il faut faire appel à des outils historiques comme DNSDB, qui ne sont pas toujours accessibles publiquement. Prenons l'exemple du ministère des affaires étrangères égyptien. DNSDB nous montre :

;;  bailiwick: gov.eg.
;;      count: 3
;; first seen: 2018-11-14 18:41:30 -0000
;;  last seen: 2018-11-14 20:05:40 -0000
mail.mfa.gov.eg. IN A 188.166.119.57
    

On y voit que le 14 novembre 2018, et peut-être également avant et après (DNSDB ne voit pas tout le trafic DNS, loin de là), mail.mfa.gov.eg avait comme adresse IP 188.166.119.57, une des adresses listées dans les IOC de CrowdStrike. (L'adresse IP habituelle de ce serveur, avant et après, est 41.191.80.13.) L'adresse IP utilisée par les attaquants est hébergée chez DigitalOcean, ce qu'on peut voir avec whois.

DNSDB permet également de chercher par le contenu. On peut voir ainsi les autres noms pointant (ou ayant pointé, parfois longtemps avant) vers cette adresse :

mail.mfa.gov.eg. IN A 188.166.119.57
sm2.mod.gov.eg. IN A 188.166.119.57
mail.mod.gov.eg. IN A 188.166.119.57
mail.noc.ly. IN A 188.166.119.57
embassy.ly. IN A 188.166.119.57
egypt.embassy.ly. IN A 188.166.119.57
...
    

Si nous faisons ce même exercice de recherche avec une autre adresse trouvée dans la liste de CrowdStrike :

    
ns0.idm.net.lb. IN A 139.59.134.216
sa1.dnsnode.net. IN A 139.59.134.216
fork.sth.dnsnode.net. IN A 139.59.134.216
plinkx.info. IN A 139.59.134.216
...

On trouve de vieilles informations (plinkx.info n'existe plus depuis 2017) mais aussi d'autres noms comme ns0.idm.net.lb, au Liban. Comme son nom l'indique, c'est un serveur DNS, et on voit qu'il fait autorité pour le domaine :

      
% dig @ns0.idm.net.lb NS idm.net.lb 
...
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 54194
;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 4
...
;; ANSWER SECTION:
idm.net.lb.		3600 IN	NS sf.idm.net.lb.
idm.net.lb.		3600 IN	NS ns0.idm.net.lb.
...
;; SERVER: 2a00:1590:3c::2#53(2a00:1590:3c::2)
;; WHEN: Tue Feb 26 20:40:26 CET 2019
;; MSG SIZE  rcvd: 134

    

DNSDB nous indique que cette adresse a changé pendant le moment où l'attaque était à son maximum :

;;  bailiwick: lb.
;;      count: 2
;; first seen: 2018-12-18 15:00:27 -0000
;;  last seen: 2018-12-18 15:00:27 -0000
ns0.idm.net.lb. IN A 139.59.134.216

Cela illustre un point important de cette attaque : elle ne visait pas que des serveurs « finaux » (serveur HTTP ou SMTP) mais aussi des serveurs DNS, afin de pouvoir envoyer de fausses réponses aux requêtes DNS.

Notez aussi la ligne marquée bailiwick (bailliage). L'information mensongère n'était pas dans la zone elle-même, mais dans la zone parente (.lb pour ns0.idm.net.lb). Cela montre que l'attaquant est bien passé par le bureau d'enregistrement et pas par l'hébergeur DNS, puisqu'il a pu modifier les informations au registre « du dessus ».

Et si vous n'avez pas accès à DNSDB ou pas confiance dans leurs résultats ? Vous pouvez essayer aussi avec PassiveDNS.cn, qui nous trouve :

mail.mfa.gov.eg A In rrset
-------
Record times: 2018-10-22 17:27:09 -- 2019-02-26 18:45:45
Count: 807
mail.mfa.gov.eg	A	41.191.80.13

Record times: 2014-08-19 13:08:27 -- 2018-10-22 11:27:47
Count: 1398
mail.mfa.gov.eg	A	41.191.80.12

Record times: 2017-11-21 00:39:59 -- 2018-10-21 10:42:56
Count: 951
mail.mfa.gov.eg	A	41.191.80.12
mail.mfa.gov.eg	A	41.191.80.13
    

Ah, oui, le monde est cruel. Le service chinois de passive DNS a beaucoup moins de points de mesure, et n'a pas vu le court moment du détournement. Même problème avec circl.lu, qui, pour le serveur de noms libanais, voit juste :

{"count": 1724, "origin": "https://www.circl.lu/pdns/", "time_first": 1477641718, "rrtype": "A", "rrname": "ns0.idm.net.lb", "rdata": "194.126.10.18", "time_last": 1538114779}
    

Bref, difficile de se passer de DNSDB.

Si vous avez bien regardé plus haut les noms qui ont pointé vers 139.59.134.216, vous avez peut-être remarqué fork.sth.dnsnode.net. C'est encore un serveur de noms, appartenant à un hébergeur important, Netnod. Cette société a publiquement communiqué à propos de cette attaque. La machine en question est également un serveur de noms, et c'est une nouvelle illustration de l'utilisation de serveurs de noms pour une attaque très indirecte, où le pirate change l'adresse IP du serveur de noms pour ensuite pouvoir répondre ce qu'il veut. fork.sth.dnsnode.net est utilisé par des TLD comme .ps ou .lb (mais aussi par des TLD sans lien avec le Moyen-Orient comme .aq). DNSDB montre au moins deux détournements :

;;  bailiwick: net.
;;      count: 9308
;; first seen: 2018-12-14 12:09:32 -0000
;;  last seen: 2018-12-24 12:17:24 -0000
fork.sth.dnsnode.net. IN A 82.196.11.127

;;  bailiwick: dnsnode.net.
;;      count: 63
;; first seen: 2018-12-24 15:21:49 -0000
;;  last seen: 2018-12-27 19:24:23 -0000
fork.sth.dnsnode.net. IN A 139.59.134.216
    

Outre les adresses IP, l'article de CrowdStrike nous apprend que les attaquants ont également utilisé des noms comme cloudnamedns.com. Si le domaine n'existe plus, on retrouve son nom dans le détournement des services de renseignement jordanien :

;;  bailiwick: gov.jo.
;;      count: 67
;; first seen: 2017-02-07 08:17:10 -0000
;;  last seen: 2017-02-12 23:27:29 -0000
gid.gov.jo. IN NS ns1.cloudnamedns.com.
gid.gov.jo. IN NS ns2.cloudnamedns.com.
    

(Notez la date : c'était bien avant que l'affaire soit publique.) Ce cas illustre le fait que les attaquants ont tantôt changé des adresses IP (enregistrements DNS de type A), tantôt des listes de serveurs de noms (enregistrements DNS de type NS). Dans le cas de gov.eg, on ne trouve pas de trace de changement des NS, alors que, pour gid.gov.jo, on voit ci-dessus le changement de NS. Changer les NS dans la zone parente nécessite d'avoir accès au bureau d'enregistrement. Changer les adresses IP nécessite un accès à l'hébergeur DNS, ou bien au bureau d'enregistrement s'il s'agit d'enregistrements dits de colle. (Notez que l'hébergeur DNS peut être également le bureau d'enregistrement, ou bien être le titulaire lui-même, ou encore être un tiers.)

DNSSEC a souvent été mentionné comme une technique à déployer, voire comme une solution qui aurait empêché cette attaque. Ce sont en fait deux questions distinctes. Oui, DNSSEC, normalisé dans le RFC 4033 et suivants, est une bonne solution, et devrait être déployé partout depuis longtemps. (Vous pouvez voir l'arborescence DNSSEC du domaine de ce blog sur DNSviz.) Mais, comme toutes les techniques de sécurité, DNSSEC ne résout pas tous les problèmes. DNSSEC signe les enregistrements DNS. Un résolveur DNS validant (qui vérifie les signatures) peut alors détecter les enregistrements modifiés et les rejeter. DNSSEC protège, par exemple, contre un serveur secondaire faisant autorité qui serait malhonnête ou piraté. Il protège également contre les attaques de type Kaminsky.

Normalisé depuis longtemps (le RFC 4033 date de quatorze ans) et déployé dans la racine du DNS et dans les TLD importants comme .fr et .com depuis 2009-2011, DNSSEC devrait aujourd'hui être présent partout. Les zones DNS importantes devraient être signées, et les résolveurs devraient valider. Bien sûr, mieux vaut tard que jamais. Si, suite aux attaques du moment, davantage d'organisations déploient DNSSEC, c'est parfait.

Mais DNSSEC aurait-il aidé dans ces cas précis ? DNSSEC, on l'a vu, permet de s'assurer que les données n'ont pas été modifiées entre l'origine (l'endroit où sont gérées les données) et le résolveur validant. Mais si les données sont fausses dès l'origine ? Le bon sens nous dit qu'il ne sert à rien de signer des données fausses. Si l'attaquant a le contrôle de l'origine (par exemple le serveur DNS maître), il peut modifier les données et signer des données mensongères. Ou bien il peut simplement retirer l'enregistrement DS dans la zone parente, indiquant ainsi que la zone n'est pas signée. Pour citer Paul Ebersman, « DNSSEC isn't useless but it solves one specific problem ».

Ça, c'est la théorie, mais la pratique est plus compliquée. D'abord, les attaquants ne sont pas parfaits. Il y a des amateurs, des professionnels, et des professionnels compétents. Et même ces derniers font des erreurs. Lors de détournements de noms signés avec DNSSEC, il a déjà été observé que les attaquants, bien qu'ils ont acquis le pouvoir de changer également les informations DNSSEC, n'y pensent pas toujours. Et même s'ils y pensent, le temps n'est pas sous leur contrôle, ce qui peut rendre DNSSEC efficace, même en cas de piratage d'un registre. L'article de Krebs cité plus haut donne d'ailleurs le témoignage de l'hébergeur PCH, qui explique comment DNSSEC a partiellement empêché l'exploitation par le pirate de ses succès antérieurs. Il faut faire très attention, en sécurité, à ne pas se braquer exclusivement sur des solutions théoriquement parfaites. Ce qu'on cherche à faire, ce n'est pas à rendre impossible toute attaque (c'est irréaliste), mais à gêner le plus possible l'attaquant. La plupart des serrures ne résistent pas longtemps à un cambrioleur professionnel, équipé de matériel de qualité. Mais on ne renonce pas à mettre des serrures pour autant : elles bloquent le cambrioleur amateur, et elles gênent même les plus compétents, ce qui peut les empêcher d'aller jusqu'au bout. Pour citer Paul Ebersman, « we are in a world now where every layer of security we can add is probably a good idea and having a day to notice could be handy ».

Bref, attaques du moment ou pas, ce serait une bonne chose que pousser le déploiement de DNSSEC. Comme DNSSEC consiste en la signature des zones et leur validation, deux catégories d'acteurs doivent agir : les gérants des zones (cela peut être l'hébergeur DNS, ou bien le titulaire de la zone), et les gérants des résolveurs (typiquement le FAI ou le service informatique de votre organisation). Pourquoi n'ont-ils pas encore agi ? Les raisons sont variées, mais c'est l'occasion de rappeler que la sécurité, ce n'est pas juste pousser des cris quand une attaque spectaculaire est révélée. Cela nécessite du temps, et des efforts constants. Une des raisons du déploiement insuffisant est peut-être l'étonnante quantité de nimportequoi qu'on trouve dans les médias au sujet de DNSSEC. Comme quand un article explique que DNS chiffre (non) et « rend les données illisibles » (certainement pas).

Arrivé·es là, mes lecteurices, qui sont très compétent·e·s, se disent probablement : « mais on s'en moque du détournement DNS, tout est protégé par TLS de nos jours, donc le détournement ne servira à rien ». Précisons : ce n'est pas tant TLS qui pourrait permettre de détecter un détournement, mais l'authentification fournie par PKIX/X.509 (ce que les médias appellent « certificat SSL », même si SSL est officiellement abandonné depuis trois ans - RFC 7568 - et que, de toute façon, ces certificats peuvent servir à d'autres usages). Normalement, en cas de détournement DNS, les visiteurs du serveur pirate auraient dû se heurter à un mauvais certificat, et la communication être coupée, non ?

Eh bien non, comme l'ont montré ces attaques. D'abord, il y a des services qui n'utilisent pas TLS ou une technique équivalente (c'est le cas du DNS, malgré le RFC 7858). Ensuite, il n'y a pas que les navigateurs Web. Les autres applications clientes oublient parfois de vérifier les certificats, ou bien ne coupent pas la communication si le certificat est invalide. Mais, surtout, ce qui relativise sérieusement la protection offerte par PKIX, c'est que, si on contrôle un nom de domaine, on peut avoir un certificat. Cela n'est certes pas vrai pour les certificats EV mais les DV, eux, peuvent être obtenus dès qu'on contrôle le domaine.

Et c'est bien ce qu'ont fait les pirates ! On peut le savoir grâce au fait qu'il existe plusieurs journaux stockant les certificats émis, et accessibles publiquement (RFC 6962). Prenons crt.sh pour y accéder, et un domaine égyptien cité plus haut :

;;  bailiwick: gov.eg.
;;      count: 3
;; first seen: 2018-11-14 18:41:30 -0000
;;  last seen: 2018-11-14 20:05:40 -0000
mail.mfa.gov.eg. IN A 188.166.119.57

Pendant cette courte période, l'attaquant a obtenu un certificat via Let's Encrypt, le 03:d9:d3:e5:a6:2c:dc:87:1c:b8:0f:1f:fd:e5:fa:eb:2c:b7. L'attaquant avait donc un certificat parfaitement valable et reconnu par beaucoup de logiciels. TLS, PKIX et X.509 ne protégeaient plus.

Un autre exemple est celui d'un domaine albanais. DNSDB montre le détournement :

;;  bailiwick: asp.gov.al.
;;      count: 8
;; first seen: 2018-11-08 09:49:18 -0000
;;  last seen: 2018-11-08 10:06:17 -0000
mail.asp.gov.al. IN A 199.247.3.191
    

Et l'attaquant a eu un certificat. On notera que, contrairement à ce qui a parfois été écrit, il n'y a pas que Let's Encrypt qui a été utilisé par les pirates, ce dernier certificat venait d'une autre AC, Comodo. Puisqu'on parlait de DNSSEC, on notera que Comodo ne valide pas les domaines à travers un résolveur DNS validant… Pire, Comodo n'a pas révoqué les certificats émis pendant les détournements, alors qu'ils sont valables un an. (Ceux de Let's Encrypt, d'une durée de validité de trois mois, sont pour la plupart expirés.)

Une autre technique qui aurait pu aider est celle du verrouillage. L'idée est de demander au registre de ne pas accepter les modifications (changement des serveurs de noms, par exemple), sans une procédure additionnelle de déverrouillage (envoi de SMS à N contacts, auxquels au moins M d'entre eux doivent répondre, par exemple). La plupart des registres offrent cette possibilité (par exemple .fr), mais elle reste peu utilisée. Notez que vous ne pouvez pas voir, de l'extérieur, si un domaine est ainsi verrouillé. whois ne l'affiche pas, par exemple.

Outre DNSSEC et le verrouillage, un autre outil de sécurité important, mais souvent négligé, est la supervision. On a vu plus haut que les certificats émis étaient publics, et il est donc utile de superviser l'émission de certificats pour ses noms de domaine, pour voir si un méchant n'a pas réussi à en obtenir un.

Dommage, crt.sh n'a apparemment pas d'API mais, comme me le conseille Valentin Robineau, on peut utiliser celle de CertStream. Ici, j'utilise leur bibliothèque Python avec un petit script qui n'affiche que les certificats pour des noms en .fr (le flux complet est évidemment très bavard) :

[2019-02-28T08:35:30] www.ilovemypet.fr (SAN: )
[2019-02-28T08:35:34] www.manaturopatheetmoi.fr (SAN: )
[2019-02-28T08:35:34] cdns.nicolaschoquet.fr (SAN: )
[2019-02-28T08:35:36] bmv-verre.fr (SAN: www.bmv-verre.fr)
[2019-02-28T08:35:36] www.armand-martin-osteo.fr (SAN: )
[2019-02-28T08:35:37] www.chiropracteur-thiais-nabe.fr (SAN: )
[2019-02-28T08:35:37] hekafrance.fr (SAN: www.hekafrance.fr)
[2019-02-28T08:35:50] mail.topocad-tech.fr (SAN: )
[2019-02-28T08:35:53] cherchons-trouvons.fr (SAN: cherchons-trouvons.odazs.com, cpanel.cherchons-trouvons.fr, mail.cherchons-trouvons.fr, webdisk.cherchons-trouvons.fr, webmail.cherchons-trouvons.fr, www.cherchons-trouvons.fr, www.cherchons-trouvons.odazs.com)
    

(Dans la réalité, bien sûr, on ne regarderait que les noms de ses domaines.)

Mais il n'y a pas que les certificats qu'on peut superviser. On peut aussi regarder son domaine avec whois et/ou avec le DNS pour être prévenu immédiatement d'un changement. C'est assez facile à programmer soi-même, pour intégration dans un système de supervision comme Icinga. Pour le DNS, il existe même des services tout faits comme l'excellent DNSspy (si vous en connaissez d'autre, merci de me les signaler).

La supervision ne peut que détecter le détournement, pas l'empêcher. À la base, le problème principal est de suivre les bonnes pratiques de sécurité, ce qui est toujours plus facile à dire qu'à faire. On peut déjà éviter de mettre le mot de passe de l'interface Web du BE sur un Post-It affiché dans l'open space. (Ne riez pas : ça existe.) Au-delà, il faut envisager de durcir tous les mécanismes d'authentification. Lors des débats suivant cette attaque, pas mal de gens ont cité l'authentification à deux facteurs. C'est une bonne idée dans l'absolu mais son déploiement est freiné par la variété des solutions fermées et incompatibles. Si on n'avait à protéger que l'interface du BE ou de l'hébergeur DNS, ce serait simple, mais l'administrateur réseaux typique gère beaucoup de choses et, s'il activait l'authentification à deux facteurs partout, il devrait se trimbaler avec un grand nombre de dispositifs matériels. Il existe bien un protocole ouvert, décrit dans le RFC 6238, mais ce n'est pas celui qui est utilisé par tout le monde. Il ne suffit pas de crier « il faut faire du 2FA ! », il faut aussi accepter de discuter les problèmes pratiques de déploiement.

Quelques lectures qui peuvent vous intéresser, outre les articles techniques sérieux cités au début de cet article :

  • De bons textes, plein de sages avis, sur la sécurisation de vos noms de domaine : le guide des bonnes pratiques de l'ANSSI et le dossier de l'AFNIC sur la même question.
  • Le communiqué de l'ICANN.
  • Un bon communiqué de SIDN, le registre de .nl, décrivant calmement le problème (avec de bons conseils dans l'avant-dernier paragraphe.)
  • Un court communiqué du registre de .com.
  • Pour les gens pressés, Ars Technica a fait un résumé pas trop mauvais.
  • Des semaines après, Talos a publié un rapport avec peu d'informations nouvelles, et des grosses erreurs sur la notion de registre.
  • Beaucoup d'articles sensationnalistes, voire ridicules, ont été publiés. Un exemple est cet article mais il est loin d'être le seul ; méfiez-vous des médias.
  • Beaucoup d'articles contiennent des erreurs, parfois sérieuses. C'est le cas de cet article, qui invente que l'ICANN aurait été « reconnue d'utilité publique » (par qui ???), qui cite une attaque dDoS sans aucun rapport avec l'attaque actuelle, et qui mélange détournement de noms de domaine et attaques par réflexion. De même, cet autre article prétend qu'on ne peut pas utiliser TCP pour le DNS (les auteurs auraient dû lire le RFC 7766), prétend que DNSSEC « introduit de l'aléatoire dans les requêtes » (!!!), ajoute que DNSSEC chiffre (!!!) et finit par ajouter des certificats imaginaires dans DNSSEC. Un autre exemple est cet autre article : contrairement à ce qu'il dit, l'ICANN n'a pas été piratée (et n'a pas signalé un tel piratage, le gestionnaire de mots de passe n'a absolument rien à voir avec ce piratage, utiliser Cisco OpenDNS n'aurait protégé, puisque l'attaque portait sur le domaine lui-même, et la publicité pour le VPN à la fin est non seulement indication de malhonnêteté mais est absurde : utiliser un VPN n'aurait rien changé ici. La médiocrité de l'information que reçoit le lecteur ou la lectrice ordinaire a de quoi inquiéter, car on n'améliorera pas la sécurité de l'Internet sans un minimum de compréhension du problème.
  • En français, plusieurs articles ont présenté une vue plus informée du problème : l'article de Next Inpact, celui du Monde ou cet interview sur France TV info.

L'article seul

Attaques récentes contre les noms de domaine, que se passe-t-il ?

Première rédaction de cet article le 25 février 2019


Le week-end des 23 et 24 février a vu beaucoup d'articles dans les médias à propos d'une campagne d'attaques Internet menées via les noms de domaine. Que s'est-il passé ?

Cet article se veut pédagogique et prévu pour des gens qui ne sont pas des experts en noms de domaine. (Les experts qui veulent plein de détails techniques devront lire un autre article.)

Donc, commençons par un avertissement : la cybersécurité est un domaine compliqué, et qui n'est pas facile à résumer et à vulgariser. Je vais être obligé de simplifier (rappelez-vous que cet article n'est pas pour les experts) tout en restant rigoureux. Il n'est pas possible de résumer ce qu'on sait de ces attaques discutées récemment en un seul paragraphe. Et tout n'a pas encore été découvert, il est possible que des investigations ultérieures nuancent, voire annulent, ce que j'écris ici. D'autre part, un point important de la cybersécurité est que tout n'est pas public, loin de là. Il y a des tas de choses que je ne sais pas, et d'autres dont je ne peux pas forcément parler. Comme le dit l'adage, « ceux qui savent ne parlent pas, ceux qui parlent ne savent pas ». Donc, prudence.

Commençons par les certitudes : au dernier trimestre de l'année 2018, plusieurs attaques informatiques ont eu lieu, en utilisant des méthodes similaires, et visant notamment des objectifs gouvernementaux. On voit déjà qu'il ne s'agit pas du tout d'une attaque en cours, qui aurait commencé le 22 ou le 23 février, mais d'un problème déjà passé. Ces attaques avaient en commun le détournement des noms de domaine. Avant de continuer, il faut donc s'arrêter sur les noms de domaine et sur leur utilité.

Un nom de domaine est un identificateur pour un service ou une machine sur l'Internet. Il se présente sous la forme de chaînes de caractères séparées par des points. Par exemple, www.bortzmeyer.org est un nom de domaine, tout comme brexit.gouv.fr ou réussir-en.fr. Des informations techniques, utiles uniquement pour les machines, sont associées à ces noms. Ces informations sont cruciales pour faire en sorte que vous, utilisateur ordinaire de l'Internet, arriviez bien au bon endroit. Par exemple, si votre banque est accessible en ligne et que vous utilisez le nom de domaine client.mabanque.example, votre ordinateur ou ordiphone va obtenir, en échange de ce nom, les informations dont il a besoin pour se connecter au site Web de la banque. (Il s'agit entre autres de l'adresse IP.) Si, par malheur, ces informations étaient incorrectes, vous n'arriveriez pas sur le site de votre banque mais sur un autre.

Et c'est précisement le cœur de l'attaque qui a fait tant de bruit depuis quelques jours : les pirates informatiques ont réussi à prendre le contrôle d'un certain nombre de noms de domaine, et à y associer d'autres informations techniques. Ainsi, les utilisateurs, croyant se connecter à tel ou tel service, allaient en fait sur un autre. Lorsque le service est un site Web, l'attaquant copiait le site Web original, faisait quelques modifications, et le plaçait sur le serveur qu'il contrôlait. Une telle attaque n'a pas d'équivalent dans le monde physique. Si vous voulez vous rendre à la Tour Eiffel et qu'on vous donne une mauvaise adresse pour ce monument, vous vous rendrez bien compte que vous n'êtes pas au bon endroit. (Des lecteurs érudits de ce blog me font remarquer qu'une attaque très similaire est pourtant montrée dans le film Ocean 11 ou dans la série The Blacklist.) Mais, sur l'Internet, vous ne voyez pas la distance (vous ne savez pas facilement si vous vous connectez à un site Web situé au Maroc ou au Japon) et vous ne voyez pas du premier coup que le site a été copié.

Et il n'y a pas que le Web. Les attaquants avaient également détourné des serveurs de messagerie, ce qui est encore plus facile, car l'utilisateur ne « voit » pas le serveur de messagerie, connexion et échange de messages se font de manière automatique.

Avec le détournement de sites Web, l'attaquant peut capter des informations confidentielles, comme le mot de passe, qu'il pourra ensuite utiliser avec le vrai site Web. Avec le détournement d'un serveur de messagerie, l'attaquant pourra capter du courrier, possiblement confidentiel (rappelez-vous que les attaquants en question visaient surtout des noms de domaine de gouvernements).

Par exemple, l'un des noms de domaine détournés était webmail.finance.gov.lb. C'est l'interface Web du service de courrier électronique au ministère des finances libanais (.lb indique le Liban). Il est normalement connecté par l'opérateur libanais TerraNet. Le 6 novembre 2018 (et peut-être davantage), en essayant de se connecter via ce nom de domaine, on arrivait chez l'hébergeur ukrainien DeltaHost. L'utilisateur qui ne se méfiait pas entrait donc le mot de passe de son compte sur un serveur contrôlé par le pirate.

La force de ce type d'attaques particulier est son caractère indirect. Au lieu de pirater le site Web, ou le serveur de messagerie, probablement bien défendus, l'attaquant pirate les informations qui indiquent comment s'y rendre. La gestion des noms de domaine est souvent le maillon faible de la cybersécurité. Les attaquants appartenant à ce groupe de pirates particulier n'ont pourtant pas innové. Ils n'ont trouvé aucune faille de sécurité nouvelle, ils n'ont pas réalisé une percée technologique. Ils n'ont même pas été les premiers à comprendre l'intérêt des attaques indirectes, via le nom de domaine. Un exemple fameux d'une telle attaque avait été le détournement du nom de domaine du New York Times en 2013. Mais ces attaquants de 2018 ont attaqué un grand nombre de noms de domaine.

Bon, mais si c'est si facile, pourquoi est-ce que tout le monde ne le fait pas ? Pourquoi est-ce que je ne détourne pas le nom de domaine du RN pour pointer vers un site Web servant un contenu anti-raciste ? Bon, d'abord, c'est parce que je suis un citoyen respectueux des lois. Mais il n'y a pas que ça. Pour comprendre, voyons comment fonctionne la gestion de noms de domaine, vue, par exemple, du webmestre. Je vais reprendre un exemple utilisé dans mon livre : « suivons M. Michu, pizzaiolo, qui habite à Soissons et gère un restaurant nommé "Au soleil de Soissons". Il n'a pas de compétence spéciale en informatique mais voudrait un site Web pour sa pizzeria. Il va alors contacter une entreprise locale, mettons "Aisne Web", qui réalise des sites Web. Aisne Web réserve le nom de domaine au-soleil-de-soissons.fr auprès d'un bureau d'enregistrement, qui sert également d'hébergeur des serveurs de noms de domaine. Aisne Web indiquera, via une interface Web, l'adresse IP du serveur Web hébergeant le site et réalisera le contenu qui apparaitra sous forme de pages Web. Dès qu'Aisne Web aura terminé ce site Web, les visiteurs pourront alors se connecter à au-soleil-de-soissons.fr. »

Mais supposons qu'Aisne Web ne soit pas une entreprise très attentive en matière de sécurité. Pour s'authentifier auprès du bureau d'enregistrement de noms de domaine, ils ont choisi le mot de passe « toto12345 ». Un tel mot de passe est facile à deviner, surtout pour un logiciel qui peut faire de nombreux essais sans s'en fatiguer. Même avec un mot de passe plus difficile, peut-être qu'un employé d'Aisne Web est crédule et que, quand quelqu'un prétendant être « un technicien de Microsoft » (ou d'Apple, ou d'Orange…) appelera, l'employé acceptera de communiquer le mot de passe. (C'est ce qu'on nomme l'ingénierie sociale et c'est beaucoup plus efficace qu'on ne le croit.)

Une fois le mot de passe connu, le pirate peut alors se connecter à l'interface Web du bureau d'enregistrement, en se faisant ainsi passer pour l'utilisateur légitime. Il va alors modifier les informations techniques, par exemple l'adresse IP du site Web. Et voilà, en croyant se connecter à la pizzeria, les visiteurs iront sur le site du pirate. Bien sûr, pour une pizzeria, ce n'est pas forcément très grave. Mais des noms de domaine bien plus sensibles peuvent être détournés ainsi. Et ces attaques forment un véritable bruit de fond sur l'Internet. Les attaques comme celles perpétrées dans l'affaire qui fait du bruit en ce moment ne sont ni les premières, ni les seules.

Comme souvent en sécurité, il n'y a pas de solution magique unique et simple à ce problème, et à ces vulnérabilités. Ce n'est pas spécifique à la cybersécurité. Pour d'autres questions de sécurité, on voudrait aussi une solution immédiate et qui résolve tout, et les politiciens sont particulièrement rapides à passer à la télé, après un fait divers, pour réclamer de telles solutions magiques. Mais la sécurité ne marche pas comme cela. Elle nécessite des efforts sur le long terme, faits avec sérieux et constance. Par exemple, un tout premier élément serait de choisir des mots de passe forts (difficiles à deviner) et de ne pas les communiquer à quelqu'un à la voix chaleureuse et qui inspire confiance. Ces mesures simples et peu spectaculaires, l'hygiène numérique, empêcheraient déjà un certain nombre d'attaques.

Comme dit plus haut, on ne sait pas tout sur cette campagne d'attaques. Il y a beaucoup d'incertitudes. Par exemple, quand les détournements ont-ils commencé ? En octobre 2018 ou avant ? Les attaquants ont-ils renoncé après la publication, de novembre 2018 à février 2019, de plusieurs articles détaillant leurs opérations ? Nous ne le savons pas.

Et il y a bien sûr la question de l'attribution. Qui a effectué ces attaques ? Beaucoup des objectifs étaient au Moyen-Orient, ce qui fait qu'on peut spéculer que l'attaquant était impliqué dans un conflit du Moyen-Orient (je ne dis pas le conflit du Moyen-Orient, car il y en a plusieurs, parfois entremêlés). Mais ça fait beaucoup de suspects. La lecture de la BD « Cyberfatale » vous donnera une idée de la difficulté de l'attribution des cyberattaques…

Enfin, si vous vous intéressez aux questions de la cybersécurité, je vous encourage à lire le livre « La face cachée d'Internet ».


L'article seul

RFC 8492: Secure Password Ciphersuites for Transport Layer Security (TLS)

Date de publication du RFC : Février 2019
Auteur(s) du RFC : D. Harkins (HP Enterprise)
Pour information
Première rédaction de cet article le 22 février 2019


Ce nouveau RFC décrit un mécanisme permettant une authentification lors de l'utilisation de TLS sans utiliser de cryptographie à clé publique, mais avec un mot de passe.

Au passage, l'auteur réhabilite la notion de mot de passe, souvent considérée comme une méthode d'authentification dépassée. Il estime que « un mot de passe est plus naturel qu'un certificat » car « depuis l'enfance, nous avons appris la sémantique d'un secret partagé ».

Experts en sécurité, ne jetez pas tout de suite ce RFC à la poubelle. Rassurez-vous, le mot de passe n'est pas utilisé tel quel, mais via un protocole nommé TLS-PWD, dont la principale partie s'appelle Dragonfly. Dragonfly était déjà utilisé dans le RFC 5931.

D'abord, pourquoi ce nouveau mécanisme (section 1 du RFC) ? TLS (RFC 5246) utilise traditionnellement de la cryptographie à clé publique pour l'authentification. La machine qui veut être authentifiée (en général, c'est le serveur, mais le client peut le faire aussi) présente un certificat, contenant la clé publique et diverses métadonnées plus ou moins utiles (date d'expiration, signature d'une AC). Le protocole vérifie ensuite que la machine peut signer des données avec la clé privée correspondante, prouvant ainsi qu'elle connait cette clé privée. Ce mécanisme est bien connu mais, estime le RFC, a quelques défauts. Notamment, obtenir un certificat n'est pas trivial, et certainement bien plus compliqué que de configurer un mot de passe, opération qui est familière (le RFC dit « naturelle », ce qui est exagéré) à beaucoup. La quantité de certificats auto-signés (les plus simples à obtenir) qu'on trouve (surtout sur les MTA) en est la preuve. (Sans compter les autres problèmes comme les certificats expirés, qui montrent bien que l'avitaillement en certificats est un problème non résolu.) Et puis s'authentifier pour obtenir le premier certificat est un problème d'œuf et de poule qu'on pourrait résoudre avec ce nouveau protocole, authentifiant simplement un échange, quitte à obtenir le certificat par la suite, sur le lien sécurisé (méthode décrite dans le RFC 7030). Autre scénario d'usage pour ce nouveau protocole, le cas d'un lecteur qui transmet le PIN à la carte à puce en clair : il serait trop compliqué d'utiliser un certificat dans ce cas, alors qu'une authentification par mot de passe serait plus simple.

Les solutions sans certificat ont des vulnérabilités comme la possibilité d'attaques par dictionnaire. Un attaquant essaie plein de mots de passe possibles (par exemple, le recrutement de Mirai fonctionne ainsi) et tombe forcément juste de temps en temps. Une solution souvent proposée est d'avoir un mot de passe à forte entropie, qui a peu de chances d'être dans les essais effectués par l'attaquant. Par exemple un mot de passe choisi aléatoirement oblige l'attaquant à essayer toutes les possibilités (puisque toutes les combinaisons sont également possibles). Si le mot de passe fait N bits, cela imposera à l'attaquant 2^(N-1) essais en moyenne.

Mais la faiblesse de ce raisonnement est qu'il ne marche que si l'attaquant peut faire autant d'essais qu'il veut, sans conséquences négatives pour lui (par exemple parce qu'il a mis la main sur un fichier de mots de passe condensés, et qu'il peut à loisir tester hors-ligne s'il en trouve un). D'autres solutions sont pourtant possibles. Ainsi, le PIN d'une carte Visa ne fait que quatre chiffres, ce qui est très peu (5 000 essais suffisent, en moyenne) sauf que la carte se bloque au bout de trois essais échoués. (Notez que sur les très anciennes cartes, il était parfois possible de remettre le compteur d'essais à zéro, annulant cette sécurité.) Ce qui compte, ce ne sont pas les 10 000 possibilités théoriques, ce sont les trois essais. Le RFC généralise cette observation : « la résistance à une attaque par dictionnaire doit être une fonction du nombre d'interactions avec un participant honnête, pas une fonction de la quantité de calculs effectués ». En effet, le nombre d'interactions avec le participant honnête ne croîtra guère dans le futur (l'attaquant est détecté avant) alors que la quantité de calculs réalistiquement possibles croîtra à coup sûr. Comme dans le cas du code PIN, il n'est pas forcément nécessaire d'avoir un mot de passe à forte entropie, il faut juste empêcher l'adversaire d'essayer à volonté, et pour cela le forcer à des attaques actives, interagissant réellement avec sa victime. La section 7 du RFC détaille cette analyse, notant que ce protocole peut se contenter de mots de passe relativement « faibles ». Ainsi, note le RFC, un mot de passe de quatre lettres ASCII peut être suffisant (sans les consignes « votre mot de passe doit comporter au moins douze caractères, dont une lettre minuscule, une lettre majuscule, un chiffre, un emoji et un hiéroglyphe ») puisqu'il offre 459 976 possibilités. Un attaquant qui tenterait la force brute devrait essayer des dizaines de milliers de fois, ce qui sera certainement détecté (par exemple par des logiciels du genre de fail2ban, ou par des IDS).

Désolé, mais je ne vais pas vous exposer le protocole Dragonfly. Il dépasse mes maigres connaissances en cryptographie. La section 3 du RFC expose le minimum qu'il faut savoir en cryptographie pour comprendre la suite (vous aurez besoin de réviser la cryptographie sur courbes elliptiques, par exemple via le RFC 6090 et ça vaut aussi la peine de relire le RFC 8422 sur les extensions TLS spécifiques aux courbes elliptiques). La section 3 rappelle aussi qu'il faut saler les mots de passe avant de les stocker, côté serveur, au cas où le fichier des mots de passe se fasse voler (voir aussi la section 7, qui détaille ce risque et ses conséquences). Le résultat se nomme la base. Plus précisement, la base est le résultat de l'application de HMAC-SHA256 à un sel et à la concaténation du nom de l'utilisateur et du mot de passe. Par exemple, si vous voulez le faire avec OpenSSL, que l'utilisateur est "fred" et le mot de passe "barney", avec un sel (tiré aléatoirement) "57ff4d5abdfe2ff3d849fb44848b42f2c41fd995", on fera :

%  echo -n fredbarney | openssl dgst -sha256 -hmac "57ff4d5abdfe2ff3d849fb44848b42f2c41fd995" -binary \
       | openssl enc -base64      
4m9bv5kWK6t3jUFkF8qk96IuixhG+C6CY7NxsOGrlPw=
    

Comme le mot de passe peut inclure de l'Unicode, il doit être traité selon les règles du RFC 8265. Le serveur va stocker le nom de l'utilisateur, le sel et la base.

C'est la base qui est présentée par le client (après que le serveur lui ait envoyé le sel), pas le mot de passe, et le fichier des bases est donc aussi sensible qu'un fichier de mots de passe en clair (cf. section 7).

La section 4 du RFC décrit le protocole. L'échange de clés utilisé, Dragonfly, est décrit dans le RFC 7664. Utiliser Dragonfly en clair serait sûr du point de vue de l'authentification, mais pas du point de vue de la vie privée puisque le nom d'utilisateur passerait en clair. TLS-PWD, le protocole complet (dont Dragonfly n'est qu'une partie), offre un mécanisme pour protéger contre l'écoute de ce nom, une paire de clés cryptographiques étant générée et utilisée juste pour chiffrer ce bout de la session.

Le protocole TLS-PWD nécessite l'utilisation d'extensions TLS (RFC 5246, notamment la section 7.4.1.2). Elles sont au nombre de trois, notamment PWD_protect (protection du nom) et PWD_clear (nom d'utilisateur en clair). Elles figurent désormais dans le registre IANA. Une fois le nom reçu et trouvé dans le fichier côté serveur, le client peut s'authentifier avec le mot de passe (c'est plus compliqué que cela : voir la section 4 pour tous les détails).

Dans TLS, la suite complète des algorithmes utilisés dans une session est indiquée dans une variable nommée cipher suite (RFC 5246, sections 7.4.1.2, 9 et annexe C). Les nouvelles suites permettant l'authentification par mot de passe sont listées dans la section 5 : ce sont TLS_ECCPWD_WITH_AES_128_GCM_SHA256, TLS_ECCPWD_WITH_AES_256_GCM_SHA384, TLS_ECCPWD_WITH_AES_128_CCM_SHA256 et TLS_ECCPWD_WITH_AES_256_CCM_SHA384. Elles sont indiquées dans le registre IANA.

La section 7 du RFC contient de très nombreux détails sur la sécurité du protocole. Elle note par exemple qu'un attaquant qui essaierait tous les mots de passe d'un même utilisateur serait facilement détecté mais qu'un attaquant pourrait aussi essayer un seul mot de passe avec beaucoup d'utilisateurs, échappant ainsi à la détection. Le RFC recommande donc de compter toutes les tentatives de connexion ensemble, quel que soit l'utilisateur. (Cela traite aussi partiellement le cas d'un IDS extérieur, qui ne verrait pas le nom d'utilisateur, celui-ci étant protégé. L'IDS pourrait néanmoins compter les problèmes de connexion et donner l'alarme.) D'autre part, les mesures contre les attaques par dictionnaire (forcer l'attaquant à interagir avec le serveur, et donc à se signaler) ne sont évidemment pas efficaces si un utilisateur a le même mot de passe sur plusieurs serveurs et que l'un est compromis. La consigne d'utiliser des mots de passe différents par service reste donc valable. (Et, même si le RFC n'en parle pas, il ne faut évidemment pas noter ces mots de passe sur un post-it collé sous le clavier. La relativisation de la règle des mots de passe compliqués permet d'utiliser des mots de passe courts et mémorisables, donc plus d'excuses pour noter sur le post-it.) Sinon, les fanas de cryptographie qui voudraient étudier la sécurité du protocole Dragonfly sont invités à lire l'article de Lancrenon, J. et M. Skrobot, « On the Provable Security of the Dragonfly Protocol ».

Une curiosité : ce RFC est apparemment le premier à avoir une section « Droits Humains » (Human Rights Considerations, section 8). Une telle section, analysant les conséquences du protocole décrit dans le RFC sur les droits humains était suggérée (mais non imposée) par le RFC 8280. Mais, en l'occurrence, celle-ci se réduit à une défense des armes à feu, sans trop de rapport avec le sujet du RFC. On note également une vision très personnelle et très états-unienne des droits humains « le premier des droits est celui de se protéger », ce qui ne figure dans aucun des textes fondateurs des droits humains.


Téléchargez le RFC 8492


L'article seul

RIS Live, un flux de messages BGP en temps réel

Première rédaction de cet article le 19 février 2019


Les annonces du protocole de routage BGP sont publiques, comme beaucoup de choses sur l'Internet. Mais si on ne gère pas soi-même un routeur connecté à la DFZ, comment récupère-t-on ces annonces ? Plusieurs systèmes vous donnent accès à ces annonces, mais pas en temps réel. Désormais, grâce à RIS Live, tu peux, toi aussi, internaute ordinaire, accéder à cette information immédiatement.

Quel est l'intérêt de voir ces annonces ? Petit détour pour expliquer ce que fait BGP : l'Internet, et c'est sa principale caractéristique, est d'être un réseau de réseaux. Aucune organisation n'est en charge de l'Internet dans sa globalité. Chacun (entreprise, association, particulier) gère un des réseaux qui, connectés ensemble, constitue l'Internet. Comment, dans ces conditions, un réseau situé en France sait à qui envoyer les paquets lorsqu'un de ses utilisateurs veut écrire en Mongolie ? C'est tout simple (dans le principe) : chaque opérateur réseau prévient ses voisins (ceux à qui il est directement connecté) des adresses IP qu'il gère. Le voisin prévient ensuite son voisin, et ainsi de suite. Au bout d'un moment, l'opérateur français recevra l'information sur les adresses IP de son collègue mongol, et va donc savoir à qui transmettre les paquets, qui suivront un chemin à peu près réciproque (oui, je simplifie…) de celui suivi par les annonces. Ces annonces sont manuelles lorsqu'un petit acteur se connecte à un gros, mais les gros opérateurs utilisent entre eux le protocole BGP, normalisé dans le RFC 4271. En permanence, les opérateurs connectés à la DFZ (et quelques autres) s'échangent ces annonces : « j'ai désormais une route vers 2c0f:fe30::/32 », « je n'ai plus ma route vers 208.65.144.0/24 ». Ces annonces sont les battements de cœur de l'Internet. Notez que BGP n'informe que des nouveautés : il n'a pas d'envoi périodique, contrairement à ce que font certains protocoles de routage intérieurs. Néanmoins, comme il y a toujours quelque chose qui bouge ou qui change dans l'Internet, en pratique, l'activité BGP est importante.

Ces annonces sont traitées automatiquement par les routeurs qui ajoutent les nouvelles routes, retirent les anciennes et décident, au vu des routes disponibles, à quel voisin envoyer les paquets. Mais il y a aussi des humains qui regardent ces annonces. Il y a les opérationnels, les gens qui dans les NOC surveillent le réseau et interviennent en cas de problèmes. (Ils utilisent par exemple des systèmes d'alerte pour savoir si quelqu'un n'a pas annoncé leurs préfixes IP.) Il y a les chercheurs, qui publient d'intéressantes études sur les dynamiques à l'œuvre dans l'Internet. Il y a les étudiants qui veulent apprendre. Et il y a les curieux qui aiment regarder ce qui se passe. Comme exemple des travaux qui résultent de l'observation de BGP, notons par exemple le rapport sur la résilience de l'Internet français, édité par l'ANSSI.

Passons maintenant au sujet principal de cet article, RIS Live. Il s'agit d'un service du RIPE-NCC, s'appuyant sur un réseau de routeurs BGP, le RIS. Les routeurs du RIS ont des sessions BGP avec un grand nombre d'opérateurs et voient donc une grande partie du trafic BGP. (Avec BGP, contrairement à des protocoles comme OSPF, les routeurs ne voient pas tous la même chose, et aucun routeur ne connait tout. Observer BGP nécessite donc plusieurs routeurs, placés à différents endroits de l'Internet et, même dans ce cas, on ne voit pas tout.) Les données récoltées par le RIS sont accessibles via divers moyens comme RIPE stat, mais toujours avec un certain retard.

Au contraire, RIS Live est temps réel. Regardez la page Web, on y voit le trafic actuel, rafraichi en permanence (tant que cette page reste ouverte, votre machine reçoit les informations de RIS Live). ris-live.png

Mais vous n'êtes pas obligé d'utiliser le Web, RIS Live est accessible via une API (la page Web utilise d'ailleurs cette API, via du code JavaScript chargé avec la page). Cette API repose sur WebSocket (RFC 6455) et est bien documentée.

J'ai écrit un petit programme Python d'exemple avec cette API, ris-live.py. Il utilise la bibliothèque websockets pour faire du WebSocket. Utilisons-le pour voir :

% ./ris-live.py
{"type":"ris_message","data":{"timestamp":1550561936.88,"peer":"198.32.176.14","peer_asn":"2914","id":"198.32.176.14-1550561936.88-24139764","host":"rrc14","type":"UPDATE","withdrawals":["140.16.144.0/23"]}}
{"type":"ris_message","data":{"timestamp":1550561936.88,"peer":"2001:504:d::6","peer_asn":"2914","id":"2001:504:d::6-1550561936.88-14277506","host":"rrc14","type":"UPDATE","path":[2914,1299,7473,3758,9911,9890],"community":[[2914,420],[2914,1008],[2914,2000],[2914,3000]],"origin":"igp","med":12,"announcements":[{"next_hop":"2001:504:d::6","prefixes":["2a00:ad87:4600::/48"]},{"next_hop":"fe80::4255:39ff:fe47:5237","prefixes":["2a00:ad87:4600::/48"]}]}}
{"type":"ris_message","data":{"timestamp":1550561936.88,"peer":"2001:504:d::6","peer_asn":"2914","id":"2001:504:d::6-1550561936.88-14277507","host":"rrc14","type":"UPDATE","path":[2914,1299,7473,4804],"community":[[2914,420],[2914,1008],[2914,2000],[2914,3000]],"origin":"incomplete","med":12,"announcements":[{"next_hop":"2001:504:d::6","prefixes":["2405:dc00:35d::/48"]},{"next_hop":"fe80::4255:39ff:fe47:5237","prefixes":["2405:dc00:35d::/48"]}]}}
{"type":"ris_message","data":{"timestamp":1550561936.91,"peer":"27.111.228.6","peer_asn":"18106","id":"27.111.228.6-1550561936.91-103597777","host":"rrc23","type":"UPDATE","path":[18106,6939,37100,24757],"community":[[6939,2000]],"origin":"igp","announcements":[{"next_hop":"27.111.228.6","prefixes":["197.156.81.0/24"]}]}}
    

Je vous avais prévenu qu'il y en avait du trafic BGP, à tout instant ! Les messages de RIS Live sont en JSON. Voyons une annonce complète :

{
  "timestamp": 1550562092.12,         (le moment de l'annonce, le 19
                                      février 2019 à 07:41:32 UTC,
				      comme on peut le voir avec 'date -u --date=@1550562092.12')
  "peer": "2001:7f8:20:101::208:223", (le voisin BGP du routeur RIS)
  "peer_asn": "20764",                (le numéro de système autonome
                                      dudit voisin)
  "host": "rrc13",                    (l'identité du routeur RIS qui a
                                      vu l'annonce)
  "type": "UPDATE",                   
  "path": [                           (le chemin d'AS - Autonomous
                                      System, système autonome - : l'AS d'origine est le 33047)
    20764,
    8359,
    6327,
    16696,
    33047
  ],
  "community": [                       (les communautés BGP attachées
                                       à l'annonce)
    [
      6327,
      1405
    ],
    [
      6327,
      41030
    ]
  ],
  "origin": "igp",
  "announcements": [                   (l'annonce elle-même, pour le
                                        préfixe d'adresses IP 2a03:8160:14::/48)
    {
      "next_hop": "2001:7f8:20:101::208:223",
      "prefixes": [
        "2a03:8160:14::/48"
      ]
    }
  }
}
    

(La notion - cruciale - de système autonome ou AS est expliquée sur Wikipédia. Les communautés BGP sont normalisées dans le RFC 1997.)

RIS Live offre de nombreuses options pour ne pas être noyé sous l'afflux des annonces, et pour ne sélectionner que celles qui vous intéressent. Le programme ris-live.py permet d'en sélectionner certaines. Ici, par exemple, on ne demande que ce qui concerne l'AS 2484 (utilisé par l'AFNIC) :

% ./ris-live.py --path 2484 -v
Trying to connect, to send {"type": "ris_subscribe", "data": {"path": "2484"}}
Connected, {"type": "ris_subscribe", "data": {"path": "2484"}} sent
Trying to receive
Waking up, it is 2019-02-18T17:00:05Z
Waking up, it is 2019-02-18T17:01:05Z
{"type":"ris_message","data":{"timestamp":1550509323.73,"peer":"2001:7f8::514b:0:1","peer_asn":"20811","id":"2001:7f8::514b:0:1-1550509323.73-471074217","host":"rrc12","type":"UPDATE","path":[20811,2484],"origin":"igp","announcements":[{"next_hop":"2001:7f8::9b4:0:1","prefixes":["2001:678:c::/48"]}]}}
Trying to receive
Waking up, it is 2019-02-18T17:02:05Z
...
Waking up, it is 2019-02-18T17:27:05Z
Waking up, it is 2019-02-18T17:28:05Z
{"type":"ris_message","data":{"timestamp":1550510896.29,"peer":"2001:7f8::514b:0:1","peer_asn":"20811","id":"2001:7f8::514b:0:1-1550510896.29-471090283","host":"rrc12","type":"UPDATE","path":[20811,2484],"origin":"igp","announcements":[{"next_hop":"2001:7f8::9b4:0:1","prefixes":["2001:678:c::/48"]}]}}
    

On peut aussi ne demander que les informations d'un seul routeur RIS. Pour avoir la liste de ces routeurs :

 % ./ris-live.py -l
{"type":"ris_rrc_list","data":["rrc00","rrc01","rrc03","rrc04","rrc05","rrc06","rrc07","rrc10","rrc11","rrc12","rrc13","rrc14","rrc15","rrc16","rrc18","rrc19","rrc20","rrc21","rrc22","rrc23","rrc24"]}
    

À ma connaissance, tous ne sont pas sur la DFZ et n'ont donc pas un flux complet, certains sont sur des points d'échange et ne voient que le trafic BGP au point d'échange.

Pour avoir un flux BGP en temps réel, je suppose qu'on peut utiliser l'alternative bgpstream mais je n'ai pas encore testé.


L'article seul

Fiche de lecture : Manuel d'auto-défense contre le harcèlement en ligne (« Dompter les trolls »)

Auteur(s) du livre : Stéphanie de Vanssay
Éditeur : Dunod
978-2100-787944
Publié en 2019
Première rédaction de cet article le 17 février 2019
Dernière mise à jour le 11 mars 2019


La question du harcèlement en ligne est maintenant bien connue et, à juste titre, souvent mise sur le devant de la scène, mais cela ne veut pas dire que ceux et celles qui en parlent en parlent intelligemment. C'est donc une excellente chose que Stéphanie de Vanssay, qui connait très bien le monde du numérique, s'attaque à cette question, dans un très bon livre.

L'auteure sait hélas de quoi elle parle : comme la grande majorité des femmes qui s'expriment publiquement, avec des opinions affirmées, elle a été victime de plusieurs campagnes de harcèlement. (Un exemple est décrit ici.) Je dis bien de harcèlement, pas juste de critiques (qui seraient parfaitement légitimes) de son engagement ou de ses idées politiques, mais des insultes sur son physique, des menaces de viol ou de torture, etc. La publication de son livre ne va évidemment pas faire changer les harceleurs, qui critiquent déjà sur les réseaux sociaux sa « position victimaire » (les victimes qui dénoncent les agressions cherchent toutes à augmenter leur nombre de followers Twitter, c'est bien connu). On notera au passage que le livre sort en même temps que l'affaire de la ligue du LOL qui illustre très bien le fait que le harcèlement n'est pas uniquement le fait de déséquilibrés isolés, mais qu'il est commis en bandes organisées, ayant des objectifs précis (souvent de faire taire les femmes).

Ayant été témoin des déchainements contre Stéphanie de Vanssay, j'ai noté que le point de départ était souvent une question pédagogique. Car l'auteur est enseignante et parle souvent de questions d'éducation. Apparemment, cela ne plait pas à une horde vindicative qui dénonce les « pédagogistes » (et, à leurs yeux, est « pédagogiste » quiconque estime que l'enseignant n'a pas toujours raison et que les méthodes d'enseignement n'ont pas forcément à rester ce qu'elles étaient dans un lycée militaire au 19e siècle). Bref, cette horde est composée en partie d'enseignants et, en tant qu'ex-parent d'élève, je ne peux pas m'empêcher de trouver inquiétant le fait que certaines personnes chargées de l'éducation des enfants soient aussi agressifs en ligne (et, je le souhaite, seulement en ligne). En tout cas, il est sûr que le harcèlement en ligne n'est pas seulement pratiqué par des islamistes et des bas-du-front votant Trump, des bac+quelquechose le font aussi, hélas.

Je l'ai dit au début, la question du harcèlement en ligne est, heureusement, aujourd'hui reconnue comme une question politique importante. Mais cela ne veut pas dire que toutes les réponses suggérées soient bonnes. Ainsi, comme c'est souvent le cas pour les questions de sécurité, le harcèlement en ligne est souvent utilisé comme prétexte pour rogner les libertés. C'est par exemple le cas en France en ce moment avec le projet présidentiel d'interdire l'anonymat en ligne. Ce projet ne tient pas compte du fait qu'il existe déjà des tas de possibilités légales de lutter contre la « haine en ligne » mais qu'ils ne sont pas utilisés par manque de moyens matériels et manque de réelle volonté. On voit aussi des politiciens sans scrupules qui soutiennent la lutte anti-anonymat en s'appuyant sur les actions de la ligue du LOL… alors que les membres de la dite ligue agissaient souvent sous leur nom officiel. Sans compter les gens qui ne comprennent rien au monde de l'Internet et se contentent d'affirmations sommaires comme « il faudrait que Facebook demande une carte d'identité » (comme si Facebook n'avait pas déjà trop de données personnelles).

Mais assez parlé du contexte, parlons du livre de Stéphanie de Vanssay, plutôt. Elle connait très bien le sujet et ne propose donc pas de ces pseudo-solutions répressives et à l'emporte-pièce. D'abord, l'auteure est modeste : il s'agit d'aider les victimes de harcèlement à se défendre, sans prétendre régler tous les cas de harcèlement, notamment les plus graves (comme, par exemple, celui dont avait été victime la journaliste Nadia Daam). Dans ce cas, l'auteure note à juste titre qu'il faut envisager des recours, par exemple à la justice, et elle donne quelques indications pratiques à ce sujet. Mais même le harcèlement moins radical est dur pour les victimes, et peut mener la victime à ne plus s'exprimer publiquement (ce qui est souvent le but des harceleurs). L'auteure rejette l'idée (qui est aussi celle des trolls, et un des leurs arguments de défense favoris) « en ligne, c'est pas grave ».

L'essentiel du livre parle de ce que les victimes peuvent faire elles-mêmes et eux-mêmes. La force du troll ou du harceleur est que la victime se croit impuissante. Stéphanie de Vanssay montre que ce n'est pas complètement le cas, et qu'il existe diverses stratégies pour lutter contre les trolls.

La plus évidente est le fameux « ne nourrissez pas les trolls » (ne leur répondez pas, ignorez-les en espérant que le problème disparaitra de lui-même), conseil souvent donné mais avec lequel l'auteure n'est pas trop d'accord. D'abord, si le troll dit des choses vraiment inacceptables (des propos racistes, par exemple), cela ne doit pas être ignoré mais combattu. Et, dans certains cas, le troll peut être neutralisé par l'humour et la solidarité (des autres participants : l'auteure insiste que la victime doit être consciente qu'elle n'est pas seule). Mais dans certains cas, cette tactique d'ignorer le harceleur peut être préférable. Voir par exemple dans le livre le témoignage de Florence Porcel (le « petit groupe de potes » dont elle parle est la ligue du LOL, pas encore connue publiquement à l'époque de la rédaction du livre). Globalement, l'auteure est prudente : il n'y a pas de méthode magique anti-troll, pas de solution universelle au harcèlement.

Stéphanie de Vanssay tord le cou à pas mal d'idées reçues. Contrairement au discours médiatique dominant, elle fait remarquer que le harcèlement n'est pas apparu avec Facebook (elle cite Usenet, qui avait déjà permis d'observer pas mal de comportements scandaleux). Elle critique également une autre tarte à la crème du discours anti-numérique, la « bulle de filtres » qui ferait qu'en ligne, on ne serait exposé qu'à ce à quoi on croit déjà. L'auteur note au contraire qu'autrefois, quelqu'un qui ne partageait pas les opinions politiques du Figaro ne lisait jamais ce journal alors que, sur l'Internet, en un clic, on peut accéder à un de leurs articles, et on le fait bien plus souvent qu'hors-ligne.

Stéphanie de Vanssay explique aussi que pour protéger les enfants des dangers qui les menacent en ligne, les solutions simplistes souvent assénées ne sont pas idéales. Ne pas leur permettre un accès à l'Internet, solution souvent citée, revient à les boucler à la maison pour les protéger des dangers de la rue. Et cela les rendra encore plus vulnérables quand ils finiront par y accéder.

Peu de mentions des GAFA dans ce livre, à part pour noter que le signalement des trolls aux GAFA a peu d'effets, voire des effets négatifs (le troll chasse en bande, et eux aussi peuvent signaler, ce qui fait que la bureaucratie va fermer le compte de la victime plutôt que celui du harceleur).

Je vous laisse lire le livre pour voir les stratégies de défense que conseille l'auteur, toujours avec nuance et en sachant bien qu'aucune n'est parfaite. Personnellement, je ne suis pas tellement d'accord avec l'approche (revendiquée) « développement personnel », comme si la lutte contre les harceleurs consistait essentiellement à s'améliorer soi-même mais la question est délicate de toute façon : il faut à la fois aider les victimes à se défendre, sans pour autant les culpabiliser si elles n'y arrivent pas. Globalement, je trouve que ce livre se tire bien de cet exercice très difficile, et je souhaite qu'il serve à de nombreuses victimes à être plus fortes.

Et l'habituel instant « déclaration de conflit d'intérêt » : j'ai reçu un exemplaire de ce livre gratuitement, en tant que blogueur.


L'article seul

RFC 8536: The Time Zone Information Format (TZif)

Date de publication du RFC : Février 2019
Auteur(s) du RFC : A. Olson, P. Eggert (UCLA), K. Murchison (FastMail)
Chemin des normes
Première rédaction de cet article le 13 février 2019


Ce nouveau RFC documente un format déjà ancien et largement déployé, TZif, un format de description des fuseaux horaires. Il définit également des types MIME pour ce format, application/tzif et application/tzif-leap.

Ce format existe depuis bien trente ans (et a pas mal évolué pendant ce temps) mais n'avait apparemment jamais fait l'objet d'une normalisation formelle. La connaissance des fuseaux horaires est indispensable à toute application qui va manipuler des dates, par exemple un agenda. Un fuseau horaire se définit par un décalage par rapport à UTC, les informations sur l'heure d'été, des abréviations pour désigner ce fuseau (comme CET pour l'heure de l'Europe dite « centrale ») et peut-être également des informations sur les secondes intercalaires. Le format iCalendar du RFC 5545 est un exemple de format décrivant les fuseaux horaires. TZif, qui fait l'objet de ce RFC, en est un autre. Contrairement à iCalendar, c'est un format binaire.

TZif vient à l'origine du monde Unix et est apparu dans les années 1980, quand le développement de l'Internet, qui connecte des machines situées dans des fuseaux horaires différents, a nécessité que les machines aient une meilleure compréhension de la date et de l'heure. Un exemple de source faisant autorité sur les fuseaux horaires est la base de l'IANA décrite dans le RFC 6557 et dont l'usage est documenté à l'IANA.

La section 2 de notre RFC décrit la terminologie du domaine :

  • Temps Universel Coordonné (UTC est le sigle officiel) : la base du temps légal. Par exemple, en hiver, la France métropolitaine est en UTC + 1. (GMT n'est utilisé que par les nostalgiques de l'Empire britannique.)
  • Heure d'été (le terme français est incorrect, l'anglais DST - Daylight Saving Time est plus exact) : le décalage ajouté ou retiré à certaines périodes, pour que les activités humaines, et donc la consommation d'énergie, se fassent à des moments plus appropriés (cette idée est responsable d'une grande partie de la complexité des fuseaux horaires).
  • Temps Atomique International (TAI) : contrairement à UTC, qui suit à peu près le soleil, TAI est déconnecté des phénomènes astronomiques. Cela lui donne des propriétés intéressantes, comme la prédictibilité (alors qu'on ne peut pas savoir à l'avance quelle sera l'heure UTC dans un milliard de secondes) et la monotonie (jamais de sauts, jamais de retour en arrière, ce qui peut arriver à UTC). Cela en fait un bon mécanisme pour les ordinateurs, mais moins bon pour les humains qui veulent organiser un pique-nique. Actuellement, il y a 37 secondes de décalage entre TAI et UTC.
  • Secondes intercalaires : secondes ajoutées de temps en temps à UTC pour compenser les variations de la rotation de la Terre.
  • Correction des secondes intercalaires : TAI - UTC - 10 (lisez le RFC pour savoir pourquoi 10). Actuellement 27 secondes.
  • Heure locale : l'heure légale en un endroit donné. La différence avec UTC peut varier selon la période de l'année, en raison de l'heure d'été. En anglais, on dit aussi souvent « le temps au mur » (wall time) par référence à une horloge accrochée au mur. Quand on demande l'heure à M. Toutlemonde, il donne cette heure locale, jamais UTC ou TAI ou le temps Unix.
  • Epoch : le point à partir duquel on compte le temps. Pour Posix, c'est le 1 janvier 1970 à 00h00 UTC.
  • Temps standard : la date et heure « de base » d'un fuseau horaire, sans tenir compte de l'heure d'été. En France métropolitaine, c'est UTC+1.
  • Base de données sur les fuseaux horaires : l'ensemble des informations sur les fuseaux horaires (cf. par exemple RFC 7808). Le format décrit dans ce RFC est un des formats possibles pour une telle base de données.
  • Temps universel : depuis 1960, c'est équivalent à UTC, mais le RFC préfère utiliser UT.
  • Temps Unix : c'est ce qui est renvoyé par la fonction time(), à savoir le nombre de secondes depuis l'epoch, donc depuis le 1 janvier 1970. Il ne tient pas compte des secondes intercalaires, donc il existe aussi un « temps Unix avec secondes intercalaires » (avertissement : tout ce qui touche au temps et aux calendriers est compliqué.) C'est ce dernier qui est utilisé dans le format TZif, pour indiquer les dates et heures des moments où se fait une transition entre heure d'hiver et heure d'été.

La section 3 de notre RFC décrit le format lui-même. Un fichier TZif est composé d'un en-tête (taille fixe de 44 octets) indiquant entre autres le numéro de version de TZif. La version actuelle est 3. Ensuite, on trouve les données. Dans la version 1 de TZif, le bloc de données indiquait les dates de début et de fin des passages à l'heure d'été sur 32 bits, ce qui les limitait aux dates situées entre 1901 et 2038. Les versions ultérieures de TZif sont passées à 64 bits, ce qui permet de tenir environ 292 milliards d'années mais le bloc de données de la version 1 reste présent, au cas où il traine encore des logiciels ne comprenant que la version 1. Notez que ces 64 bits permettent de représenter des dates antérieures au Big Bang, mais certains logiciels ont du mal avec des valeurs situées trop loin dans le passé.

Les versions 2 et 3 ont un second en-tête de 44 octets, et un bloc de données à elles. Les vieux logiciels arrêtent la lecture après le premier bloc de données et ne sont donc normalement pas gênés par cette en-tête et ce bloc supplémentaires. Les logiciels récents peuvent sauter le bloc de données de la version 1, qui ne les intéresse a priori pas (voir section 4 et annexe A). C'est au créateur du fichier de vérifier que les blocs de données destinés aux différentes versions sont raisonnablement synchrones, en tout cas pour les dates antérieures à 2038.

Nouveauté apparue avec la version 2, il y aussi un pied de page à la fin. Les entiers sont stockés en gros boutien, et en complément à deux. L'en-tête commence par la chaîne magique « TZif » (U+0054 U+005A U+0069 U+0066), et comprend la longueur du bloc de données (qui dépend du nombre de transitions, de secondes intercalaires et d'autres informations à indiquer). Le bloc de données contient la liste des transitions, le décalage avec UT, le nom du fuseau horaire, la liste des secondes intercalaires, etc. Vu par le mode hexadécimal d'Emacs, voici le début d'un fichier Tzif version 2 (pris sur une Ubuntu, dans /usr/share/zoneinfo/Europe/Paris). On voit bien la chaîne magique, puis le numéro de version, et le début du bloc de données :

00000000: 545a 6966 3200 0000 0000 0000 0000 0000  TZif2...........
00000010: 0000 0000 0000 000d 0000 000d 0000 0000  ................
00000020: 0000 00b8 0000 000d 0000 001f 8000 0000  ................
00000030: 9160 508b 9b47 78f0 9bd7 2c70 9cbc 9170  .`P..Gx...,p...p
00000040: 9dc0 48f0 9e89 fe70 9fa0 2af0 a060 a5f0  ..H....p..*..`..
...
    

Avec od, ça donnerait :


% od -x -a /usr/share/zoneinfo/Europe/Paris
0000000    5a54    6669    0032    0000    0000    0000    0000    0000
          T   Z   i   f   2 nul nul nul nul nul nul nul nul nul nul nul
0000020    0000    0000    0000    0d00    0000    0d00    0000    0000
        nul nul nul nul nul nul nul  cr nul nul nul  cr nul nul nul nul
0000040    0000    b800    0000    0d00    0000    1f00    0080    0000
        nul nul nul   8 nul nul nul  cr nul nul nul  us nul nul nul nul
0000060    6091    8b50    479b    f078    d79b    702c    bc9c    7091
        dc1   `   P  vt esc   G   x   p esc   W   ,   p  fs   < dc1   p
...

    

Un exemple détaillé et commenté de fichier TZif figure en annexe B. À lire si vous voulez vraiment comprendre les détails du format.

Le pied de page indique notamment les extensions à la variable d'environnement TZ. Toujours avec le mode hexadécimal d'Emacs, ça donne :

00000b80: 4345 542d 3143 4553 542c 4d33 2e35 2e30  CET-1CEST,M3.5.0
00000b90: 2c4d 3130 2e35 2e30 2f33 0a              ,M10.5.0/3.
    

On a vu que le format TZif avait une histoire longue et compliquée. La section 4 du RFC est entièrement consacré aux problèmes d'interopérabilité, liés à la coexistence de plusieurs versions du format, et de beaucoup de logiciels différents. Le RFC conseille :

  • De ne plus générer de fichiers suivant la version 1, qui ne marchera de toute façon plus après 2038.
  • Les logiciels qui en sont restés à la version 1 doivent faire attention à arrêter leur lecture après le premier bloc (dont la longueur figure dans l'en-tête).
  • La version 3 n'apporte pas beaucoup par rapport à la 2 et donc, sauf si on utilise les nouveautés spécifiques de la 3, il est recommandé de produire plutôt des fichiers conformes à la version 2.
  • Un fichier TZif transmis via l'Internet devrait être étiqueté application/tzif-leap ou application/tzif (s'il n'indique pas les secondes intercalaires). Ces types MIME sont désormais dans le registre officiel (cf. section 8 du RFC).

L'annexe A du RFC en rajoute, tenant compte de l'expérience accumulée ; par exemple, certains lecteurs de TZif n'acceptent pas les noms de fuseaux horaire contenant des caractères non-ASCII et il peut donc être prudent de ne pas utiliser ces caractères. Plus gênant, il existe des lecteurs assez bêtes pour planter lorsque des temps sont négatifs. Or, les entiers utilisant dans TZif sont signés, afin de pouvoir représenter les moments antérieurs à l'epoch. Donc, attention si vous avez besoin de données avant le premier janvier 1970, cela perturbera certains logiciels bogués.

La section 6 du RFC donne quelques conseils de sécurité :

  • L'en-tête indique la taille des données mais le programme qui lit le fichier doit vérifier que ces indications sont correctes, et n'envoient pas au-delà de la fin du fichier.
  • TZif, en lui-même, n'a pas de mécanisme de protection de l'intégrité, encore moins de mécanisme de signature. Il faut fournir ces services extérieurement (par exemple avec curl, en récupérant via HTTPS).

Une bonne liste de logiciels traitant ce format figure à l'IANA.


Téléchargez le RFC 8536


L'article seul

Articles des différentes années : 2019  2018  2017  2016  2015  2014  2013  Précédentes années

Syndication : en HTTP non sécurisé, Flux Atom avec seulement les résumés et Flux Atom avec tout le contenu, en HTTPS, Flux Atom avec seulement les résumés et Flux Atom avec tout le contenu.