Je suis Charlie

Autres trucs

Accueil

Seulement les RFC

Seulement les fiches de lecture

È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 7901: CHAIN Query Requests in DNS

Date de publication du RFC : Juin 2016
Auteur(s) du RFC : P. Wouters (Red Hat)
Expérimental
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 24 juin 2016


Lorsqu'un client DNS parle à un résolveur, il pose une question et obtient une réponse. Avant DNSSEC, ce mode de fonctionnement simple était souvent satisfaisant. Mais, avec DNSSEC, il est beaucoup plus fréquent de devoir faire plusieurs requêtes pour obtenir toute l'information nécessaire pour valider les réponses. (Il faut les clés de toutes les zones situées entre la racine et la zone visée.) Cela coûtait cher en latence. Cette extension EDNS expérimentale permet au client DNS de demander au résolveur de chercher et de renvoyer toutes les réponses d'un coup.

Cette extension est particulièrement utile pour le cas de machines terminales hébergeant leur propre résolveur validant (ce qui est la meilleure configuration, question confiance et sécurité). Ce n'est donc pas un hasard si l'auteur du RFC travaille chez Red Hat, système qui est livré par défaut avec une telle configuration. Mais, lorsqu'un tel résolveur validant veut vérifier les informations obtenues sur foo.bar.example, il devra (en supposant qu'il y a une zone par composant du nom de domaine) obtenir la délégation sécurisée de example (dig @la-racine DS example), la clé de example (dig @ns-example DNSKEY example), la délégation sécurisée de bar.example, etc (la clé de la racine, elle, est en dur dans le résolveur, il faut bien partir de quelque part). À faire séquentiellement, cela serait beaucoup de requêtes, donc du temps passé à attendre les réponses. Sur des liens à latence élevée (ce qui arrive souvent aux machines terminales), cela peut être pénible, même si le cache DNS aidera, pour les requêtes suivantes.

L'idée de cette extension (sections 1 et 3 du RFC) est donc que le résolveur validant local ait un forwarder (attention, le RFC utilise un vocabulaire erroné, en donnant à forwarder un sens différent de celui qu'il a dans les RFC 2308 et RFC 7719 ; j'utilise, moi, la terminologie standard). Le résolveur validant local va demander à ce forwarder, grâce à la nouvelle extension EDNS CHAIN, d'envoyer tout d'un coup (tous les DS et DNSKEY nécessaires). Bien sûr, le forwarder, lui, devra faire toutes les requêtes mais, a priori, il a un plus gros cache et sera mieux connecté.

Cette nouvelle extension est donc conçue pour des résolveurs, et est ignorée par les serveurs faisant autorité. Notez que le résolveur validant local peut être un démon autonome (Unbound tournant sur mon portable Unix) ou bien une partie d'une application qui embarquerait ses propres fonctions de résolution de noms.

Le format de l'extension est décrit en section 4 du RFC. C'est une option EDNS (RFC 6891), encodée, comme les autres options EDNS, en TLV. Le type (le code) est 13. La valeur est composée d'un seul champ, l'ancêtre le plus proche (Closest Trust Point) dont on connaisse les informations nécessaires à la validation. Le résolveur validant local a en effet certaines informations (dans sa configuration ou dans son cache) qu'il n'est pas nécessaire de lui envoyer. Dans l'exemple plus haut, si le résolveur validant local connait déjà la clé DNSSEC de example, il mettra dans le champ Closest Trust Point ce nom de domaine, indiquant au forwarder qu'il peut se contenter des informations situées plus bas, dans l'arbre du DNS. Ce nom est encodé dans le format habituel du DNS (qui n'est pas le format texte avec les points).

La section 5 du RFC décrit comment utiliser cette extension au DNS. Si on veut tester les capacités du résolveur qu'on interroge, on peut utiliser une option CHAIN vide (longueur nulle). Si le serveur à qui on a envoyé cette option répond avec la même option nulle, c'est bon. Attention, les serveurs récursifs qui mettent en œuvre CHAIN n'accepteront des requêtes « réelles » (longueur non nulle) qu'au dessus d'un transport où l'adresse IP source est vérifiée. Le but est d'éviter les attaques par réflexion avec amplification (voir aussi la section 7.2). Pour vérifier l'adresse IP source (ce qui ne se fait normalement pas en UDP), il y a plusieurs solutions, notamment TCP (RFC 7766) et les gâteaux (RFC 7873).

Une fois qu'on a un tel transport, et que le client DNS a testé que le serveur qu'il interroge gère bien CHAIN, on peut y aller. Le client met l'ancêtre le plus proche (dont il a les clés) du nom demandé dans le champ Closest Trust Point. Dans le cas le plus courant (résolveur validant configuré avec une seule clé, celle de la racine), le résolveur « froid », qui vient de démarrer et dont le cache est vide, il commencera par mettre la racine en Closest Trust Point puis, au fur et à mesure qu'il se « réchauffera » (que son cache se peuplera), il pourra mettre des noms plus proches du nom demandé (et donc plus éloignés de la racine). Par exemple, si le résolveur validant local est configuré avec la clé de la racine, et qu'il a appris par les réponses précédentes la clé de example, mais pas celle de bar.example, et qu'il veut des informations sur le nom foo.bar.example, son option CHAIN vaudra {type = 13, longueur = 9, valeur = 0x07 0x65 0x78 0x61 0x6d 0x70 0x6c 0x65 0x00} (la longueur est celle de la partie « valeur » uniquement, le nom example est encodé selon la norme DNS). S'il connaissait également la clé de bar.example, son option CHAIN vaudrait {type = 13, longueur = 13, valeur = 0x03 0x62 0x61 0x72 0x07 0x65 0x78 0x61 0x6d 0x70 0x6c 0x65 0x00}. D'autres exemples figurent en section 9 du RFC.

Faut-il envoyer l'option CHAIN à chaque requête ? On peut mais il est recommandé de se souvenir de quels serveurs la gèrent et de n'envoyer qu'à ceux-ci (autrement, non seulement on fait du travail inutile mais on renseigne des serveurs extérieurs sur l'état de son cache). Comme il existe des middleboxes boguées sur certains trajets, la stratégie de repli du RFC 6891, section 6.2.2 peut être utile.

Et le serveur interrogé, que fait-il ? S'il accepte de répondre à une requête contenant l'extension CHAIN, il doit :

  • Ajouter à la réponse, dans la section Autorité, les enregistrements DNSSEC nécessaires (DS, DNSKEY et NSEC),
  • Mettre une CHAIN dans la réponse, avec la valeur Closest Trust Point mise au nom le plus bas (le plus éloigné de la racine) pour lequel ces informations sont nécessaires. (C'est surtout utile lorsque le serveur n'envoie pas une chaîne complète, par exemple pour économiser le réseau.)

Évidemment, si la question avait une erreur de syntaxe (taille de la partie Valeur inférieure à la Longueur, par exemple), le serveur répond FORMERR (FORmat ERRor).

La section 7 sur la sécurité étudie quelques programmes que peut poser cette extension au DNS. D'abord, mettre en œuvre cette option fatigue davantage le serveur interrogé, en terme de travail et de capacité du réseau. Un serveur est donc toujours libre d'ignorer les options CHAIN et de s'en tenir au service minimum.

Ensuite, comme vu plus haut, les réponses suivant une question qui utilise CHAIN vont être évidemment plus grosses que les réponses DNS habituelles. Il y a donc un risque d'attaques par réflexion avec amplification, si un attaquant usurpe l'adresse IP de sa victime. C'est pour cela que notre RFC impose de ne répondre avec une chaîne complète que si l'adresse IP du client a été vérifiée (par exemple parce qu'il utilise TCP, ou bien les cookies du RFC 7873).

CHAIN a aussi quelques effets sur la vie privée. Le résolveur validant local va indiquer à son forwarder (et à tout espion qui surveille le trafic) comment il est configuré et ce qu'il y a dans son cache.

Il ne semble pas qu'il existe de mise en œuvre de cette option CHAIN pour l'instant, même si c'est en projet pour Go.

Si vous vous intéressez à la conception des protocoles réseaux, notez que cette extension a fait l'objet d'une discussion pour savoir s'il ne valait pas mieux, pour réduire la latence, envoyer toutes les requêtes possibles en parallèle (cette idée a finalement été rejetée).


Téléchargez le RFC 7901


L'article seul

Version 9 d'Unicode

Première rédaction de cet article le 22 juin 2016


Le 21 juin, la nouvelle version d'Unicode est sortie, la 9.0. Une description officielle des principaux changements est disponible mais voici ceux qui m'ont intéressé particulièrement. (Il n'y a pas de changement radical.)

Pour explorer plus facilement la grande base Unicode, j'utilise un programme qui la convertit en SQL et permet ensuite de faire des analyses variées. Faisons quelques requêtes SQL :

ucd=> SELECT count(*) AS Total FROM Characters;
 total  
--------
 128237

Combien caractères sont arrivés avec la version 9 ?


ucd=> SELECT version,count(version) FROM Characters GROUP BY version ORDER BY version;
...
 8.0     |  7716
 9.0     |  7500

7 500 nouveaux pile. Lesquels ?

ucd=> SELECT To_U(codepoint) AS Codepoint, name FROM Characters WHERE version='9.0';
 codepoint |                                    name                                    
-----------+----------------------------------------------------------------------------
...
 U+8BA     | ARABIC LETTER YEH WITH TWO DOTS BELOW AND SMALL NOON ABOVE
...
 U+8E2     | ARABIC DISPUTED END OF AYAH
...
 U+23FB    | POWER SYMBOL
 U+23FC    | POWER ON-OFF SYMBOL
 U+23FD    | POWER ON SYMBOL
 U+23FE    | POWER SLEEP SYMBOL
...
 U+104D8   | OSAGE SMALL LETTER A
 U+104D9   | OSAGE SMALL LETTER AI
 U+104DA   | OSAGE SMALL LETTER AIN
...
 U+17000   | TANGUT IDEOGRAPH-17000
 U+17001   | TANGUT IDEOGRAPH-17001
 U+17002   | TANGUT IDEOGRAPH-17002
...
 U+1F921   | CLOWN FACE
 U+1F922   | NAUSEATED FACE
 U+1F923   | ROLLING ON THE FLOOR LAUGHING
...
 U+1F933   | SELFIE
...
 U+1F953   | BACON
 U+1F954   | POTATO
 U+1F955   | CARROT

On trouve également des écritures entièrement nouvelles comme l'osage ou le tangoute, qui fait 91 % des nouveaux caractères de cette version. Et il y a bien sûr l'habituel lot d'emojis pour faire rire les réseaux sociaux (signe des temps, il y a maintenant un emoji pour selfie). Je ne sais pas pourquoi on ajoute des caractères arabes pré-composés comme le « ARABIC LETTER YEH WITH TWO DOTS BELOW AND SMALL NOON ABOVE » au lieu de permettre sa composition à partir de caractères existants. On note aussi un caractère dont le nom indique qu'il est contesté... (Il existe déjà U+6DD, « ARABIC END OF AYAH » mais on me souffle que le nouveau serait nécessaire au Pakistan.) On note qu'après un long lobbying, les symboles d'allumage et d'extinction de votre machine sont désormais dans Unicode.

Si vous avez les bonnes polices de caractères, voici les caractères pris en exemple plus haut : ࢺ ࣢ ⏻ ⏼ ⏽ ⏾ 𐓘 𐓙 𐓚 𗀀 𗀁 𗀂 🤡 🤢 🤣 🤳 🥓 🥔 🥕

Il n'y a pas que l'ajout de nouveaux caractères, mais aussi quelques légers changements techniques. Par exemple, les règles de passage à la ligne (UAX #14) prennent désormais en compte les gens qui ont un signe $ dans leur nom (comme Travi$ Scott) et les règles IDN (UTS #46) ont corrigé une bogue.


L'article seul

RFC 7855: Source Packet Routing in Networking (SPRING) Problem Statement and Requirements

Date de publication du RFC : Mai 2016
Auteur(s) du RFC : S. Previdi, C. Filsfils (Cisco Systems), B. Decraene, S. Litkowski (Orange), M. Horneffer (Deutsche Telekom), R. Shakir (Jive Communications)
Pour information
Réalisé dans le cadre du groupe de travail IETF spring
Première rédaction de cet article le 22 juin 2016


Traditionnellement, la transmission d'un paquet IP au routeur suivant était faite uniquement sur la base de l'adresse de destination, sans tenir compte du reste du paquet. Et la décision est prise par chaque routeur, sur le trajet, en complète indépendance. Or, l'émetteur d'un paquet voudrait souvent décider de la route suivie ou, au minimum, l'influencer. C'est pour cela qu'il existe des mécanismes de routage par la source (source routing). Leurs défauts et leurs limites ont mené à la recherche d'une meilleure solution, dite SPRING (Source Packet Routing In NetworkinG). Ce RFC est la description du problème.

Notez que le terme « source » a, pour SPRING, un sens plus large que lorsqu'on parle habituellement de source routing. Dans ce dernier cas, la source était uniquement l'émetteur original. Pour SPRING, la source est l'endroit où on définit la politique de routage ultérieur, elle peut se situer au milieu du trajet.

Avant SPRING, il y avait plusieurs solutions permettant à la source de décider du routage mais aucune n'a été largement déployée (à part MPLS). C'est dû en partie à leur manque de souplesse, en partie à des problèmes de sécurité.

La future solution SPRING doit être un meilleur système (section 1 du RFC), et déployable de manière incréméntale (il ne serait évidemment pas réaliste de devoir changer tout l'Internet). En outre, l'état doit être maintenu dans le paquet lui-même, pas dans les routeurs intermédiaires. L'expérience de l'Internet a en effet largement montré que pour faire marcher un grand réseau complexe, il ne faut pas maintenir d'état dans les nœuds intermédiaires.

SPRING devra être assez général marcher avec plusieurs mécanismes de transmission des paquets (dataplanes, cf. section 2). Les principaux visés sont MPLS et IPv6 avec un nouvel en-tête de routage (cf. RFC 2460, section 4.4).

La section 3 présente plusieurs scénarios d'usage, pour montrer pourquoi un système tel que SPRING est utile. Il y a par exemple la création de tunnels pour faire des VPN (RFC 4364).

Il y a aussi le reroutage rapide de paquets (FRR, Fast ReRoute), et bien sûr l'ingéniérie de trafic. Pour ce dernier scénario, notre RFC demande que la future solution SPRING permette des options strictes (le paquet suit exactement le chemin spécifié) ou laxistes (le paquet suit à peu près le chemin spécifié), puisse fonctionner en centralisé (SDN) ou en décentralisé, etc.

Une des raisons du peu de déploiement des solutions de routage par la source est évidemment la sécurité (section 4 du RFC). SPRING met le chemin désiré dans le paquet (pour éviter de garder un état dans le réseau). Or, si on suit aveuglément les desiderata de chaque paquet, on ouvre la voie à des tas d'attaques. Par exemple, un paquet spécifie un détour considérable par un autre pays, et cela occupe pour rien les liaisons internationales. Un paquet spécifie un trajet qui boucle et les routeurs qui lui obéiraient feraient une attaque par déni de service contre eux-mêmes.

Le RFC impose donc que SPRING fournisse un mécanisme de « domaines de confiance » avec des frontières bien claires. Si un paquet vient d'un domaine de confiance, on lui obéit. S'il vient de n'importe où sur l'Internet, on ignore ses demandes (ou bien on vire ces options de routage par la source lorsque le paquet change de domaine).

La réalisation concrète de SPRING sur un système de transmission donné (comme MPLS ou IPv6) doit également documenter les risques spécifiques à ce dataplane. Par exemple, MPLS est en général utilisé uniquement à l'intérieur d'un domaine contrôlé et connu (le réseau d'un opérateur) alors qu'IPv6 est de bout en bout donc pose davantage de risques (mais il dispose de possibilités supplémentaires, comme la signature cryptographique des en-têtes).

Il faut maintenant attendre les RFC décrivant les solutions, ils sont en cours de développement dans le groupe SPRING.


Téléchargez le RFC 7855


L'article seul

RFC 7874: WebRTC Audio Codec and Processing Requirements

Date de publication du RFC : Mai 2016
Auteur(s) du RFC : JM. Valin (Mozilla), C. Bran (Plantronics)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF rtcweb
Première rédaction de cet article le 21 juin 2016


Ce très court RFC expose les exigences en matière de codec audio pour WebRTC. Opus et G.711 sont ainsi obligatoires.

WebRTC permet de communiquer (texte, audio et vidéo) entre deux machines, typiquement via les navigateurs Web (ainsi, Firefox et Chrome sont tous les deux capables de faire du WebRTC.) On sait qu'il existe un grand nombre de moyens de représenter les sons sous forme d'un flux de données numériques et, pour que la communication puisse se faire, il faut que les participants aient au moins un de ces moyens en commun. C'est le but de ce RFC. D'autres codecs peuvent évidemment être gérés par le logiciel mais ceux-ci sont obligatoires (section 3 du RFC) :

  • Opus (RFC 6716), avec le format du RFC 7587.
  • G.711, avec le format de la section 4.5.14 du RFC 3551.
  • La gestion du bruit de fond du RFC 3389. (Sauf pour Opus, qui a sa propre gestion.)
  • Le format audio/telephone-event du RFC 4733 (DTMF), qui permet d'envoyer les indispensables signaux « si vous voulez de la musique d'attente pendant une heure, tapez 1, si vous voulez parler à un incompétent sous-payé qui ne comprendra pas votre problème, tapez 2 ».

Les autres codecs facultatifs sont décrits dans le RFC 7875, ce qui a permis à chacun de faire citer son codec favori.

Notre RFC spécifie également le niveau sonore (section 4). Contrairement aux recommandations UIT G.169 et G.115, il n'est pas constant car il dépend de la bande passante.

Il y a aussi une mention de la suppression d'écho (section 5 du RFC), mais sans solution unique imposée.


Téléchargez le RFC 7874


L'article seul

The DAO, Ethereum, et l'attaque de juin 2016

Première rédaction de cet article le 20 juin 2016


Vendredi 17 juin 2016, une attaque spectaculaire contre l'organisation The DAO a eu lieu, menant à la soustraction d'environ un tiers de ses fonds. Quelles leçons à en tirer ?

Si vous connaissez au moins un peu The DAO et Ethereum, vous pouvez lire tout de suite mes réflexions sur cette crise. Si vous ne connaissez pas, vous pouvez lire en anglais la bonne explication de Robert Graham ou bien en français les articles de Wikipédia sur Ethereum et les contrats.

Comme d'habitude lorsqu'un gros problème de cybersécurité est publié, on trouve du grand n'importe quoi dans les médias ou sur les rézosocios. Il est donc important de commencer par être précis sur les faits :

  • La bogue n'était pas dans la chaîne de blocs Ethereum, ni même dans un autre élément d'infrastructure comme le compilateur Solidity. Elle était uniquement dans un contrat (un programme stocké dans la chaîne Ethereum), le contrat The DAO. Dire qu'Ethereum est menacé, ou que le concept de chaîne de blocs est menacé, revient à affirmer que PHP, voire le Web entier, est menacé parce qu'on a trouvé une bogue dans WordPress.
  • Le voleur n'a pas réussi à récupérer les fonds soustraits à The DAO et il n'est pas sûr qu'il y arrive jamais. On est loin du casse du siècle. La transparence de la chaîne de blocs, qui crée bien des vulnérabilités, fournit également les moyens d'empêcher le voleur de jouir du fruit de son forfait.
  • L'attaque n'a rien à voir avec les problèmes de Mt. Gox, souvent cités par des journalistes paresseux (« crypto-monnaie? Citons MtGox ! »). Il ne s'agit pas du piratage (ou de la malhonnêteté) d'un site centralisé particulier, mais d'une faille d'un contrat, un concept spécifique à Ethereum et qui n'a donc pas de vrai équivalent jusqu'à présent.

Mais cela ne veut pas dire que cette bogue est juste un détail sans importance et qu'on peut passer. Il s'agit d'une crise grave, dont il faudra tirer les leçons. D'abord, sur l'aspect technique (mais je parle des questions financières, légales et de gouvernance par la suite). L'origine du problème est une bogue dans le code de The DAO (pour les cœurs bien accrochés, voici les explications techniques complètes). C'est une banalité de noter qu'on ne sait pas écrire du logiciel sans bogues. Tout logiciel a des bogues et, avant de confier des fonds à un contrat, il faut garder ce point en tête. Un des rares cas dans cette affaire où les pessimistes systématiques (« ce n'est pas moi qui a inventé ce truc, donc ça va rater ») avaient raison est quand ils pointaient le fait qu'il y aura forcément des bogues dans les contrats et, qu'en l'absence de mécanisme de recours, on aura du mal à en gérer les conséquences.

Cela ne veut pas dire qu'il faut baisser les bras et renoncer à programmer. Mais il faut changer, et d'état d'esprit, et sans doute de techniques utilisées. Emin Gün Sirer fait remarquer à juste titre que l'écriture d'un contrat devrait ressembler à celle du code d'un avion ou d'une centrale nucléaire, pas à celle d'un site Web avec images et CMS. Or, aujourd'hui, pas mal de programmeurs de contrat sont plutôt dans la mentalité « si le code semble faire vaguemement ce qu'on veut, c'est bon », qui a mené à pas mal de désastres de sécurité sur le Web. Du point de vue des techniques utilisées, le même Sirer a raison de dire qu'il faut se poser la question des langages de programmation. Un langage impératif comme Solidity est-il vraiment la meilleure solution pour faire des contrats sûrs, et ne faudrait-il pas plutôt utiliser des langages plus adaptés, par exemple plus fonctionnels, inspirés d'Haskell ? Ces langages ont un fossé plus réduit entre la spécification et l'exécution. Plus radicale, la vérification formelle des contrats devrait-elle être la norme ? A priori oui, mais soyons prudents : les mécanismes de vérification formelle des programmes sont lourds et compliqués et ont leurs propres bogues.

En parlant de spécification, Vitalik Buterin a fait un très bon article pour expliquer qu'une bogue, c'est par définition une déviation par rapport à la spécification, et que réduire le nombre de bogues implique d'être clair dans la spécification, ce qui est déjà un défi considérable. Dans un message non authentifié, un individu se présentant comme l'attaquant prétend ainsi que, le code du contrat étant sa loi, par définition, toute opération faite avec le contrat The DAO est légale, y compris son vol. Il est bien sûr de mauvaise foi, mais on peut noter qu'il n'est pas possible de lui opposer une spécification précise de ce que le contrat était censé faire.

Autre leçon technique, un rappel que la complexité est l'ennemie de la sécurité. Le code de The DAO comprenait de nombreuses fonctions (comme celle permettant de retirer ses fonds, à l'origine de la bogue), ce qui augmentait la probabilité d'avoir une bogue. J'ai toujours expliqué que le terme de smart contract était dangereux car il encourageait les programmeurs à faire du code compliqué, alors qu'un bon contrat est au contraire trivial à lire et à analyser. Un programmeur de contrat ne devrait pas être admiré pour ses hacks astucieux mais au contraire pour sa capacité à faire du code ennuyeux et évident. (Je pensais à la validation d'un contrat par ses utilisateurs, mais ce raisonnement s'applique également à la sécurité.)

A posteriori, il est clair qu'on est passé trop rapidement du petit contrat « Hello, World », à un gros truc complexe, avec plein de fric, comme The DAO. C'est un peu comme si, immédiatement après la traversée de la Manche par Blériot, on avait lancé sur l'Atlantique un avion de 500 passagers payants...

Il y a aussi des leçons à tirer de l'excessive focalisation sur l'argent, commune à une bonne partie de la communauté Ethereum, et aux médias. Les médias ont surtout présenté cette crise sous son angle financier (The DAO a perdu 50 millions, l'ether a baissé de 50 %, etc) alors que la chaîne de blocs Ethereum, contrairement à celle de Bitcoin, ne sert pas qu'à des transactions financières. Des tas de contrats ne consomment des ethers que pour acheter l'essence (le mécanisme par lequel on paie pour l'exécution des contrats). Se focaliser sur les contrats à caractère financier, comme The DAO, empêche de voir toutes les potentialités de la chaîne de blocs (plusieurs articles ont ainsi présenté, de manière erronée, Ethereum comme étant juste « une crypto-monnaie concurrente de Bitcoin »). Et, évidemment, stocker autant d'argent allait attirer les voleurs. Bref, tant que les articles sur Ethereum continueront à mettre en avant le cours de l'ether en comparant avec la monnaie étatique traditionnelle, on n'arrivera pas à comprendre toutes les potentialités (disruptives, forcément disruptives) de la chaîne de blocs.

Il y a également bien des leçons à tirer de la crise de The DAO en terme de gouvernance de la chaîne de blocs. Normalement, les contrats « intelligents » étaient censés se gouverner tout seuls. Le code est la loi, il est exécuté fidèlement par la la machinerie Ethereum, et il n'y a donc pas de place pour l'interprétation ou l'action humaine. Face à la crise et au vol d'ethers, que fallait-il faire ? En schématisant, il y avait deux positions : les principiels voulaient qu'on laisse les choses se produire. The DAO avait une bogue, ils perdent leur argent. Selon eux, toute autre solution aurait mis en cause ce qui était justement l'un des principaux arguments en faveur des contrats, leur côté automatique, insensibles aux passions et aux manipulations humaines. Les réalistes, de l'autre côté, considéraient qu'on ne pouvait pas rester sans rien faire et voir le voleur emporter l'argent. Ils prônent un fork, c'est-à-dire une scission délibérée de la chaîne : une nouvelle version des logiciels est produite, appliquant des règles différentes (par exemple empêchant les transferts depuis le compte du voleur). Certains nœuds du réseau adoptent le fork, d'autres pas. Si les premiers sont plus nombreux, leur chaîne est considérée comme la bonne, les autres n'ont plus qu'à se soumettre, ou à partir et faire leur chaîne de leur côté (ce qui serait évidemment une grosse tuile pour Ethereum). Vu superficiellement, cela serait une décision centrale dans un système, la chaîne de blocs, conçu justement pour éviter cela. Mais si une telle décision peut en effet être prise par un petit groupe de gens (en gros, les développeurs des logiciels qui font marcher la chaîne ; notez que, contrairement à Bitcoin, il n'existe pas qu'un seul logiciel), sa mise en œuvre, elle, dépend de tous les gens qui gèrent des nœuds (enfin, surtout des mineurs), et qu'il faut convaincre. C'est pour cela que les articles de Buterin, par exemple, insistent sur le fait que les développeurs comme lui n'imposent pas, ils proposent. Une attitude tout à fait opposée était celle de de Stephan Tual qui, dans ce tweet et celui-ci accusait tout opposant (ceux qui refusent le fork, les principiels), d'être forcément en cheville avec le voleur, et appelait même à les dénoncer ! Ce délire robespierro-stalinien a certainement fait bien plus de mal à Ethereum que la bogue elle-même.

Un des éléments du débat était aussi le statut particulier de The DAO. Pourquoi forker juste pour eux, disent les principiels ? Fera-t-on pareil à chaque fois qu'un contrat a une bogue ? Le seul argument des réalistes est la taille : The DAO est « too big to fail ». Après que tant de gens, aussi bien à l'intérieur de la communauté Ethereum qu'à l'extérieur, aient entretenu une certaine confusion entre Ethereum et The DAO, il est difficile de laisser tomber le canard boiteux. Même si cela a mené à des injustices flagrantes, comme l'appel lancé par Slock.it à faire une attaque par déni de service contre toute la chaîne Ethereum, pour ralentir l'attaquant (cette boîte a fait une bogue, et la fait payer à tout le monde).

Cette crise pose donc évidemment la question de ce mode de gouvernance « le code [des contrats] est la seule règle ». Thibault Verbiest a ainsi estimé que ce n'était pas souhaitable et qu'il fallait une régulation étatique des chaînes de blocs.

Les habituels ricaneurs ont évidemment proclamé qu'ils avaient bien raison, et que la chaîne de blocs était fichue, et que cela les faisait bien rigoler (manger le popcorn en regardant le film est évidemment plus facile que de travailler). Mais on est loin d'une telle conclusion. Si The DAO ne survivra probablement pas à cette crise, l'idée de contrat, les autres contrats et Ethereum lui-même sont bien vivants et continueront, une fois la crise actuelle digérée. Les contrats sont une innovation et, comme toute innovation, les débuts sont un peu cahotiques. Lors des débuts de l'aviation, le projet le plus sérieux, celui qui avait de très loin le plus gros budget et la plus grande attention des médias était celui de Langley. Le 8 décembre 1903, son projet se termine après un nouveau crash, qui mène beaucoup de gens à affirmer que l'aviation est morte. Une semaine après, le premier avion des frères Wright décolle avec succès... Matthew Spoke estime même que cette attaque est une bonne chose, elle va forcer à être plus sérieux.

PS : j'ai oublié d'en parler initialement, mais voici la déclaration de conflit d'intérêt. Je ne possède pas (et n'ai jamais possédé) de tokens (de parts) de The DAO.


L'article seul

RFC 7871: Client Subnet in DNS Queries

Date de publication du RFC : Mai 2016
Auteur(s) du RFC : C. Contavalli, W. van der Gaast (Google), D. Lawrence (Akamai Technologies), W. Kumari (Google)
Pour information
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 20 juin 2016


Ce nouveau RFC décrit une option EDNS qui permet à un client DNS d'indiquer au serveur l'adresse IP d'origine de la requête DNS. Pourquoi diable ferait-on cela, au prix de la vie privée ? Cette option est surtout utile dans le cas de l'utilisation d'un gros résolveur DNS public (comme Google Public DNS) et d'un CDN.

Pour comprendre pourquoi, il faut se rappeler que le DNS ne fonctionne pas de bout en bout. La machine de M. Michu émet des requêtes DNS à un résolveur (en général fourni par le FAI ou par le réseau local, mais certaines personnes, victimes du marketing, préfèrent les résolveurs publics comme OpenDNS, plus lointains et plus lents). Ce résolveur, à son tour, interroge les serveurs faisant autorité. Si M. Michu voulait se connecter à un site Web pour voir des vidéos de chats, il est possible qu'un nouvel acteur soit présent, le CDN (comme Akamai) qui héberge les dites vidéos. Les serveurs DNS faisant autorité pour le CDN renvoient souvent une adresse IP différente selon l'adresse IP du résolveur qui les interroge. Si l'adresse IP du client est au Sénégal, l'adresse IP du serveur de vidéos qui sera renvoyée sera celle du centre de données le plus « proche » du Sénégal. En temps normal, cela fonctionne plus ou moins. Bien sûr, le serveur DNS faisant autorité pour le CDN ne voit pas le « vrai » client, M. Michu, il voit le résolveur DNS utilisé mais les deux sont proches : si M. Michu est en Colombie, son résolveur DNS le sera aussi. Voici un exemple, vu avec les sondes RIPE Atlas, où on demande, au Sénégal (SN) puis en Colombie (CO) l'adresse IP de www.elysee.fr, hébergé sur un CDN états-unien :

% atlas-resolve --country SN www.elysee.fr
[207.123.59.254 209.84.7.126 8.27.7.254] : 1 occurrences 
[209.84.7.126 8.253.3.254 8.27.7.254] : 1 occurrences 
[4.26.233.254 4.26.236.126 8.254.119.126] : 1 occurrences 
[207.123.59.254 209.84.7.126 8.253.3.254] : 1 occurrences 
[207.123.59.254 8.26.223.254 8.27.7.254] : 1 occurrences 
Test #4106632 done at 2016-06-15T22:52:44Z

% atlas-resolve --country CO www.elysee.fr
[192.221.116.253] : 3 occurrences 
[205.128.71.253 4.27.25.125 8.27.155.126] : 1 occurrences 
[206.33.52.253 209.84.20.126 8.253.16.126] : 1 occurrences 
Test #4106633 done at 2016-06-15T22:52:46Z
  

On voit qu'on a obtenu des adresses IP très différentes et, espérons-le, adaptées à chaque pays.

Autre exemple, avec un service de PowerDNS, qui renvoit une géolocalisation du client. Ici, j'utilise dig depuis deux machines différentes, une en France et l'autre aux États-Unis :

%  dig +short -t txt www.geo.powerdns.com 
"bonjour france 2a01:db8:8bd9:85cb:21e:8cff:fe76:29b6/26"

% dig +short -t txt www.geo.powerdns.com 
"hello USA 204.62.14.153/22"

On voit que le résolveur que j'utilise (qui, à chaque fois, était sur le réseau local de la machine cliente), a bien été géolocalisé. Si j'utilise un résolveur public :

%  dig @8.8.8.8 +short -t txt www.geo.powerdns.com  
"bonjour france XX.YY.152.0/11"

Ici, cela a marché car Google Public DNS a des serveurs en France. Si cela n'avait pas été le cas, j'aurais été géolocalisé... quelque part ailleurs.

Tout change (section 1 du RFC) si on utilise un résolveur DNS public comme Verisign Public DNS ou bien Yandex DNS. Dans ce cas, l'adresse IP du résolveur, vue par le serveur faisant autorité pour le CDN, n'a plus grand'chose à voir avec celle du vrai client, elle peut être très lointaine. Les serveurs DNS faisant autorité risquent donc de renvoyer une adresse IP de serveur Web qui ne soit pas optimale. Certes, tout marchera quand même mais ça sera plus lent alors qu'officiellement, le but des CDN est d'accélerer l'arrivée de la vidéo du chat (non, de François Hollande).

On voit que ce RFC résout donc un problème que n'a pas tout le monde. Seuls ceux qui se servent d'un résolveur public lointain, et qui visitent des sites Web hébergés sur un CDN (en général les gros sites commerciaux) auront le problème. C'est une des raisons qui expliquent que ce RFC a pas mal trainé (voyez cet article, qui date de plusieurs années) à l'IETF : son intérêt n'est pas évident, et il y avait beaucoup de contestation. Mais l'IETF a finalement choisi de documenter cette option (qui est effectivement déployée), sans forcément la recommander. (On peut consulter le site de promotion du projet.)

Donc, comment est-ce que cela résout le problème décrit plus haut ? L'idée est de standardiser une option EDNS que les résolveurs publics ajouteront dans leur requête aux serveurs faisant autorité, et qui indiquera la « vraie » adresse IP d'origine (section 5 du RFC). Imaginons que M. Michu ait pour adresse IP 192.0.2.56 et qu'il utilise Google Public DNS. Ce dernier va transmettre la requête au CDN et ajoutera l'option Client Subnet (ce n'est donc pas M. Michu qui le fera). Le serveur DNS du CDN verra une requête arriver de, mettons, 74.125.17.1. L'option EDNS Client Subnet contiendra le préfixe de l'adresse IP de M. Michu, 192.0.2.0/25. Il saura alors qu'il doit adapter ses réponses, non pas au préfixe 74.125.17.0/24 (son client direct) mais au préfixe 192.0.2.0/25 (le vrai client). C'est donc une option entre résolveur et serveur faisant autorité, pas entre machine terminale et résolveur.

Le format de l'option est décrite dans la section 6 du RFC. Comme toutes les options EDNS (RFC 6891), elle est encodée en TLV : le type est 8, la valeur est composée de :

  • La famille d'adresses utilisée (IPv4 ou IPv6, l'exemple ci-dessus utilisait IPv4),
  • La longueur du préfixe indiqué dans la requête DNS (25 bits dans l'exemple ci-dessus),
  • La longueur significative du préfixe dans la réponse DNS (elle est mise à zéro dans les requêtes),
  • Le préfixe lui-même (192.0.2.0 dans l'exemple plus haut).

La section 7 du RFC décrit les détails du protocole. Le résolveur va mettre dans son cache les réponses du serveur faisant autorité. Normalement, l'information dans le cache est indexée par le nom de domaine (et le type de données demandé, mais je simplifie). Avec ECS (EDNS Client Subnet), l'information est indexée par le couple {nom de domaine, préfixe IP}. En effet, deux requêtes pour le même nom peuvent avoir donné des résultats différents selon le préfixe IP (c'est bien le but !)

Le résolveur qui met cette option doit choisir la longueur du préfixe envoyé. Il tient compte de deux choses :

  • La capacité de son cache : si le préfixe est trop spécifique, le cache devra stocker davantage de données (imaginons en IPv6 une réponse différente par adresse IP : le cache pourrait avoir à stocker 2^128 réponses par nom de domaine !)
  • La protection de la vie privée des utilisateurs. ECS la menace déjà, n'aggravons pas les choses. En utilisant un préfixe assez général, on limite l'indiscrétion.

Mais l'affaire est un peu plus compliquée : le client d'origine (la machine de M. Michu, le stub resolver) a pu mettre une option ECS elle-même (ce n'est pas courant aujourd'hui mais ça pourrait arriver). Dans ce cas, le résolveur doit en tenir compte et mettre comme longueur la plus courte entre celle demandée par le client (a priori pour protéger sa vie privée) et celle que le résolveur aurait choisi tout seul.

Si la requête reçue par le résolveur avait l'option ECS et une longueur de zéro, cela indique le souhait du client qu'on ne transmette pas son adresse IP du tout. Le résolveur doit évidemment respecter cette demande.

Et le serveur faisant autorité, que doit-il mettre dans sa réponse ? (S'il envoie des réponses différentes selon la source, et s'il gère l'option ECS, EDNS Client Subnet ; autrement, c'est simple, il ne fait rien de particulier.) Il met une option ECS dans la réponses, avec :

  • La famille, la longueur du préfixe demandé, et le préfixe identiques à celui de la requête,
  • Une longueur effective (scope prefix length) qui indique pour quel préfixe la réponse est valable. Cette longueur effective peut être supérieure à la longueur demandée (le préfixe était trop général, pense le serveur), ou inférieure (le préfixe était inutilement spécifique, le serveur ne varie pas ses réponses à ce point).

(Notez que le RFC est bien plus détaillé que ce résumé, car il y a plein de cas rigolos. Je me suis limité à une présentation générale, je n'essaie pas de traduire tout le RFC.)

En recevant cette réponse, le résolveur la mettre dans son cache, en tenant compte de la longueur du préfixe (et, bien sûr, le résolveur transmet la réponse à son client). Une réponse valable pour 2001:db8:43:bef::/64 ne pourra pas être utilisée pour le client 2001:db8:43:bed::1. Quelle longueur sera utilisée pour indexer le cache ? Celle demandée ou bien celle effective ? Les régles exactes sont un peu complexes (il faut tenir compte de la longueur effective, mais aussi des limites du cache, qui ne veut pas stocker une réponse pour des préfixes trop spécifiques), je vous renvoie à la section 7.3.1 du RFC.

Les questions ultérieures des clients du résolveur pourront recevoir une réponse tirée du cache, sans repasser par les serveurs faisant autorité. Mais ECS impose d'organiser le cache différemment. Avec le DNS classique, si on a dans le cache la réponse à une question pour cat.example.com (je simplifie en ne tenant pas compte du type des données DNS), et qu'on reçoit une question pour ce nom, on peut répondre avec les données du cache. Avec ECS, le cache doit en plus tenir compte du préfixe stocké avec la réponse, et de l'adresse IP du client.

Et avec DNSSEC, ça se passe comment (section 9 du RFC) ? Les CDN ne signent pas leur zone en général. Mais s'ils se mettent (il faudrait), il y aura quelques précautions à prendre.

Et avec le NAT ? Il n'y a normalement pas de problèmes, sauf évidemment si le résolveur est NATé et ne le sait pas : il mettrait, dans ce cas, une adresse privée dans l'option ECS, ce qui serait idiot.

Reste à regarder les problèmes de sécurité et notamment de vie privée. ECS diminue forcément votre vie privée. Il ajoute en effet une information qui n'était pas là sans lui. C'est pour limiter les dégâts que le RFC recommande aux résolveurs qui ajoutent une option Client Subnet de la limiter aux 24 premiers bits en IPv4 et aux 56 premiers en IPv6. Un résolveur qui connait bien la topologie de son réseau peut faire encore mieux : s'il sait que tous ses clients sont proches, et couverts par le même /20, il peut ainsi ne transmettre que les vingt premiers bits, sans diminuer l'intérêt du service.

Notez que, avec les clients DNS d'aujourd'hui, votre résolveur mettra votre adresse IP dans ses requêtes sortantes. On peut en sortir (opt-out en mettant une option ECS avec une longueur nulle) mais cela nécessite une action explicite (que ne permettent pas forcément les clients DNS actuels). Le RFC recommande donc que cette option ECS soit désactivée par défaut, en raison de ces risques.

L'option ECS peut être vue par les serveurs faisant autorité, mais également par les tiers qui espionnent le trafic. Pour empêcher cela, il faudra déployer des solutions de chiffrement du trafic DNS, comme celles sur lesquelles travaille le groupe DPRIVE.

Un bon article sur les problèmes de vie privée liés à ECS est le « Privacy Implications of ECS » (pas encore publié) de Panagiotis Kintis, Yacin Nadji, David Dagon, Michael Farrell et Manos Antonakakis. Un autre bon article sur cette question est celui de Frank Denis.

Voyons maintenant cette option ECS en action. Elle est par exemple utilisée par Google dont le résolveur public ajoute cette option avant de l'envoyer aux serveurs faisant autorité. Mais on trouve une liste d'utilisateurs plus détaillée sur le site de promotion de la technologie.

Parmi les logiciels libres qui la mettent en œuvre, on note la bibliothèque getdns. Ou bien le programme dig livré avec BIND. Voici un exemple avec la nouvelle option +subnet de dig (prise sur un BIND 9.11, l'option était déjà en 9.10) :

% dig +subnet=8.189.152.0/25 @ns-1568.awsdns-04.co.uk  A www.amazon.com 
...
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; CLIENT-SUBNET: 8.189.152.0/25/0
...
;; ANSWER SECTION:
www.amazon.com.         60 IN A 54.239.25.192
...

Et ce que voit le serveur faisant autorité ? On peut le savoir un faisant tourner tcpdump sur un serveur faisant autorité qu'on contrôle, mais il y a plus simple, le service edns-client-sub.net renvoie sous forme d'un objet JSON les options ECS reçues, ainsi que la géolocalisation. Ici, mon résolveur n'envoie pas ECS :

% dig +short -t txt edns-client-sub.net
"{'ecs':'False','ts':'1447875683.94','recursive':{'cc':'FR','srcip':'XX.YY.152.187','sport':'37512'}}"

Mais Google, lui, le fait (et heureusement, sinon j'aurais été géolocalisé en Belgique, où se trouve le serveur de Google utilisé) :

% dig @8.8.8.8 +short -t txt edns-client-sub.net 
"{'ecs_payload':{'family':'1','optcode':'0x08','cc':'FR','ip':'XX.YY.152.0','mask':'24','scope':'0'},
     'ecs':'True','ts':'1447875689.25','recursive':{'cc':'BE','srcip':'74.125.47.152','sport':'41735'}}"

Téléchargez le RFC 7871


L'article seul

RFC 7824: Privacy considerations for DHCPv6

Date de publication du RFC : Mai 2016
Auteur(s) du RFC : S. Krishnan (Ericsson), T. Mrugalski (ISC), S. Jiang (Huawei Technologies)
Pour information
Réalisé dans le cadre du groupe de travail IETF dhc
Première rédaction de cet article le 12 juin 2016


Le protocole DHCP sert à transmettre à une machine qui vient de se connecter au réseau, des informations utiles pour sa connexion. Il est surtout connu pour son utilisation avec IPv4 mais DHCP existe aussi pour IPv6 (il est normalisé dans le RFC 3315). Comme son équivalent IPv4, DHCP pour IPv6 pose un certain nombre de problèmes de vie privée, que ce RFC explore.

Il fait donc partie de la série de RFC développés après le RFC 6973 et, surtout, après les révélations de Snowden qui ont mené l'IETF à s'engager plus vigoureusement contre la surveillance massive. Ce RFC ne propose pas de solutions (elles sont décrites dans le RFC 7844), il décrit le problème.

Le problème fondamental est le même qu'en IPv4 (RFC 7819) : le client DHCP, lorsqu'il vient de se connecter à un réseau et émet des requêtes, publie des informations trop détaillées, dont certaines sont des véritables identificateurs stables (cf. section 2 de notre RFC), permettant au serveur DHCP, mais aussi à toute machine qui écoute le réseau, de suivre à la trace une machine donnée. Au contraire des solutions comme SLAAC, où le client est purement passif, DHCP impose au client d'annoncer son existence et de donner des informations. Bref, si vous avez déjà lu le RFC équivalent pour IPv4, le RFC 7819, vous n'apprendrez pas grand'chose de nouveau.

La section 3 du RFC donne une liste aussi complète que possible des options DHCPv6 qui peuvent servir à la surveillance. D'abord, l'adresse IP source. Bon, elle ne fait pas partie de DHCP à proprement parler et tout protocole va la publier, puisqu'elle apparait dans tous les paquets émis. (Dans le cas de DHCP, la requête du client est émise depuis une adresse locale au lien, link-local, celles qui commencent par fe80::.) Néanmoins, l'adresse IP source mérite une mention car certains mécanismes de génération d'une adresse IPv6 peuvent poser des problèmes de vie privée (cf. RFC 7721). Il faut donc utiliser des mécanismes comme ceux du RFC 4941 ou du RFC 7217.

L'exemple suivant est celui d'une option particulièrement dangereuse pour la vie privée, Client Identifier, qui envoie au serveur le DUID (DHCPv6 Unique Identifier, RFC 3315, section 9) du client. Comme son nom l'indique, il identifie chaque machine de manière unique et, par défaut, il est stable. La méthode la plus courante pour le générer est d'utiliser l'adresse MAC, elle-même un identificateur unique et stable. Même si on prend la précaution de changer l'adresse MAC, le DUID ne change pas. C'est donc un excellent moyen de suivre une machine, cassant complètement la sécurité de techniques comme celle du RFC 4941.

Également dangereuse, l'option Client FQDN (RFC 4704) qui envoie un FQDN.

Certaines options peuvent être moins clairement indiscrètes mais peuvent néanmoins révéler indirectement l'identité du client. C'est le cas de l'option Option Request qui dit au serveur quelles options on souhaiterait qu'il utilise. Cette liste de choix peut servir à distinguer entre plusieurs clients DHCP : toutes les fois où il y a un choix dans un protocole, il y a une possibilité de fingerprinting.

Certaines options n'envoient pas directement un identificateur unique mais envoient de l'information sur une classe à laquelle appartient la machine. Par exemple, les options Vendor Class et Vendor-specific Information (sections 22.16 et 22.17 du RFC 3315), ou encore l'option Client System Architecture (RFC 5970), indiquent le matériel et le logiciel du client.

On n'a vu ici que des options allant du client vers le serveur mais l'inverse existe aussi, et certaines options qu'un serveur peut envoyer sont révélatrices (par exemple Civic Location, RFC 4776). Mais les problèmes de vie privée du serveur sont moins graves que ceux du client et notre RFC passe donc rapidement (voir aussi la section 5.3).

En dehors des options DHCP, certains mécanismes utilisés dans le cadre de DHCP peuvent être bien indiscrets. C'est par exemple le cas de la demande d'adresses temporaires (RFC 3315, section 12), pourtant bien intentionnée. Le but était de pouvoir obtenir des adresses qui ne soient pas stables, pour minimiser justement les risques pour la vie privée. Le RFC détaille les nombreux problèmes et pièges que récèle ce mécanisme. Mais le principal problème est que la seule demande de ces adresses, visible par tout surveillant, est déjà très révélatrice ! Cela revient à sa promener avec une cagoule sur sa tête pour préserver sa vie privée.

Autre mécanisme qui peut être révélateur, la mise à jour du DNS que font certains serveurs DHCP. Si le nom utilisé est stable (cf. l'option Client FQDN mentionnée plus haut), tout surveillant ayant accès au DNS (c'est-à-dire tout le monde) pourra suivre les changements d'adresse IP de la machine, connaissant ainsi ses déplacements d'un réseau à l'autre.

Les stratégies d'allocation d'adresses du serveur DHCP peuvent également être dangereuses pour la vie privée. Le serveur DHCP dispose d'une certaine plage d'adresses. S'il alloue les adresses en commençant toujours par la plus basse adresse libre, les adresses attribuées vont être assez prévisibles, ce qui n'est en général pas bon pour la discrétion. (Et ce mécanisme, qui a certes l'avantage d'être simple et rapide, tend à concentrer les adresses allouées au début de la plage.) Autre possibilité, allouer des adresses fixes (le même client - identifié par une option comme Client Identifier - a toujours la même adresse IP). C'est évidemment très pratique pour l'administrateur du réseau local. Mais c'est la pire solution pour la vie privée, puisque cela oblige le client à divulguer son identité, et cela permet même aux serveurs extérieurs de le suivre à la trace lorsqu'il communique avec eux avec son adresse fixe. Pour la vie privée, la meilleure stratégie d'allocation est sans doute le tirage au sort parmi les adresses libres de la plage.

Maintenant qu'on a vu les vulnérabilités de DHCPv6, voyons ce qu'un attaquant peut en faire (section 5 du RFC). D'abord, il peut découvrir le type de machine chez le client (matériel et/ou logiciel), ce qui peut être utile, par exemple pour sélectionner une attaque spécifique à un système d'exploitation, ou bien, si le matériel/logiciel utilisé est rare, pour identifier un client particulier. Cette information sur le type de machine peut être trouvé dans l'adresse MAC (les premiers octets identifient le vendeur), dans les identificateurs dérivés de l'adresse MAC, ou dans les options comme Vendor Class.

L'espion peut également utiliser ces faiblesses de DHCPv6 pour identifier les réseaux visités précédemment (je n'en ai pas parlé plus haut, mais il existe une option qui indique la précédente adresse IP utilisée : elle est pratique pour obtenir une adresse stable, mais elle est indiscrète).

Plus généralement, le surveillant peut essayer de découvrir une identité stable, lui permettant de savoir combien de machines utilisent ce serveur DHCP, et lui permettant également de corréler deux machines sur deux réseaux, découvrant qu'il s'agit en fait de la même. Le DUID est particulièrement sensible ici.

Le surveillant peut ainsi suivre une machine, soit dans le temps (toutes ses activités en un réseau donné), soit dans l'espace (suivre à la trace un engin mobile).

Si le surveillant a les moyens d'une agence d'un État riche (par exemple si le surveillant est la NSA), il peut effectuer une surveillance massive très efficace (RFC 7258). Il est par exemple conceptuellement aisé de bâtir une liste de très nombreuses machines, en observant beaucoup de réseaux : les failles de sécurité de DHCPv6 citées dans ce RFC permettront de reconnaitre chaque machine individuelle. Ainsi, un organisme comme la NSA peut se faire une base de données permettant de répondre très vite à des questions du genre « où était 38:59:f9:7d:b6:47 la dernière fois qu'on l'a vu ? »

Enfin, la section 6 de notre RFC rappelle une triste réalité : en sécurité, il faut en général faire des compromis. Ici, le RFC note que toute authentification du client va à l'encontre du souhait de préserver la vie privée. Ce genre de choix (sécurité de son réseau, ou bien vie privée des utilisateurs) est bien embêtant pour l'administrateur système.


Téléchargez le RFC 7824


L'article seul

RFC 7873: Domain Name System (DNS) Cookies

Date de publication du RFC : Mai 2016
Auteur(s) du RFC : Donald Eastlake (Huawei), Mark Andrews (ISC)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 10 juin 2016


La grande majorité des requêtes DNS passent aujourd'hui sur UDP. Ce protocole ne fournit aucun mécanisme permettant de vérifier un tant soit peu l'adresse IP source de la requête. Contrairement à ce qui arrive avec TCP, il est trivial de mentir sur l'adresse IP source, sans être détecté. Cela permet des comportements négatifs, comme les attaques par réflexion. Ce nouveau RFC propose un mécanisme simple et léger pour s'assurer de l'adresse IP source du client : des petits gâteaux, les cookies.

Le principe est le même que pour les cookies de HTTP (décrits dans le RFC 6265) : le serveur DNS génère un nombre imprévisible qu'il transmet au client. Celui-ci renvoie ce nombre à chaque requête, prouvant qu'il recevait bien les réponses, et n'avait donc pas triché sur son adresse IP. (Notez une grosse différence avec les cookies du Web : ils changent quand l'adresse IP du client change et ils ne peuvent donc pas être utilisés pour suivre à la trace un client mobile.)

Bien sûr, une autre solution serait d'utiliser TCP (comme proposé dans le RFC 7766) ou bien DTLS (RFC en cours de discussion). Mais les petits gâteaux se veulent une solution moins radicale, de déploiement peut-être plus facile. Ils ne sont pas forcément utilisés seuls, ils peuvent être combinés avec d'autres mesures anti-usurpation, comme celles du RFC 5452.

Comme avec toute technique de sécurité, il faut regarder en détail les menaces auxquelles elle répond (section 2 du RFC). En usurpant l'adresse IP source, un méchant peut effectuer des attaques par déni de service, et il peut empoisonner un cache. Voyons ces deux cas.

D'abord, l'attaque par déni de service : en usurpant l'adresse IP source, on peut effectuer une attaque par réflexion. Dans ces attaques, le méchant envoie un paquet à un tiers, le réflecteur, en mentant sur son adresse IP source : le méchant met celle de la victime. Lorsque le réflecteur répondra, il enverra un message à la victime. Cette attaque est surtout intéressante lorsqu'elle est combinée avec l'amplification. Si la réponse est plus grosse que la question (ce qui est en général le cas avec le DNS), le méchant aura frappé la victime avec davantage d'octets que ce qu'il a lui-même envoyé.

Avec les cookies, cette attaque ne serait pas possible, la réponse à une requête ayant un cookie erroné étant plus petite que la question.

Notez que les cookies ne protègent pas contre un attaquant situé sur le chemin (on-path attacker) et qui peut lire le trafic réseau : voyant les paquets, il verra le cookie et pourra le transmettre. Les cookies n'empêchent donc pas toutes les attaques. D'autre part, si l'attaquant matraque directement le serveur DNS (sans réflexion), les cookies n'empêcheront pas l'attaque mais ils permettent de s'assurer que l'adresse IP source est exacte, ce qui autorisera de remonter à la source de l'attaque.

Le déni de service peut aussi viser le serveur DNS (au lieu de simplement l'utiliser comme réflecteur dans une attaque par réflexion). Chaque requête DNS va donner du travail au serveur et un nombre excessif peut dépasser ses capacités (comme dans l'attaque dafa888). Le problème est surtout aigu pour les serveurs récursifs, qui ont nettement plus à faire lorsqu'une requête arrive. Et ceux qui ont le plus de travail sont les serveurs récursifs qui valident avec DNSSEC : lors de la réception d'une réponse, il faut faire des calculs cryptographiques pour cette validation. Ces attaques par déni de service, au contraire de celles faites par réflexion, n'imposent pas de tricher sur l'adresse IP source mais, en le faisant, l'attaquant a l'avantage de rendre plus difficile son identification. Et cela peut lui permettre de faire traiter des requêtes qui seraient normalement refusées. Par exemple, si un résolveur n'accepte de requêtes que de son réseau (ce qui est la bonne pratique, cf. RFC 5358), et si on a oublié de filtrer en entrée les requêtes prétendant venir du réseau local, une attaque reste possible, en usurpant les adresses IP locales (une telle attaque est décrite dans l'exposé de Lars Nøring).

Après les attaques par déni de service, voyons les attaques visant à faire accepter de fausses réponses, ce qui peut mener à empoisonner le cache. Le principe est de répondre à la place du vrai serveur faisant autorité, en usurpant son adresse IP. Si le méchant est plus rapide, sa réponse peut, dans certains cas, être acceptée par un résolveur (qui la mettra peut-être dans son cache, ce qui sera encore pire). L'attaque Kaminsky est une version améliorée de cette vieille attaque. Les cookies sont une bonne protection contre ce genre d'attaques.

Après les attaques, voyons les défenses. Il n'y a pas que les cookies dans la vie. D'abord, il y a DNSSEC (RFC 4034 et RFC 4035). DNSSEC permet d'authentifier les réponses DNS, résolvant ainsi complètement les attaques par empoisonnement. Par contre, il ne résout pas les attaques par déni de service et, pire, les calculs cryptographiques qu'il impose et la taille des réponses plus élevées peuvent dans certains cas aggraver une partie de ces attaques. (Le RFC ne le note pas, mais DNSSEC a une autre limite, que les cookies résolvent : s'il empêche l'empoisonnement, il ne permet pas pour autant d'obtenir la réponse DNS correcte. DNSSEC protège bien du hameçonnage, beaucoup moins de la censure.)

Autre solution de sécurité, TSIG (RFC 2845). TSIG est meilleur que les cookies dans la mesure où il permet de vérifier cryptographiquement l'identité de la machine avec qui on parle DNS. Mais il est non trivial à déployer : reposant sur de la cryptographie symétrique, il impose un partage des clés préalable. Cela le limite à des usages entre parties qui se connaissent bien (typiquement pour sécuriser les transferts de zone). On note aussi que, comme DNSSEC, mais contrairement aux cookies, il nécessite des horloges synchronisées.

Pour résoudre ce problème de déployabilité, on peut envisager le mécanisme de distribution de clés TKEY (RFC 2930) ou bien passer à de la cryptographie asymétrique avec SIG(0) (RFC 2931). Mais aucune de ces deux techniques n'a connu de déploiement significatif.

Bref, les solutions de sécurité existantes ne résolvent pas réellement les problèmes que veulent traiter les cookies. Mais assez parlé de la « concurrence », venons-en aux cookies, comment marchent-ils (section 4 de notre RFC) ? Les cookies s'appuient sur EDNS (RFC 6891). Ils sont donc une option dans l'enregistrement EDNS. L'option cookie de EDNS porte le numéro 10. Comme toutes les options EDNS, elle est codée en TLV : le type 10, la longueur et la valeur, qui comprend un ou deux cookies. S'il n'y a que le cookie client, la longueur est fixe, de 8 octets. S'il y a en plus le cookie serveur, la longueur peut aller de 16 à 40 octets.

Le cookie client est normalement le résultat d'une fonction non-prévisible des adresses IP du client et du serveur, et d'un secret connu du client (par exemple, généré aléatoirement en suivant le RFC 4086, et changé de temps en temps). Cette fonction est, par exemple, une condensation mais le client prend ce qu'il veut : il est le seul à avoir besoin d'interpréter ses propres cookies, ils sont opaques pour tout autre acteur. L'adresse IP du client est incluse dans les paramètres de la fonction notamment pour des raisons de vie privée : empêcher le client d'être reconnu s'il change d'adresse IP (le but de nos cookies DNS n'est pas du tout le même que celui des fameux cookies du Web).

Le cookie serveur prend comme paramètres de sa propre fonction (qui n'est pas forcément la même) l'adresse IP de son client, un secret (mêmes propriétés que chez le client), et le cookie du client (et pourquoi le cookie client ne se sert pas du cookie serveur ? Voyez la section 6.) Voilà comment on fabrique les gâteaux.

Mais comment les utilise-t-on ? La section 5 l'explique. Le client qui gère les gâteaux fabrique un cookie client qu'il envoie dans ses requêtes DNS. S'il n'a jamais parlé au serveur, il envoie une option cookie de forme courte, ne comprenant qu'un seul cookie, le sien. S'il a déjà parlé au serveur et mémorisé le cookie de celui-ci, il fabrique une option EDNS cookie longue, incluant les deux cookies.

Si le serveur ne comprend rien aux cookies, il ne met pas l'option dans la réponse, et le client sait alors qu'il s'agit d'un vieux serveur, sans gestion des cookies. (Ou bien c'était une attaque par repli ; le cas ne semble pas traité dans le RFC, la solution est sans doute que le client mémorise les serveurs cookie-capable, pour détecter ces attaques.)

Si, par contre, le serveur gère les cookies, il y a cinq possibilités :

  • Si c'est le client qui est vieux, il n'envoie pas de cookie. Le serveur répond alors comme aujourd'hui. Les cookies ne posent donc pas de problème d'interopérabilité : vieux et récents logiciels peuvent cohabiter.
  • Si l'option EDNS cookie est présente, mais invalide (longueur inférieure à 8 octets, par exemple), le serveur répond FORMERR (FORmat ERRor).
  • Si la requête ne contient qu'un cookie client (client qui ne connaissait pas encore ce serveur), le serveur décide alors, selon sa politique à lui, de laisser tomber la requête (c'est violent, et cela implique de configurer le serveur avec les cookies des clients), d'envoyer un code d'erreur BADCOOKIE (valeur 23), incluant le cookie du serveur, ou enfin de répondre normalement, en ajoutant son cookie. En effet, dans ce cas, le client n'est pas « authentifié ». On n'a pas vérifié son adresse IP source. Il peut donc être justifié de ne pas donner la réponse tout de suite (le BADCOOKIE) ou bien, par exemple, de limiter le trafic de ce client (comme on le fait aujourd'hui, avant les cookies, puisqu'on n'est jamais sûr de l'adresse IP du client).
  • Il y a deux cookies dans la requête mais le cookie serveur est incorrect, par exemple parce que le secret utilisé par le serveur a changé. C'est parfaitement normal et cela n'indique, ni une erreur, ni une attaque, simplement qu'on ne peut pas authentifier le client. On répond donc comme dans le cas précédent (avec trois choix, dont seuls les deux derniers sont réalistes).
  • Il y a deux cookies dans la requête et le cookie serveur est correct. On a donc une certitude raisonnable que le client n'a pas usurpé son adresse IP (puisqu'il a reçu le bon cookie du serveur) et on va donc lui répondre. Les mesures de méfiance comme la limitation de trafic peuvent être débrayées pour cette requête.

Lorsqu'il reçoit une réponse, le client doit mémoriser le cookie du serveur. C'est particulièrement important la première fois, lorsque le client n'est pas encore authentifié. Si la réponse était BADCOOKIE, cela veut dire qu'on a affaire à un serveur grognon qui ne veut pas répondre sans qu'on lui donne un cookie correct : on retransmet alors la requête, cette fois en incluant le cookie transmis par le serveur.

Voilà, c'est tout. Avec ce système, on a une authentification légère et simple de l'adresse IP du client. Dans la vraie vie, il y aura peut-être quelques problèmes pratiques, que couvre la section 6 de notre RFC. Par exemple, si le client est derrière du NAT (RFC 3022), un méchant situé sur le même réseau local que lui pourrait faire une requête au serveur, obtenir le cookie du serveur et envoyer ensuite des requêtes en usurpant l'adresse IP locale du client légitime. Le serveur ne peut pas distinguer ces deux clients, le bon et le méchant. C'est pour cela que le cookie serveur inclut dans les paramètres de sa fonction le cookie du client. Ainsi, les deux machines, la gentille et la méchante auront des cookies serveur différents.

Un problème du même genre (plusieurs machines derrière une même adresse IP) pourrait survenir côté serveur, par exemple en raison de l'anycast. Mais on ne peut pas appliquer la même solution : si le cookie serveur dépend du cookie client et le cookie client du cookie serveur, on a une boucle sans fin. Le serveur doit donc se débrouiller : soit avoir le même secret (et donc les mêmes cookies) sur toutes les machines (c'est l'approche la plus simple, et c'est celle recommandée par le RFC), soit faire en sorte qu'un client donné arrive toujours sur la même machine.

D'autres considérations pratiques figurent en section 7, notamment sur le remplacement d'un secret (ce qui invalidera les cookies précédemment distribués).

Et quelques discussions sur la sécurité, pour finir (section 9 du RFC). L'« authentification » fournie par les cookies est faible : elle ne protège pas contre un attaquant situé sur le chemin de communication entre client et serveur, lorsqu'il peut lire le trafic. Dans ce cas, l'attaquant a en effet accès au cookie et peut facilement le rejouer. Par exemple, si on est connecté à un réseau Wi-Fi public sans sécurité (pas de WPA), n'importe quel client du même réseau peut voir passer les cookies. Néanmoins, les cookies réduisent quand même sérieusement l'ampleur du problème. Une attaque (l'usurpation d'adresse IP) que tout l'Internet pouvait faire est maintenant restreinte à un sous-ensemble de l'Internet. Si cela est encore trop, il faut passer à une sécurisation cryptographique comme celle que fournit le RFC 7858.

L'algorithme utilisé pour calculer les cookies est évidemment crucial. Il n'a pas besoin d'être normalisé, puisque seule la machine qui émet le cookie original a besoin de le comprendre. Mais il doit garantir des cookies très difficiles à prévoir par un attaquant. On peut par exemple utiliser SHA-256 (RFC 6234, mais il n'y a pas forcément besoin de cryptographie top canon, les cookies n'étant qu'une authentification faible, de toute façon).

Des exemples d'algorithmes figurent dans les annexes A et B. Pour le client DNS, un algorithme simple serait d'appliquer la fonction simple et rapide FNV-64 à la concaténation des adresses IP du client et du serveur, et du secret. Un algorithme plus compliqué, mais plus sûr, serait de remplacer FNV par SHA-256, plus coûteux.

Pour le serveur, l'algorithme simple serait un FNV-64 de la concaténation de l'adresse IP du client, du cookie du client, et du secret. Pour l'algorithme compliqué, on peut tirer profit de la longueur plus grande du cookie serveur pour y mettre davantage d'informations : par exemple, huit octets calculés comme dans l'algorithme simple suivis de l'heure de génération du cookie (pour détecter plus facilement les vieux cookies, avant même toute opération cryptographique).

Et les mises en œuvre ? Les cookies sont gérés par BIND à partir de la version 9.11 (pas encore officiellement publiée). Ils sont activés par défaut. Et Wireshark sait les afficher. Ici, un client nouveau (il ne connait pas encore le cookie serveur) :


No.     Time           Source                Destination           Protocol Length Info
      1 0.000000       192.168.2.9           192.168.2.7           DNS      97     Standard query 0x0000 SOA foobar.example OPT
...
Domain Name System (query)
...
    Additional records
        <Root>: type OPT
...
        Data length: 12
            Option: COOKIE
                Option Code: COOKIE (10)
                Option Length: 8
                Option Data: fb40ce9a68a6f1f0
                Client Cookie: fb40ce9a68a6f1f0
                Server Cookie: <MISSING>


No.     Time           Source                Destination           Protocol Length Info
      2 0.003910       192.168.2.7           192.168.2.9           DNS      200    Standard query response 0x0000 SOA foobar.example SOA ns1.foobar.example NS ns1.nic.fr NS ns2.nic.fr OPT
...
      Additional records
        <Root>: type OPT
...
        Data length: 28
            Option: COOKIE
                Option Code: COOKIE (10)
                Option Length: 24
                Option Data: fb40ce9a68a6f1f0727e7501575acc5977ced0351ad20d56
                Client Cookie: fb40ce9a68a6f1f0
                Server Cookie: 727e7501575acc5977ced0351ad20d56

L'algorithme de condensation peut être choisi mais, apparemment, uniquement à la compilation (avec --with-cc-alg=ALGALG vaut aes|sha1|sha256).

Le dig livré avec cette version de BIND peut passer des cookies :

% dig +cookie @192.168.2.7 foobar.example
...
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
; COOKIE: 51648e4b14ad9db8eb0d28c7575acbdde8f541a0cb52e2c2 (good)
;; QUESTION SECTION:
;foobar.example.                IN A
...
     

Pour les programmeurs en Go, la bibliothèque Go DNS gère désormais les cookies. Un exemple de code Go pour les envoyer :

     
	m := new(dns.Msg)
	m.Question = make([]dns.Question, 1)
	c := new(dns.Client)
	m.Question[0] = dns.Question{zone, dns.TypeSOA, dns.ClassINET}
	o := new(dns.OPT)
	o.Hdr.Name = "."
	o.Hdr.Rrtype = dns.TypeOPT
	o.Hdr.Class = 4096
	e := new(dns.EDNS0_COOKIE)
	e.Code = dns.EDNS0COOKIE
	e.Cookie = "fb40ce9a68a6f1f0"
	o.Option = append(o.Option, e)
	m.Extra = make([]dns.RR, 1)
	m.Extra[0] = o

Téléchargez le RFC 7873


L'article seul

RFC 7799: Active and Passive Metrics and Methods (with Hybrid Types In-Between)

Date de publication du RFC : Mai 2016
Auteur(s) du RFC : A. Morton (AT&T Labs)
Pour information
Réalisé dans le cadre du groupe de travail IETF ippm
Première rédaction de cet article le 30 mai 2016


Dans le monde de la métrologie, il existe deux classes de mesures effectuées sur l'Internet : les mesures actives et les mesures passives. La signification de ces termes semble assez intuitive mais ce nouveau RFC fournit des définitions rigoureuses, qui n'étaient pas encore publiées. (Il y a aussi des mesures hybrides.)

Cela fait pourtant de très nombreuses années que ces deux termes sont largement utilisés. Par exemple, en 2000 s'est tenue une conférence « Passive and Active Measurement (PAM) ». Et les termes étaient certainement plus anciens.

En première approximation, on peut caractériser ces deux classes ainsi (section 1 du RFC) :

  • Une mesure active nécessite un envoi de paquets dédiés à cette mesure.
  • Une mesure passive ne dépend que des paquets qui seraient envoyés de toute façon, même si la mesure n'avait pas lieu.

Du point de vue des outils, on peut donc noter que les ultra-traditionnels ping et traceroute font des mesures actives et que tcpdump permet des mesures passives.

Mais, les choses étant plus compliquées dans la vraie vie des vrais réseaux, notre RFC va un peu plus loin que cela. Sa section 3 définit plus précisement les termes. Elle s'appuie sur des RFC précédents comme les RFC 2330 et RFC 6390 qui définissaient, par exemple, la notion de métrique (une grandeur qu'on mesure), ou comme le RFC 7011, qui définissait la notion de point d'observation. On s'appuie aussi sur des documents qui ne sont pas des RFC comme la norme UIT Y.1540 qui définit la notion de « population [de paquets] qui nous intéresse » (stream of interest) ou comme la norme UIT Y.1731.

Notez que les adjectifs « actif » et « passif » peuvent s'appliquer aux méthodes de mesure ou bien aux métriques.

Armé de ces définitions, on peut dire que les méthodes de mesure actives ont les caractéristiques suivantes :

  • La population de paquets qui nous intéresse est générée (synthétisée). Parfois un autre flux de paquets est généré, même si leur sort ne nous intéresse pas directement, par exemple pour générer de la charge.
  • Les paquets générés ont un contenu qui est spécifique à la mesure, qui n'a pas d'intérêt autrement. C'est par exemple le numéro de séquence dans les paquets ICMP (RFC 792) que génère ping, numéros qui permettent de faire correspondre une réponse à une question.
  • Source et destination des paquets sont connus a priori.
  • D'ailleurs, toutes les caractéristiques de la population sont connues à l'avance, ce qui facilite nettement l'observation. Parfois, certaines caractéristiques seront changées en route (comme le champ TTL dans l'en-tête IPv4).

Comme la mesure active introduit du trafic réseau qui n'existerait pas sans elle, elle perturbe le réseau qu'on veut mesurer. Un des défis importants des mesures actives est de minimiser cette perturbation ou, au minimum, de pouvoir quantifier cette perturbation pour l'indiquer comme marge d'erreur dans les résultats (section 4.1).

Une métrique active est simplement une métrique dont la définition inclut des méthodes actives. Par exemple, le type des paquets qu'on a injecté dans le réseau.

Les méthodes passives, par contre, ont ces propriétés :

  • Elles sont fondées sur l'observation de paquets non modifiés et non perturbés. Une méthode passive ne laisse aucune trace sur le réseau.
  • Elles ne sont donc utiles que s'il existe déjà des paquets intéressants, puisqu'elles n'en créent pas et n'en modifient pas.

Il faut faire attention en observant les paquets : comme on ne choisit pas leurs caractéristiques, on risque de ne pas voir le vrai phénomène, car on n'observait que le phénomène supposé. (Il m'est arrivé d'utiliser tcpdump pour observer un trafic LDAP et de filtrer sur l'adresse du serveur LDAP. Je ne comprenais pas pourquoi aucun trafic n'était visible. En fait, je ne capturais que les paquets IPv4 alors que le trafic se faisait en IPv6.)

Une observation passive peut se faire en un seul point, ou en plusieurs. Un exemple d'observation passive est ce que fait un routeur IPFIX (RFC 7011).

Une métrique passive est une métrique fondée uniquement sur l'observation passive. Par exemple, le temps de trajet entre deux points peut être formalisée dans une métrique passive : on observe le paquet à un point et à l'autre, et on en déduit le temps de son voyage.

Évidemment, dans le monde réel, les classifications ne sont pas toujours très simples. Par exemple, il existe des méthodes hybrides. Les « hybrides de type I » partent d'un flux de paquets existant mais le modifient, ou bien modifient le traitement qu'il subit. Par exemple, si on observe un flux existant mais qu'on envoie en même temps des données dans le réseau pour le charger, on est en présence d'une méthode hybride de type I. Les métriques spatiales du RFC 5644 sont un cas de métriques hybrides.

Et les hybrides de type II ? Le terme indique les méthodes où il y a plusieurs populations intéressantes générées activement (et d'autres qu'on observe passivement).

La section 4 de notre RFC discute de certains problèmes de métrologie et compare l'effet des méthodes et métriques actives ou passives. Par exemple, si on veut mesurer la capacité d'un lien, une méthode active serait de tenter d'envoyer le plus de données possible, une méthode passive d'observer le trafic et de regarder le débit maximum atteint. La première méthode va remplir le tuyau, gênant les applications en cours. La seconde risque de sous-estimer la capacité (si les machines sont lentes, elles peuvent ne pas réussir à remplir le tuyau.)

Au passage, l'importance des mesures est telle que l'IETF envisage un mécanisme de mesure instrumentant les paquets eux-mêmes : c'est l'option IPv6 PDM (Performance and Diagnostic Measurements, actuellement à l'état de projet), qui consiste à ajouter un nouvel en-tête d'extension aux paquets IP pour y noter les informations nécessaires aux mesures. Les mesures ainsi faites seraient plutôt des hybrides de type I. (On ajoute des données à des paquets existants.)


Téléchargez le RFC 7799


L'article seul

Valider qu'un contrat Ethereum est bien ce qu'il prétend être

Première rédaction de cet article le 29 mai 2016


La chaîne de blocs Ethereum permet bien plus que de gérer de l'argent : elle autorise la création de programmes (appelés contrats) qui peuvent être invoqués par des utilisateurs, qui envoient leur argent au contrat, espérant que celui-ci va bien faire ce qui est promis. Mais comment le vérifier ?

Les contrats (le terme marketing est smart contracts) sont des programmes informatiques : dans le cas le plus courant, ils sont écrits par un programmeur dans un langage « de haut niveau » puis compilé dans le langage machine d'Ethereum.

Le contrat, comme son nom l'indique, est censé faire quelque chose. Imaginons par exemple un serveur de clés PGP dans la chaîne de blocs : il est censé recevoir des clés, les stocker, et les restituer à la demande. Les gens qui stockent des clés paient (en ethers) pour cela. Il est légitime de se demander « est-ce que ce programme va bien faire ce qui est prévu, ou bien va-t-il soudainement détruire toutes les clés, et j'aurais alors dépensé mes ethers pour rien ? » C'est d'autant plus critique qu'il existe des contrats qui brassent des sommes d'argent importantes. Les utilisateurs se fient typiquement à la documentation publique de ce contrat, alors qu'on ne peut pas être sûr qu'elle corresponde au contrat réel (soit par suite d'une erreur, soit par suite d'une volonté délibérée). Le code s'exécute dans la chaîne de blocs, sans intervention humaine (c'est le but des smart contracts). Comment valider ce code ? C'est à mon avis le gros problème de ces « contrats intelligents ».

Arrivé à ce stade, mes lecteurs partisans du logiciel libre ont déjà une réponse : on distribue le code source (rappelez-vous qu'un contrat n'est qu'un programme), des gens le liront et le vérifieront. Si suffisamment de gens compétents le lisent, le contrat est vérifié, on peut lui faire confiance. Mais c'est très insuffisant.

Déjà, analyser un code source complexe peut être difficile (on peut espérer que les auteurs de contrats, voulant inspirer confiance, essaieront d'écrire du code clair et lisible). Il est clair que la disponibilité du code source est un pré-requis : s'il n'est pas public, il ne faut jamais envoyer de l'argent à ce contrat. Seulement, ça ne suffit pas : ce qui est stocké et exécuté sur la blockchain, c'est du langage machine d'Ethereum (à peu près du même niveau d'abstraction que le langage des processeurs matériels). Ça, c'est vraiment dur à valider. Pour donner un exemple, voici un contrat très très simple écrit en Solidity, il stocke une valeur et permet de la récupérer :

contract SimpleStorage {
  uint storedData;

  function set(uint x) {
    storedData = x;
  }

  function get() constant returns (uint retVal) {
    return storedData;
  }
}

Il est trivial à analyser et à vérifier. Seulement, ce n'est pas ça qu'exécute la chaîne de blocs, mais un code machine. Voici sa version en assembleur, produite par l'option --asm du compilateur solc : storage.asm (je ne l'ai pas incluse dans cet article, elle est trop longue). Mais ce n'est pas non plus ce que stocke la chaîne de blocs, en fait, on a juste les opcodes, sans les jolis commentaires et tout :

% solc --opcodes storage.sol 

======= SimpleStorage =======
Opcodes: 
PUSH1 0x60 PUSH1 0x40 MSTORE PUSH1 0x97 DUP1 PUSH1 0x10 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN PUSH1 0x60 PUSH1 0x40 MSTORE PUSH1 0x0 CALLDATALOAD PUSH29 0x100000000000000000000000000000000000000000000000000000000 SWAP1 DIV DUP1 PUSH4 0x60FE47B1 EQ PUSH1 0x41 JUMPI DUP1 PUSH4 0x6D4CE63C EQ PUSH1 0x57 JUMPI PUSH1 0x3F JUMP JUMPDEST STOP JUMPDEST PUSH1 0x55 PUSH1 0x4 DUP1 DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP2 SWAP1 POP POP PUSH1 0x78 JUMP JUMPDEST STOP JUMPDEST PUSH1 0x62 PUSH1 0x4 DUP1 POP POP PUSH1 0x86 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST DUP1 PUSH1 0x0 PUSH1 0x0 POP DUP2 SWAP1 SSTORE POP JUMPDEST POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x0 PUSH1 0x0 POP SLOAD SWAP1 POP PUSH1 0x94 JUMP JUMPDEST SWAP1 JUMP 
    

À noter que c'était sans l'optimisation. Celle-ci réduit sérieusement le nombre d'instructions :

% solc --opcodes storage.sol |wc -w 
137
% solc --opcodes --optimize storage.sol |wc -w
73

Si vous voulez observer ce contrat en ligne, il a été déployé sur la chaîne de blocs, à l'adresse 0x48b4cb193b587c6f2dab1a9123a7bd5e7d490ced (et ça m'a coûté 69 558 unités d'essence, payées 0,00139116 ethers). Le résultat est visible sur les explorateurs de la chaîne, comme etherscan.io, Etherchain ou ether.camp. Sur Etherscan.io, la fonction Switch To Opcodes View vous permet de passer des instructions en assembleur au code binaire. Sur Ether.camp, ce sont les liens code et asm. Au passage, si vous voulez interagir avec ce contrat (après l'avoir vérifié !), les instructions en console sont :

storage = eth.contract([{"constant":false,"inputs":[{"name":"x","type":"uint256"}],"name":"set","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"type":"function"}]).at("0x48b4cb193b587c6f2dab1a9123a7bd5e7d490ced")

Et cela permet de stocker et de récupérer des valeurs depuis la console de geth (cela vous coûtera 26 563 unités d'essence, soit, aujourd'hui, 0,00053126 ether) :

> storage.set(42,{from:eth.accounts[0]})
"0x36084ff3d5bf0235326277b2d5ba30b1964f6d8b3720b9aef0578faeaeb2678b"
...
> storage.get()
42

Quittons ce détour technique et revenons à la question de fond, la vérification. Cette préoccupation est relativement fréquente dans le monde Ethereum. Il y a quelques mois, elle ne suscitait guère d'intérêt. Il y a plusieurs solutions pour vérifier un contrat avant de lui confier ses précieux ethers :

  • On compile le code source soi-même et on vérifie que le binaire correspond. S'il correspond, on peut être rassuré : sauf bogue/malhonnêteté du compilateur, le contrat fait bien ce que dit le code source. C'est ainsi que fonctionnent les services de vérification de code des explorateurs (comme Etherscan ou Etherchain), ce qui ajoute d'ailleurs une confiance supplémentaire : il faut faire confiance à ce service.
  • On vérifie directement le code machine, par rétro-ingénierie, comme le font les reverseurs qui analysent le logiciel malveillant (pour lequel ils n'ont évidemment pas les sources). C'est très sûr mais très complexe, puisqu'on travaille sur du matériau de très bas niveau. À ma connaissance, personne n'a encore développé cette compétence mais cela se fera sans doute, étant donné l'inquiétude sur la sécurité des contrats. Cela fera de beaux articles de blog :-)
  • On copie le code machine et on fait tourner le contrat dans une chaîne de blocs de test (comme Morden), en utilisant ce contrat comme une boîte noire : on n'essaie pas de comprendre le code, mais on voit s'il répond bien aux fonctions qu'on appelle. Cette méthode est plus simple mais limitée : si le contrat est complexe, on aura du mal à tester tous les cas. Et, même avec un contrat trivial comme celui donné en exemple plus haut, on ne peut pas ainsi découvrir si certaines valeurs (comme 42...) ne vont pas activer la porte dérobée.
  • Il y a aussi cette technique, spécifique à Solidity, que je n'ai pas encore creusée.

Dans le cas de la première méthode, la recompilation, si le binaire obtenu correspond à celui déployé, on est tranquille. Mais s'il ne correspond pas ? Est-ce que cela veut dire que quelqu'un essaie de nous tromper ? Non, car le code obtenu dépend du compilateur, et de sa version exacte. Si le binaire correspond, on est rassuré, s'il ne correspond pas, on n'est pas plus avancé. Et le problème devient plus compliqué avec le temps (certains contrats peuvent être éternels) : comment on retrouve le compilateur utilisé deux ans après ? Il faudrait que le code soit étiqueté avec la version du compilateur, ce qui n'est pas le cas, et qu'on dispose d'une copie de cet ancien compilateur.

Bref, il n'y a pas de solution parfaite aujourd'hui. Lorsque vous mettez de l'argent dans un contrat sérieux, vous avez forcément une incertitude. Vous pouvez la réduire en regardant les vérifications faites par d'autres. Pour The DAO, le code source est en ligne. Il existe une documentation sur cette vérification et des détails. Et le code a été vérifié par certains explorateurs, comme Etherscan.

Et, pour finir, une copie d'écran d'un cas où ça a marché, la vérification du contrat montré plus haut :


L'article seul

RFC 7841: On RFC Streams, Headers, and Boilerplate

Date de publication du RFC : Mai 2016
Auteur(s) du RFC : J. Halpern, L. Daigle, O. Kolkman (Internet Society), Internet Architecture Board (IAB)
Pour information
Première rédaction de cet article le 29 mai 2016


Les textes sacrés de l'Internet, les RFC, comprennent un certain nombre d'éléments obligatoires, souvent collectivement appelés boilerplates et comprenant, par exemple, les conditions légales d'utilisation du RFC. Ce RFC 7841 écrit par l'IAB les décrit et les précise.

Les éléments utilisés autrefois comme Category: Experimental ne suffisaient pas à transporter toute l'information nécessaire. Depuis la formalisation des voies dans le RFC 4844, les différents circuits de publication des RFC, il était devenu crucial de déterminer facilement de quelle voie venait un RFC. (Les anciens RFC étaient tous marqués comme provenant d'un mystérieux Network Working Group, cf. RFC 3.) Cela avait été fait dans le RFC 5741, que notre RFC 7841 remplace.

Donc, dans sa section 2, notre méta-RFC rappelle que, non seulement tous les RFC ne sont pas des normes (RFC 1796), mais que tous ne sont pas des documents issus de l'IETF, qui n'est qu'une voie parmi d'autres (quoique la plus prolifique). Ainsi, un RFC peut très bien être publié sans que l'IETF n'aie pu donner un avis sur des points comme la sécurité ou le contrôle de congestion, par le biais de procédures comme le IETF Last Call ou l'examen par l'IESG. En termes para-légaux, disons que l'IETF refuse toute responsabilité pour les RFC non-IETF. (À noter que, si tous les RFC ne sont pas des normes IETF, en revanche, toutes les normes IETF sont publiées sous forme d'un RFC.) Si vous tenez à tout connaitre sur les processus de l'IETF, et la publication des RFC, consultez les RFC 2026, RFC 4844, RFC 5742, RFC 6410 et RFC 7127.

La section 3 liste les éléments qui forment la structure d'un RFC. Leur forme exacte, plus susceptible de changer, figure sur une page Web séparée. Il y a l'en-tête général (section 3.1) qui, pour notre RFC, est :

Internet Architecture Board (IAB)                        J. Halpern, Ed.
Request for Comments: 7841
Obsoletes: 5741                                           L. Daigle, Ed.
Updates: 7322
Category: Informational                                  O. Kolkman, Ed.
ISSN: 2070-1721
                                             Internet Architecture Board
                                                                   (IAB)
                                                              April 2016

indiquant qu'il est issu de la voie IAB, qu'il porte le numéro 7841, qu'il est de la catégorie « Pour information » (les catégories sont décrites dans le RFC 2026), etc. Les autres voies sont IETF, IRTF et « contribution indépendante ».

Après cet en-tête vient un paragraphe (section 3.2) qui décrit clairement la voie par laquelle ce RFC est passé. Par exemple, pour une soumission indépendante, le texte (qui est sujet à évolution, en synchronisation avec la définition des voies) actuel est « This is a contribution to the RFC Series, independently of any other RFC stream. The RFC Editor has chosen to publish this document at its discretion and makes no statement about its value for implementation or deployment. ».

Cet en-tête indique également les relations de ce RFC avec d'autres RFC. Par exemple, notre RFC 7841 indique :

Obsoletes: 5741

car il remplace le RFC 5741, qui n'a désormais plus qu'un un intérêt historique.

Je ne reprends pas ici tous les éléments, qui sont décrits dans cette section 3. Notons simplement le copyright, issu des RFC 5378, RFC 3979 et RFC 4879, et l'ISSN des RFC, 2070-1721. Pour le reste du RFC, il faut utiliser le guide stylistique du RFC 7322.

Notre RFC ne décrit que les principes gouvernant ce boilerplate. Les détails, qui sont changeants, sont désormais sur une page Web dédiée à l'IAB. C'est l'un des gros changements depuis le RFC 5741. L'annexe A de notre RFC contient l'état initial de ces textes. Ainsi, un RFC de l'IETF sur le chemin des normes commencera par « This is an Internet Standards Track document. This document is a product of the Internet Engineering Task Force (IETF). It represents the consensus of the IETF community. It has received public review and has been approved for publication by the Internet Engineering Steering Group (IESG). »

Outre ce déplacement du texte effectif depuis le RFC (document rigide et stable) vers une page Web, le principal changement depuis le RFC 5741 est l'allègement de certaines règles de présentation, pour tenir compte du projet de réforme du format de publication des RFC (qui, dans le futur, ne seront plus publiés uniquement sous forme de texte brut).


Téléchargez le RFC 7841


L'article seul

RFC 7844: Anonymity profile for DHCP clients

Date de publication du RFC : Mai 2016
Auteur(s) du RFC : C. Huitema (Microsoft), T. Mrugalski (ISC), S. Krishnan (Ericsson)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dhc
Première rédaction de cet article le 29 mai 2016


Vous vous connectez à un réseau IP, vous obtenez la configuration via un serveur DHCP, mais vous voulez rester relativement anonyme, et vous n'avez pas envie que le serveur, ou que des indiscrets qui écoutent, sachent qui vous êtes ? C'est là que ce RFC est utile en proposant un profil de requête DHCP qui envoie le moins d'informations possibles.

C'est que DHCP, par défaut, est trop bavard. Comme l'expliquent bien les RFC 7819 et RFC 7824, une requête DHCP comporte pas mal de champs et d'options qui peuvent contenir des identificateurs stables, qui permettront au serveur DHCP, ou à des espions qui écoutent le trafic, de reconnaitre une machine. Un exemple d'une telle surveillance est celle effectuée dans les aéroports canadiens mais ce n'est certainement pas la seule. Un des buts de cette surveillance peut être, pour quelqu'un qui peut écouter en plusieurs endroits, de suivre à la trace les utilisateurs en déplacement, en reconnaissant les requêtes spécifiques de leur ordinateur portable ou smartphone. Bien sûr, DHCP n'est pas le seul outil pour faire cela. L'identificateur stable le plus évident est l'adresse MAC, mais c'est aussi le plus connu : les utilisateurs soucieux de leur vie privée prennent souvent des mesures pour la changer souvent. Mais peu de gens pensent aux risques pour la vie privée associés à DHCP. Ceux-ci sont désormais bien établis, et documentés dans les RFC 7819 et RFC 7824.

Mais pourquoi en faire un RFC, une norme ? Après tout, on pourrait se contenter d'attendre que les différents fournisseurs de clients DHCP minimisent les informations envoyées. Le problème est qu'ils risquent de le faire légèrement différemment (certains supprimant une option de la requête que d'autres garderont, par exemple). Cette différence permettra une différenciation des utilisateurs, justement ce qu'on veut éviter (cf. la section 2.4). Au contraire, si tout le monde met en œuvre ce profil standard, tous les clients seront pareils, ce qui protège nettement mieux leur anonymat.

La section 2 de notre RFC détaille certains problèmes concrets. J'ai dit plus haut que l'identificateur le plus évident pour suivre une machine à la trace était l'adresse MAC. En Wi-Fi, n'importe qui peut la voir, même si le réseau utilise le chiffrement, puisqu'elle est dans la partie en clair du paquet. En la corrélant avec d'autres informations qu'on retrouve ailleurs, on peut remonter à l'individu qui utilise la machine en question. Le danger est donc réel.

La contre-mesure évidente est de changer l'adresse MAC, en la remplaçant par une valeur aléatoire, par exemple avec macchanger. Cela a fait d'ailleurs l'objets de tests en grand à la réunion IETF de Honolulu, ainsi que dans d'autres réunions. Il n'y a pas de norme technique décrivant cette « aléatoirisation ». Parmi les choix possibles :

  • Un tirage au hasard à chaque connexion à un réseau,
  • Un tirage au hasard pour chaque nouveau réseau mais on garde toujours la même adresse MAC pour un réseau donné,
  • Des changements de temps en temps, si on reste connecté sur des longues périodes. (Cela ne marchera pas en Wi-Fi où le changement d'adresse MAC nécessitera déconnexion/reconnexion donc peut-être changement d'adresse IP donc coupure des connexions TCP en cours.) Cette astuce n'est même pas forcément efficace : un observateur peut facilement noter le départ d'une machine et l'arrivée immédiate d'une autre, corrélant ces deux événements.

En tout cas, un changement de l'adresse MAC est nécessaire, sinon, le profil DHCP « anonyme » de ce RFC aura une utilité limitée. Mais, inversement, attention à ne pas se contenter de changer un seul identificateur. Si on change d'adresse MAC en gardant tout le reste, la tâche d'un surveillant est trop facile, et il déduira sans problème la nouvelle adresse MAC. Il faut changer l'adresse MAC, l'adresse IP et les identificateurs DHCP en même temps.

Notre RFC mentionne qu'il existe des techniques de plus bas niveau (couche 1) qui peuvent défaire tout le travail de protection de la vie privée. Par exemple, certains récepteurs radio permettent d'identifier des particularités d'un émetteur physique et, en observant le trafic Wi-Fi, on peut ainsi identifier une machine donnée quels que soient ses efforts pour ne pas laisser de traces (cf. « Wireless Device Identification with Radiometric Signatures »). Heureusement, tous les surveillants n'ont pas les moyens de placer ce genre de récepteurs. S'ils doivent se contenter de capter le trafic, sans pouvoir analyser le signal physique, les précautions recommandées plus loin dans ce RFC vont suffire.

Le profil d'« anonymat » décrit dans ce RFC n'est pas explicite. On ne peut pas distinguer les clients DHCP qui appliquent ce profil de ceux qui n'ont simplement pas mis en œuvre les options trop révélatrices. Il y avait eu une discussion à l'IETF sur une mention explicite, un bit dans la requête disant « je veux être anonyme et ne vous étonnez donc pas si je ne publie pas grand'chose ». Cette idée avait été rejetée avec l'idée que proclamer publiquement qu'on veut être anonyme peut être au contraire un excellent moyen de se distinguer, comme de sortir dans la rue avec un masque de Guy Fawkes. Au contraire, le vrai anonymat s'obtient en ne faisant rien de trop extraordinaire.

Enfin, comme toute mesure de sécurité, celles qui préservent la vie privée ont des inconvénients. La plus évidente est que l'« anonymat » va rendre plus difficile la gestion des réseaux. Si l'administrateur réseaux suit les machines sur le réseau local en les identifiant par leurs adresses MAC, il devra s'adapter. D'autre part, il y a un conflit entre la protection de la vie privée, qui requiert des changements fréquents d'adresse MAC, et le bon fonctionnement du réseau, qui demande qu'on limite le trafic DHCP (mais aussi ARP et NDP). Attention donc à ne pas changer d'adresse MAC « trop souvent ».

Autre inconvénient, le changement de l'identificateur DHCP par le client, s'il permet davantage de vie privée, empêchera d'obtenir des paramètres de connexion stables (comme l'adresse IP, cf. RFC 7618) dans le temps. On n'a rien sans rien !

Et la vie privée du serveur DHCP, on en parle ? On ne s'est préoccupé jusqu'à présent que du client. C'est parce que le RFC considère que c'est le client qui est aujourd'hui suivi à la trace, et c'est son cas qui nécessite des solutions urgentes. Pour le serveur, cela peut attendre (par exemple parce qu'un serveur qui veut être discret peut ne répondre qu'aux clients authentifiés au niveau 2).

Bien, assez de préliminaires, voyons maintenant le profil proposé. D'abord, pour IPv4 (section 3). Donc, le client qui veut minimiser la surveillance doit donc :

  • Dans le message DHCPDISCOVER, mettre les options « identificateur de client » et « paramètres demandés » mais rien d'autre.
  • Dans un DHCPREQUEST, ajouter éventuellement la demande d'une adresse IP précise.

L'option « identificateur de client » (Client Identifier, RFC 2132, code 61) est, comme son nom l'indique, dangereuse pour la vie privée. Elle permet un suivi très efficace d'une machine, précisement ce qu'on voudrait empêcher. Ne pas la mettre n'est pas une solution car tous les clients DHCP l'incluent. Ne pas le faire serait se singulariser (voir la remarque sur Guy Fawkes plus haut). Notre RFC demande donc qu'on envoie cette option mais qu'on lui donne comme valeur l'adresse MAC (qui est déjà dans l'en-tête couche 2 du paquet). Cela contredit le RFC 4361, section 6.1, mais ce changement de politique reflète l'accent désormais mis sur la préservation de la vie privée. Si on n'a pas d'adresse MAC (cas de certaines liaisons point à point), on doit tirer au hasard (après avoir lu le RFC 4086 et la section 5 du RFC 7217) un identificateur.

Et l'autre option acceptable, la liste des paramètres demandés (Parameter Request List, RFC 2132, code 55) ? La liste doit être réduite au minimum, et ordonnée au hasard, pour éviter qu'on reconnaisse le type de client DHCP utilisé.

L'adresse MAC est indispensable, on ne peut pas ne pas la mettre dans le paquet, et, donc, il ne sert à rien de l'omettre du champ correspondant dans la requête DHCP, mais il est recommandé de la changer (et que le client DHCP utilise cette adresse dans son paquet, qu'il ne garde surtout pas l'ancienne).

Le champ « adresse IP du client » ne pose guère de problème de vie privée (puisque la même adresse IP figure dans l'en-tête IP du paquet) sauf si le client est nouveau sur ce réseau, l'adresse IP indiquée étant alors celle du précédent réseau. Donc : pensez à effacer l'adresse IP lorsque le matériel signale qu'on vient de changer de réseau. Pour la même raison, le profil anonyme ne comprend pas l'option « adresse IP souhaitée » (RFC 2132, code 50). Elle est certes bien pratique (permettant de conserver son adresse IP) mais très révélatrice.

Parmi les autres options, le nom de la machine (code 12) est très révélateur. Même si ce n'est pas un FQDN, il peut être très spécifique (« pc-de-jean-dupont »). Il ne doit pas être utilisé dans ce profil. Si on doit quand même le faire, le nom doit être choisi aléatoirement. Une méthode possible est de condenser un secret et l'adresse MAC, puis prendre la représentation en hexadécimal de six premiers octets (quelque chose comme echo -n "$SECRET" "$MACADDRESS" | sha256sum | cut -c 1-12 en shell Unix).

L'option Client FQDN (RFC 4702, code 81) est évidemment également à proscrire. Ou alors, il faut l'« anonymiser » avec la même méthode qu'au paragraphe précédent.

Le RFC 4578 décrit une option UUID, prévue pour PXE, et identifiant de manière unique un client DHCP. Normalement, on n'utilise PXE que dans des environnements contrôlés et sécurisés. Dans un cyber-café inconnu, télécharger son système d'exploitation serait une très mauvaise idée. Il ne faut donc utiliser cette option que dans un réseau que l'on sait sûr.

Enfin, les options indiquant le type de logiciel utilisé (comme Vendor Specific Information, code 43, ou Vendor Class, code 60 sont évidemment à rejeter.

Pour éviter le fingerprinting, le client ne devrait pas ajouter d'autres options, mêmes si celles-ci sont inoffensives du point de vue de la vie privée. En effet, si certains clients mettent telle option, quel que soit son contenu, ils diffusent une information. Et, si on envoie des options DHCP, leur ordre doit être tiré au hasard avant l'envoi, là encore, pour éviter de révéler le type de client utilisé (DHCP permet pas mal de choix, et le choix facilite le fingerprinting). Si on n'a pas de bon générateur de nombres aléatoires, un repli possible est d'envoyer toujours les options dans l'ordre de leur code : ainsi, tous les logiciels (qui sont dans ce cas) feront pareil.

La section 4 du RFC fait la même chose, mais pour IPv6. DHCP v6 a d'autres possibilités (comme l'existence de deux modes, avec ou sans état). Le profil est donc un peu plus compliqué mais bien des conseils sont identiques (par exemple ceux sur les options Client FQDN, sections 3.8 et 4.9), et je ne les répéterai donc pas ici. Dans le mode sans état, les clients configurent l'adresse avec d'autres mécanismes, comme le SLAAC et ne se servent de DHCP que pour récupérer des informations générales. Le choix entre les deux modes dépend d'options publiées dans les Router Advertisement (RFC 4861, section 4.2, les bits M et O).

Parmi les messages spécifiques à DHCP v6, Confirm (RFC 3315, section 18.1.2) est dangereux, car il contient de l'information sur le précédent réseau où on s'est connecté. En mode « anonyme », il ne faut pas l'envoyer, sauf si on est certains qu'on est toujours sur le même réseau (ce qui est une vérification pas toujours triviale, le RFC recommande d'utiliser 802.1X).

L'option Client Identifier (code 1) en DHCP v6 contient un identificateur unique, le DUID (DHCP Unique Identifier, RFC 3315, section 9). Elle rend donc le suivi d'un client très facile. Pour empêcher ce suivi, le profil demande d'utiliser le format 3, « adresse MAC », du DUID (RFC 3315, section 9.4), avec une adresses MAC changée comme indiquée plus haut. Dans les cas où cette option n'est pas exigée par le protocole (comme les Information-Request, RFC 3315, section 18.1.5, qui sont sans état), elle ne doit pas être envoyée.

DHCP v6 permet évidemment d'obtenir des adresses IPv6 (mais ce n'est pas le seul moyen, contrairement à ce qui se passe en IPv4). Une option semble intéressante pour la vie privée, la demande d'adresses temporaires (RFC 3315, section 12). Mais elle n'est pas si utile que ça : car peu de serveurs la mettent en œuvre (le client ne peut donc pas se reposer dessus), le renouvellement de ces adresses n'est pas spécifié, et le fait que le client doive la demander est déjà une fuite d'informations (« je veux être anonyme »). Elle est donc déconseillée.

Notre RFC met également en garde contre des options qui peuvent être amusantes mais qui sont rares : les utiliser revient, pour le client DHCP, à « sortir du lot ». C'est le cas par exemple de la demande de délégation de préfixe (RFC 3633), que le PC typique n'utilise pas.

Le RFC se termine par quelques considérations opérationnelles (section 5). La plus évidente, et la plus « gênante » est que l'application de ce profil va cache l'identité du client au serveur DHCP. C'est le but. Mais cela peut être ennuyeux. Des fonctions comme la publication de l'adresses du client dans le DNS, ou comme la relative stabilité des adresses IP (redonner la même adresse lorsqu'un client revient) ne seront plus possibles. On n'a rien sans rien.

D'autre part, les clients utilisant ce profil consommeront davantage de ressources. Par exemple, à chaque changement au niveau 2, ils réclameront une nouvelle adresse IP, alors que l'ancienne reste réservée, jusqu'à la fin du bail.

Et certains serveurs DHCP fascistes ne donnent une adresse IP qu'aux clients connus, interdisant ainsi l'anonymat. Pour ces raisons, le RFC recommande aux programmeurs de permettre la configuration du client DHCP, configuration allant jusqu'à permettre de débrayer l'anonymisation.

Ce profil a été mis en œuvre dans un client Microsoft, ce qui a donné lieu à un compte-rendu d'expérience à une réunion IETF.


Téléchargez le RFC 7844


L'article seul

RFC 7858: Specification for DNS over Transport Layer Security (TLS)

Date de publication du RFC : Mai 2016
Auteur(s) du RFC : Z. Hu, L. Zhu, J. Heidemann (USC/Information Sciences Institute), A. Mankin, D. Wessels (Verisign Labs), P. Hoffman (ICANN)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dprive
Première rédaction de cet article le 18 mai 2016


Traditionnellement, les requêtes DNS voyageaient sur le réseau en clair, visibles par tous. Ce n'est évidemment plus acceptable, notamment depuis les révélations de Snowden, et ce RFC normalise donc un mécanisme qui permet de chiffrer les requêtes DNS pour en assurer la confidentialité vis-à-vis d'un éventuel surveillant.

Le chiffrement est le deuxième pilier de la protection des données, après la minimisation des données (qui, pour le DNS, est spécifiée dans le RFC 7816). Ce chiffrement est motivé notamment par le développement de la surveillance de masse (RFC 7258), par le souci de protéger la vie privée (RFC 6973) et par la prise de conscience des risques spécifiques au DNS (RFC 7626).

Il y avait plusieurs choix possibles pour le groupe de travail DPRIVE qui a produit ce RFC. Il pouvait utiliser une technique extérieure à l'IETF comme DNSCrypt. Il pouvait s'appuyer sur un protocole existant comme IPsec ou TLS. Et il pouvait développer un nouveau protocole (plusieurs propositions avaient été faites en ce sens). Finalement, le choix s'est porté sur un protocole facile à déployer, bien connu, et éprouvé, TLS. Pour résumer techniquement ce RFC (section 1) : on met les requêtes DNS sur un canal TLS lui-même évidemment transporté sur TCP. (Le groupe DPRIVE travaille également sur une future solution utilisant DTLS et donc UDP.) Outre la confidentialité, TLS permet de protéger les données contre une modification en cours de route.

Notons au passage que DNSSEC ne résout pas ces problèmes : son but est d'authentifier les réponses, pas de protéger contre l'espionnage.

Il y a deux liens à protéger dans une requête DNS, celui entre la machine de l'utilisateur et le résolveur, et celui entre le résolveur et les serveurs faisant autorité. La charte du groupe DPRIVE précisait qu'il fallait d'abord s'attaquer au premier problème, plus facile (une machine ne parle qu'à peu de résolveurs, et elle a une relation avec eux, alors qu'un résolveur parle à beaucoup de serveurs faisant autorité, qu'il ne connait pas.)

La section 3 décrit la gestion des connexions TLS. TLS tourne sur TCP (un de ses copains, DTLS, tourne sur UDP), et il faut donc utiliser ce protocole (notez que l'évolution récente du DNS fait de plus en plus de place à TCP, cf. RFC 7766). DNS-sur-TLS tourne sur un port fixe, le port 853 (les premières versions de ce protocole utilisaient un protocole de négociation de TLS, comme pour SMTP mais, trop compliqué et trop dangereux, il a été abandonné). Le serveur DNS-sur-TLS écoute donc sur le port 853, le client se connecte à ce port, et démarre tout de suite une session TLS (RFC 5246). Ensuite, il y fait circuler le DNS, encodé comme sur TCP (le message DNS précédé de deux octets indiquant sa taille, cf. RFC 1035, section 4.2.2). Comme pour tout usage de DNS sur TCP (RFC 7766), le client et le serveur ne doivent évidemment pas couper la connexion après une seule requête. S'ils le faisaient, les performances seraient catastrophiques, vu le temps qu'il faut pour établir la connexion TCP et la session TLS. Au contraire, la session doit être réutilisée (section 3.4) pour les requêtes ultérieures (et le RFC demande aussi qu'un serveur traite les requêtes en parallèle, pas séquentiellement dans leur ordre d'arrivée, section 3.3.) Un autre moyen de gagner du temps lors de l'établissement d'une nouvelle connexion TCP, moyen recommandé par notre RFC, est d'utiliser TCP Fast Open (RFC 7413).

Notez bien la règle : jamais de contenu chiffré sur le port 53, jamais de contenu en clair sur le port 853. Si le serveur ne répond pas aux requêtes sur le port 853, cela peut être parce qu'une affreuse middlebox bloque tout le trafic vers le port 853, ou tout simplement parce que ce résolveur ne gère pas encore DNS sur TLS. Le client doit alors décider, selon sa politique de sécurité, s'il se rabat sur du trafic DNS en clair ou bien s'il renonce à communiquer. Le RFC recommande que le client se souvienne des serveurs qui répondent sur le port 853, pour détecter un filtrage récemment apparu.

À noter aussi que je n'ai pas parlé encore d'authentification du serveur. Comment être sûr qu'on parle bien au serveur à qui on veut parler et pas au terrible Homme du Milieu ? Pour l'instant, gardez la question de côté, on y reviendra.

Dit comme cela, c'est peut-être un peu compliqué, mais l'un des gros avantages du choix de TLS est qu'il existe déjà des bibliothèques toutes faites pour ce protocole. Ajouter TLS à un client ou un serveur existant est donc relativement simple. (Plus simple que la gestion du RFC 7766, qui est un pré-requis pour DNS-sur-TLS.)

Revenons à l'authentification. A priori, elle est indispensable. Si on n'authentifie pas, on risque d'envoyer ses requêtes DNS à un serveur qui n'est pas le bon, et, dans ce cas, le chiffrement n'aura servi à rien. Pour se faire passer pour le bon serveur DNS, les attaquants actifs ont bien des moyens à leur disposition, comme d'injecter des fausses routes, comme en Turquie. Un chiffrement sans authentification ne protégerait que contre des attaquants strictement passifs.

Oui, mais l'authentification, c'est difficile. Il y a plein de pièges, de problèmes possibles, et d'argent à dépenser (par exemple pour acheter un certificat). Imposer dès le début une authentification stricte dans tous les cas aurait tué le projet dans l'œuf. Le choix a donc été de prévoir un certain nombre de profils d'authentification, que le client choisit, en fonction du degré de sécurité souhaité. (Le serveur, lui, n'authentifie pas le client, en tout cas aucun mécanisme n'est prévu pour cela.) Notre RFC propose deux profils d'authentification (section 4), et d'autres seront décrits dans un futur RFC. Ne vous impatientez donc pas si votre profil favori est absent de ce RFC.

Le premier profil est celui « opportuniste » (opportunistic privacy). Le client DNS qui utilise ce profil va tenter de chiffrer, il peut même essayer d'authentifier mais, si cela échoue, il continue quand même à envoyer des requêtes DNS, se disant qu'il est au moins protégé contre les attaques passives.

Le second profil est celui de l'« épinglage de clé » (out-of-band key-pinned »). La clé publique (SPKI pour Subject Public Key Info) du serveur DNS est connue du client (par un mécanisme non spécifié dans ce RFC), et il ne se connecte à un serveur DNS-sur-TLS que s'il utilise une des clés correspondant à son adresse. C'est un mécanisme analogue à l'épinglage HTTP du RFC 7469. Une syntaxe possible, pour un /etc/resolv.conf sur Unix serait, par exemple (l'annexe A propose une autre syntaxe) :

domain example.net
nameserver 2001:db8:90e:241a::1  NjAwZGI5YTVhMzBiY2EzOWY1OTY5YzM0ZGYzMTllYTVkNmYxNjAwYjJmNzZhOGFhYTNhMDEyMzU4MTIwNjNkMwo= 
  

Où le dernier champ est le condensat de la clé publique.

Ce mécanisme est sûr, empêchant toute attaque de l'Homme du Milieu. Il est peut-être même trop sûr, par exemple pour les réseaux qui utilisent ces horribles portails captifs qui font des attaques de l'Homme du Milieu pour vous rediriger vers le portail. Il peut donc être préférable de ne pas activer ce profil avant de s'être authentifié auprès du portail. (dnssec-trigger utilise un mécanisme analogue.)

J'ai déjà parlé des performances au moment de l'établissement de la connexion, et des problèmes de latence qui peuvent survenir en raison de l'utilisation de TCP et de TLS. La section 5 revient sur ces histoires (il est également recommandé de lire le rapport « T-DNS: Connection-Oriented DNS to Improve Privacy and Security »). Évidemment, une connexion TCP plus une requête DNS, c'est plus coûteux qu'une requête DNS tout court. La requête et la réponse DNS nécessitent deux voyages entre client et serveur, l'etablissement de la connexion TCP en nécessite trois à lui seul, et TLS deux de plus. On pourrait en déduire que DNS-sur-TLS-sur-TCP aura une latence plus élevée de 250 %. On peut réduire ce coût avec des trucs TCP qui réduisent le temps d'établissement de la connexion, comme le TCP Fast Open du RFC 7413 et avec des trucs TLS comme la reprise de session du RFC 5077. Mais, de toute façon, ce calcul n'est vrai que si on établit une connexion TCP par requête DNS, ce qui n'est pas conseillé, la bonne méthode étant au contraire, dans l'esprit du RFC 7766, de réutiliser les connexions.

D'autre part, TCP nécessite de stocker un état dans le serveur. Pour éviter que beaucoup de clients n'écroulent celui-ci, il faut donc ajuster les délais d'inactivité, pour couper les connexions TCP inutilisées.

La section 7 de notre RFC intéressera les ingénieurs qui se demandent pourquoi les choses sont comme elles sont et pourquoi un autre choix n'a pas été fait. Elle est consacrée à l'évolution de la solution de chiffrement du DNS, au sein du groupe de travail DPRIVE. Comme indiqué plus haut, le premier projet prévoyait de tout faire passer sur le port 53, avec un passage en TLS à la demande du client, lorsqu'il envoyait une requête DNS « bidon » avec un nouveau bit EDNS, TO (TLS OK), mis à un, et avec le QNAME (Query NAME) STARTTLS (reprenant un mot-clé utilisé par SMTP, dans le RFC 3207).

Cette méthode avait des avantages : elle permettait par exemple à un serveur d'accepter TLS quand il n'était pas trop chargé, et de le refuser autrement. Et, réutilisant le port existant, elle ne nécessitait pas de changer les ACL sur les pare-feux. Mais elle avait aussi des inconvénients : les affreuses middleboxes ont une longue habitude d'interférence avec EDNS et il n'était pas du tout sûr qu'elles laissent passer le bit TO. Et puis, même si le RFC ne le mentionne pas, il y avait un risque qu'une middlebox trop zélée ne fasse du DPI sur le port 53, s'aperçoive que ce qui passe n'est pas du DNS, et coupe la communication. Mais le principal problème de cette approche était qu'elle rendait les attaques par repli triviales. Un attaquant actif n'avait qu'à supprimer le bit TO et le client n'avait alors plus aucun moyen de savoir si l'absence de TLS était due à un serveur trop ancien, à une middlebox boguée... ou bien à une attaque par repli.

Une proposition alternative amusante avait été de mêler le trafic chiffré et non chiffré sur le port 53 sans signalisation : la structure de l'en-tête TLS est telle qu'une machine interprétant le TLS comme étant du DNS en clair aurait vu une réponse DNS (bit QR à 1) et il n'y aurait donc pas eu de confusion avec le trafic DNS en clair. Astucieux mais évidemment très fragile.

La section 8 de notre RFC synthétise les questions de sécurité. D'abord, TLS n'est évidemment pas une formule magique. Il y a eu plein d'attaques contre TLS (par exemple pour forcer un repli vers des algorithmes de chiffrement faibles), ou contre ses mises en œuvre (on pense évidemment tout de suite à OpenSSL). Pour éviter cela, outre le respect des bonnes pratiques TLS (RFC 7525), le client prudent tâchera de se souvenir quels serveurs acceptaient DNS-sur-TLS. Si un serveur qui l'acceptait ne répond tout à coup plus sur le port 853, c'est peut-être qu'un attaquant tente de forcer un repli sur le port 53, en clair. Le client prudent peut ainsi détecter une attaque possible. Si c'est un nouveau serveur, que le client ne connait pas, la marche à suivre dépend de la politique du client (sécurisé ou laxiste).

Quant aux attaques non-TLS (comme le blocage du port 853 mentionné ci-dessus), c'est également au client, en fonction de son profil de sécurité, de décider ce qu'il va faire (renoncer à communiquer, essayer un mécanisme de résolution alternatif, s'en foutre et tout passer en clair, etc).

Revenons à TLS pour noter que ce protocole ne fait pas d'effort pour dissimuler la taille des paquets. Un attaquant passif peut donc, en observant cette taille, et d'autres informations comme le temps écoulé entre deux paquets, en déduire certaines informations, malgré le chiffrement. L'option de remplissage du RFC 7830 permet de remplir les paquets avec des données bidons, afin de rendre cette analyse plus difficile.

Pour un bilan d'étape du projet « DNS et vie privée » à l'IETF, vous pouvez regarder mon exposé State of the "DNS privacy" project: running code à l'OARC.

Question mises en œuvre de ce RFC, où en est-on ? Aujourd'hui, le résolveur Unbound a le code nécessaire depuis longtemps (depuis la version 1.4.14). On peut génerer les clés nécessaires avec OpenSSL ainsi :

openssl req -x509 -newkey rsa:4096 \
      -keyout privatekeyfile.key -out publiccertfile.pem \
      -days 1000 -nodes    
  

et configurer le serveur ainsi :

server:
  interface: 2001:db8:1::dead:beef@853
  ssl-service-key: "/etc/unbound/privatekeyfile.key"
  ssl-service-pem: "/etc/unbound/publiccertfile.pem"
  ssl-port: 853
  

Unbound va alors activer DNS sur TLS au démarrage et annoncer fièrement « setup TCP for SSL [sic] service ». Les clients pourront alors l'interroger en DNS sur TLS.

Bon, mais quel client utiliser ? Dans la bibliothèque getdns, le logiciel d'exemple getdns_query sait faire du DNS sur TLS :

% ./getdns_query @2001:db8:1::dead:beef -s -a -A -l L www.bortzmeyer.org
...
Response code was: GOOD. Status was: At least one response was returned
  

(C'est l'option -l L qui lui indique de faire du TLS.)

Si on capture le trafic entre getdns_query et Unbound, on peut afficher le résultat avec tshark :

% tshark -n -d tcp.port==853,ssl -r /tmp/dnstls.pcap    
 4   0.002996  2001:db8:1::63a:671 -> 2001:db8:1::dead:beef  SSL Client Hello
 6   0.594206  2001:db8:1::dead:beef -> 2001:db8:1::63a:671  TLSv1.2 Server Hello, Certificate, Server Key Exchange, Server Hello Done
 8   0.734094  2001:db8:1::63a:671 -> 2001:db8:1::dead:beef  TLSv1.2 Client Key Exchange
16   0.751614  2001:db8:1::dead:beef -> 2001:db8:1::63a:671  TLSv1.2 Application Data
17   0.759223  2001:db8:1::63a:671 -> 2001:db8:1::dead:beef  TLSv1.2 Application Data
  

On voit un trafic TLS classique, chiffré. Notez que tshark, par défaut, ne sait pas que c'est du TLS sur le port 853 (cela sera fait lors de la prochaine version majeure). On lui indique donc explicitement (-d tcp.port==853,ssl).

Et si j'ai la flemme d'installer un Unbound configuré pour TLS, est-ce que je peux quand même tester un client DNS-sur-TLS ? Oui, si les serveurs de test publics listés en https://portal.sinodun.com/wiki/display/TDNS/DNS-over-TLS+test+servers veulent bien répondre.

Si vous préférez développer en Go, l'excellente bibliothèque GoDNS gère DNS sur TLS (depuis janvier 2016) et vous permet de faire vos propres programmes. Par exemple, ce code Go :

c := new(dns.Client)
c.Net = "tcp-tls"
if *insecure {
        c.TLSConfig = new(tls.Config)
        c.TLSConfig.InsecureSkipVerify = true
}
in, rtt, err := c.Exchange(m, net.JoinHostPort(myResolver, "853"))

va ouvrir une connexion avec le serveur myResolver, sur le port 853, et utiliser TLS. Par défaut, la bibliothèque TLS de Go vérifie le certificat, et que le nom (ou l'adresse IP) dans le certificat correspond bien (ce qui est la bonne approche). Mais cela peut être embêtant si on n'a pas acheté de certificat. D'où l'option (dangereuse !) pour débrayer la vérification (les trois lignes qui commencent par if *insecure). Voici un exemple d'utilisation (au fait, le programme est en dns-tls.go, -k active l'option dangereuse) :

%  ./dns-tls  my-resolver internautique.fr  
Error in query: x509: certificate signed by unknown authority

%  ./dns-tls -k my-resolver internautique.fr 
(time 43051 µs) 2 keys. TC=false    

Téléchargez le RFC 7858


L'article seul

RFC 7786: TCP modifications for Congestion Exposure

Date de publication du RFC : Mai 2016
Auteur(s) du RFC : M. Kuehlewind (ETH Zurich), R. Scheffenegger (NetApp)
Expérimental
Réalisé dans le cadre du groupe de travail IETF conex
Première rédaction de cet article le 15 mai 2016


C'est après une très longue genèse (ce document avait été adopté par le groupe de travail il y a plus de quatre ans) que voici les protocoles concrets pour la signalisation de la congestion aux routeurs situés en aval. Ici, l'utilisation de ce système avec TCP.

ConEx (pour Congestion Exposure, signalement de la congestion) est décrit dans le RFC 6789. L'idée de base est d'informer le réseau qu'un flot de données rencontre de la congestion, afin que les éléments actifs de ce réseau puissent prendre des décisions intelligentes. ConEx est divisé en une spécification abstraite (RFC 7713) et une ou plusieurs spécifications de protocoles concrets. Ce RFC ne spécifie pas un encodage sur le câble, juste le changement de comportement des mises en œuvre de TCP. (Un autre RFC concret spécifie un encodage pour IPv6, le RFC 7837.)

Il n'y a pas besoin de négociation au début (section 1 du RFC), comme avec les options TCP. Les émetteurs qui connaissent ConEx utilisent les informations existantes (pertes de paquets et ECN, stockées dans deux compteurs différents, cf. la section 3 du RFC).

Pour bien utiliser ConEx, le TCP de l'émetteur a besoin d'informations. Bien qu'il ne soit pas indispensable, c'est mieux si SACK (RFC 2018) est disponible.

La section 2 du RFC résume les modifications chez l'émetteur TCP (le récepteur n'a pas besoin d'être changé pour ConEx). Le comportement de l'émetteur dépendra du fait que le récepteur met en œuvre (ou pas) SACK et ECN. L'émetteur est responsable du marquage des paquets (suivant l'encodage du RFC 7837) avec des signaux ConEx. Il doit tenir compte du nombre d'octets, pas du nombre de paquets (RFC 7141).

En cas de perte de paquets, l'émetteur va mettre le signal ConEx L (loss experienced). Dans certains cas (retransmission inutile parce que le paquet était bien arrivé, c'est l'accusé de réception qui s'était perdu), l'émetteur ne connait pas le nombre exact d'octets perdus. Il peut donc surestimer la congestion dans les signaux ConEx qu'il envoie. Pour avoir de meilleurs mesures, l'émetteur peut toujours mettre en œuvre les RFC 5682, RFC 3708 ou RFC 3522.

Si c'est par des marques ECN, et non pas par des pertes de paquets, que l'émetteur a appris qu'il y avait congestion, il va utiliser les marques ConEx E (ECN experienced).

Dans tous les cas (perte de paquets ou bien ECN), les paquets marqués ConEx devront également porter une marque X, qui indique que l'émetteur sait faire du ConEx (section 4 du RFC).

Un émetteur ConEx est aussi censé envoyer des crédits lorsqu'il n'y a pas de congestion. Ces crédits seront ensuite « consommés » lors des épisodes de congestion. Cela se fait avec le signal C (Credit).

Les paquets contenant les signaux ConEx peuvent se perdre, comme tous les paquets IP (section 5 du RFC). Cela peut mener à des pénalités injustes (un émetteur détecte qu'il y a congestion en aval, le signale avec un L ou un E, le paquet portant le signal est perdu, un routeur qui fait de l'audit ConEx se dit alors « ah, ah, il essaie de tricher, il n'a pas signalé la congestion »). Le problème étant du second ordre (si la probabilité de perdre un paquet est P, la probabilité qu'il y ait perte du paquet et perte du signal est de P au carré), on peut choisir de l'ignorer.

Plus délicat, le problème de la fraîcheur des informations ConEx (section 6 du RFC). Ces informations ne sont utiles que si elles sont très récentes (typiquement moins d'un RTT depuis que la congestion est apparue). L'émetteur doit donc faire attention à ne pas retarder les signaux ConEx. Parfois, il n'a pas trop le choix, par exemple si l'application arrive d'envoyer des données, il n'y aura pas de paquets à marquer.


Téléchargez le RFC 7786


L'article seul

RFC 7837: IPv6 Destination Option for Congestion Exposure (ConEx)

Date de publication du RFC : Mai 2016
Auteur(s) du RFC : S. Krishnan (Ericsson), M. Kuehlewind (ETH Zurich), B. Briscoe (Simula Research Laboratory), C. Ralli (Telefonica)
Expérimental
Réalisé dans le cadre du groupe de travail IETF conex
Première rédaction de cet article le 15 mai 2016


Le mécanisme ConEx, normalisé dans le RFC 7713, permet d'informer les routeurs situés en aval qu'un flot de données se heurte à la congestion. Il y a plusieurs façons d'indiquer cette congestion, et ce RFC le fait par une option dans l'en-tête Destination Options d'IPv6.

En effet, le mécanisme décrit dans le RFC 7713 est abstrait : il spécifie des concepts, pas comment ils sont représentés sur le câble. Notre RFC 7837, au contraire, est concret : il indique comment mettre l'information ConEx dans des champs du paquet que les équipements réseau, notamment les routeurs, pourront lire. ConEx est actuellement un projet expérimental (et même très expérimental) et il n'est pas sûr qu'il soit déployé avec enthousiasme. En attendant, puisque c'est expérimental, le but est de récolter de l'information et, pour cela, il faut du code qui tourne, avec des paquets concrets (section 1 de notre RFC). Mettre l'information ConEx dans le champ Options d'IPv4 est délicat : ce champ est de taille limitée, et pose souvent des problèmes dans le réseau. L'idée est donc d'utiliser le protocole du futur, IPv6, et ses en-têtes d'extension (RFC 2460, section 4).

La section 3 détaille les choix techniques effectués et leurs raisons. Les sections 3.3 et 4 du RFC 7713 expliquent les contraintes d'encodage concret de ConEx dans les paquets. Ici, les exigences considérées ont été :

  • Les marques ConEx doivent être visibles par tous les nœuds ConEx du chemin (donc, pas question de les mettre tout au bout du paquet),
  • Pour que les paquets marqués arrivent à bon port, même en traversant les équipements actuels qui ne connaissent pas ConEx, il faut un mécanisme standard et déjà largement accepté (pas question de changer le format des paquets IP, cela empêcherait le déploiement incrémental),
  • La présence des marques ConEx ne doit pas ralentir le traitement des paquets (cf. section 5),
  • Les marques ConEx doivent pouvoir être protégées contre les manipulations ultérieures (exigence pas réellement satisfaite en pratique, sauf à utiliser IPsec).

Quatre solutions IPv6 avaient été envisagées par le groupe de travail à l'IETF :

  • Une option Hop-by-hop (RFC 2460, section 4.3).
  • Réutiliser le champ Flow label qui ne sert quasiment pas (cf. RFC 6437),
  • Créer un nouvel en-tête d'extension,
  • Une option Destination (RFC 2460, section 4.6), le choix qui a finalement été fait.

L'en-tête d'extension Hop-by-hop aurait été l'option logique puisqu'elle est examinée par chaque routeur, ce qui est bien ce qu'on veut pour ConEx. Elle aurait été conforme aux principes d'IPv6. Mais, dans les routeurs actuels, le traitement de cette option se fait de manière extrêmement lente (elle n'emprunte pas le chemin rapide dans le routeur, mis en œuvre en ASIC ou FPGA), ce qui viole la troisième exigence. Le choix de l'en-tête Destination, qui est normalement de bout en bout et que les intermédiaires ne sont pas censés regarder, est donc surprenant, mais justifié. Il viole un peu la première exigence (si le paquet est encapsulé, le routeur aura du mal à voir cet en-tête). Et, surtout, analyser la chaîne des en-têtes d'extension IPv6 est anormalement compliqué. Mais il n'y avait guère d'autre choix réaliste. En pratique, certains routeurs auront donc besoin d'un changement de leurs règles de traitement des en-têtes d'extension s'ils veulent voir les marques ConEx.

(Sur la survivabilité des en-têtes d'extension IPv6 dans l'Internet, voir l'étude de Mehdi Kouhen en février 2016.)

La section 4 présente le format concret. La nouvelle option Destination se nomme CDO, pour ConEx Destination Option. Elle est mise dans un en-tête d'extension Destination Options (RFC 2460, section 4.6). Comme les autres options Destination, elle est encodée en TLV. Le type de l'option est 0x1E (30, valeur réservée aux expérimentations, non définitive), sa longueur est 1 (un seul octet, et encore, tous les bits ne sont pas utilisés) et sa valeur est composée de quatre bits (RFC 7713, notamment la section 2.1) : X (« je sais faire du ConEx »), L (« des paquets ont été perdus »), E (« de la congestion a été signalée par ECN ») et C (« pas (encore) de congestion, j'accumule des crédits »). Le dernier bit, C, est à utiliser avant qu'on détecte la congestion (RFC 7713, notamment la section 5.5).

Au passage, si vous écrivez des programmes en C qui veulent ajouter des options dans l'en-tête Destination, vous pouvez consulter mon article.

On a dit plus haut que la principale raison pour utiliser l'en-tête Destination et pas le Hop-by-Hop (qui aurait été plus logique), est le souci que les paquets restent sur le fast path des routeurs (le traitement fait par le matériel, par opposition au slow path, confié au processeur généraliste, bien plus lent). Mais le problème est que l'en-tête Destination, n'étant pas prévu pour être lu par les équipements réseau sur le chemin, peut se trouver n'importe où dans la chaîne des en-têtes (alors que l'en-tête Hop-by-hop est forcément au début, cf. RFC 2460, section 4.1). Et l'option CDO pourrait, en théorie, se trouver n'importe où dans l'en-tête Destination. Notre RFC est donc obligé de recommander (section 5) que l'option CDO soit la première dans l'en-tête Destination.

Reste à voir s'il sera effectivement possible de déployer cette option. L'ossification de l'Internet rend tout déploiement de ce type difficile (les en-têtes d'extension sont rares dans les paquets IPv6 actuels).


Téléchargez le RFC 7837


L'article seul

RFC 7793: Add 100.64.0.0/10 prefixes to IPv4 Locally-Served DNS Zones Registry

Date de publication du RFC : Mai 2016
Auteur(s) du RFC : M. Andrews (ISC)
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 13 mai 2016


Il existe un registre des zones DNS qui doivent être gérées localement par le résolveur DNS et pour lesquelles les requêtes ne sont pas transmises aux serveurs de la racine. Ce nouveau RFC ajoute à ce registre les zones correspondant au préfixe IPv4 100.64.0.0/10, que le RFC 6598 avait réservé pour la numérotation des machines situées derrière les CGN.

Le but de ce registre est d'éviter de surcharger les serveurs racine avec des requêtes qui sont inutiles puisque les noms dans ces zones n'ont qu'une signification locale, et ne pourraient pas recevoir une réponse sensée de la racine. Le RFC 6303 avait donc créé ce registre des noms pour lesquels, par défaut, le résolveur DNS doit retourner NXDOMAIN (code indiquant que le nom n'existe pas) tout de suite. On y trouve par exemple la zone 10.in-addr.arpa, zone correspondant aux adresses IP du RFC 1918.

Le RFC 6598 avait réservé tout le préfixe 100.64.0.0/10 pour les CGN. Notre nouveau RFC met donc les zones 64.100.in-addr.arpa à 127.100.in-addr.arpa dans le registre des zones à servir localement. Au fur et à mesure des mises à jour des résolveurs (leur code, ou bien la configuration locale), toute requête PTR dans une de ces zones doit être traitée localement par le résolveur.

Ces zones sont déléguées aux serveurs de noms de l'IANA, pour attraper les requêtes qui ne suivent pas ces règles :

% dig +short NS 64.100.in-addr.arpa
a.iana-servers.net.
b.iana-servers.net.
c.iana-servers.net.

Sinon, aujourd'hui, par défaut, Unbound « délègue » ces zones à... localhost (si on veut un vrai contenu, il faut configurer explicitement ces zones) :

% dig +short NS 64.100.in-addr.arpa
localhost.
    
% dig +short  NS 64.100.in-addr.arpa 
64.100.IN-ADDR.ARPA.
    

Téléchargez le RFC 7793


L'article seul

RFC 7830: The EDNS(0) Padding Option

Date de publication du RFC : Mai 2016
Auteur(s) du RFC : A. Mayrhofer (nic.at GmbH)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dprive
Première rédaction de cet article le 11 mai 2016


Ce nouveau RFC fait partie de la série de ceux qui tentent d'améliorer la situation du DNS pour tout ce qui concerne la protection de la vie privée. Parmi les efforts dans ce domaine, il y a une possibilité de chiffrement des communications DNS, dans le RFC 7858 (DNS-sur-TLS). Elle utilise le protocole TLS. Ce dernier ne fait rien pour dissimuler la longueur des requêtes et réponses DNS. Or, de telles métadonnées peuvent suffire à identifier les requêtes faites. Il est donc important de compléter le chiffrement avec un mécanisme de remplissage (padding). C'est ce que permet la nouvelle option EDNS normalisée dans ce RFC.

Trouver la requête effectuée uniquement à partir de la taille de la réponse est d'autant plus facile que les données DNS ne sont pas confidentielles. Un espion qui soupçonne que M. Michu fait des requêtes pour tel nom de domaine peut faire la même requête, noter la taille de la réponse chiffrée, et voir s'il trouve la même taille dans les réponses reçues par M. Michu. Voilà pourquoi il faut ajouter aux requêtes et aux réponses un nombre imprévisible d'octets, pour rendre plus difficile cette analyse des métadonnées.

Ce RFC est court car le mécanisme est très simple (section 3 du RFC). Ce mécanisme utilise une nouvelle option EDNS (EDNS est normalisé dans le RFC 6891.) Cette option porte le numéro 12 et sa partie « données » porte le remplissage. (Comme toute option EDNS, elle est encodée en TLV : un champ indique le type de l'option, ici, 12, un champ indique la longueur de l'option, et le dernier contient les données.)

Que mettre comme remplissage ? Cette question a été la plus discutée lors de la création de ce RFC (qui a été plutôt calme et consensuelle, pour le reste.) Le RFC précise que l'émetteur d'un message DNS devrait remplir avec des octets nuls (0x00). Si l'émetteur craint que certains traitements (par exemple de la compression, voyez cependant la section 6 qui demande de ne pas l'utiliser) appliqués avant le chiffrement ne suppriment l'essentiel du remplissage, il est autorisé à mettre une autre valeur. De toute façon, le récepteur doit accepter n'importe quelle valeur, pour permettre les évolutions futures. En pratique, il doit donc ignorer le contenu des données de cette option.

Pourquoi n'avoir pas simplement dit que l'émetteur pouvait mettre ce qu'il voulait, dans ce cas ? Parce qu'il semblait possible, dans ce cas, que des programmeurs naïfs utilisent de la variable non initialisée, et laissent ainsi fuiter le contenu de leur mémoire (comme dans la faille Heartbleed.) Et pourquoi n'avoir pas spécifié un remplissage avec des données aléatoires ? Parce que ce n'est pas normalement nécessaire : pour un observateur, le contenu chiffré doit apparaitre aléatoire, quel que soit le texte en clair (si TLS ne fournissait pas cette propriété, des tas d'attaques seraient possibles, par exemple à base de texte en clair connu.)

Voilà, l'essentiel du RFC tient dans cette courte section 3. Mais quelques détails suivent. Par exemple, quelle quantité d'octets mettre dans la nouvelle option ? Le RFC ne fournit pas de guide à ce sujet, il rappelle juste qu'il ne faut pas aboutir à des messages plus gros que ce que le client spécifiait dans son champ Payload size EDNS (souvent 4 096 octets mais cela dépend du client.) Le serveur DNS ne doit évidemment pas utiliser cette option si la requête ne contenait pas d'EDNS. Si elle contenait de l'EDNS sans cette option, le serveur est libre de remplir ou pas. Si la requête contenait de l'EDNS avec l'option Padding, alors, le serveur doit effectuer du remplissage.

Quelques trucs à ne pas oublier en section 6 : le remplissage augmente la taille des paquets (évidemment). Cela mènera donc à un accroissement du trafic. Dans l'Internet d'aujourd'hui, où tous les États qui en ont les moyens procèdent à une surveillance massive de leurs citoyens (RFC 7258), c'est un petit prix à payer, pour l'avantage de compliquer le travail des surveillants.

Autre piège, l'option de remplissage ne doit être utilisée que si le trafic DNS est chiffré. Autrement, non seulement elle ne servirait à rien, mais elle augmenterait le risque d'attaques avec amplification.

À noter que, comme plein d'autres champs des messages DNS (comme par exemple le QNAME, le Query Name), cette option peut servir de canal caché. Peut-être verra-t-on un jour une mise en œuvre d'IP-sur-DNS utilisant cette option ?

Notez que cette technique est indépendante du protocole de chiffrement sous-jacent, puisqu'elle est faite au niveau applicatif. DNScrypt pourrait l'utiliser (sauf qu'il a son propre système de remplissage.)

Et les mises en œuvre de cette technique ? A-t-on du code qui tourne ? getdns a le remplissage depuis sa version 0.5.1 (cf. le Changelog.) GoDNS y travaille. Wireshark peut analyser cette option. La page officielle sur cette option de remplissage liste d'autres mises en œuvre.

Daniel Kahn Gillmor, qui avait programmé cette extension dans getdns, en a profité pour faire quelques statistiques :

Ethernet Frame sizes for packet containing DNS query

                Transport    |   query to   |     query to
                   used      |  example.com |  www.example.com
   --------------------------+--------------+-------------------
               cleartext UDP |   82 octets  |   86 octets
               cleartext TCP |  108 octets  |  112 octets
                TLS over TCP |  137 octets  |  141 octets
(padded to 512) TLS over TCP |  609 octets  |  609 octets
  

On voit que le remplissage brouille la différence de taille entre les deux requêtes. Mais restons prudents : le remplissage est une bonne technique pour rendre plus difficile l'analyse des métadonnées mais il n'est pas parfait. Lisez par exemple l'excellent « Peek-a-Boo, I Still See You : Why Efficient Traffic Analysis Countermeasures Fail ».


Téléchargez le RFC 7830


L'article seul

Google Chrome et son utilisation du DNS

Première rédaction de cet article le 8 mai 2016
Dernière mise à jour le 10 mai 2016


Une tribune sensationnaliste dans le Monde le 6 mai prétendait que « Google [avait] changé l'Internet » et portait une accusation précise : le navigateur Google Chrome utiliserait une racine DNS spécifique à Google. Passons sur le fond politique de l'article, est-ce qu'au moins les faits allégués sont exacts ?

Un petit mot au passage sur ce concept de « racine » (les explications dans la tribune publiée dans le Monde sont... floues). Un logiciel qui veut utiliser un nom de domaine (par exemple un navigateur Web qui veut aller voir https://www.laquadrature.net/fr) va devoir interroger le DNS, un système technique qui permet, à partir d'un nom de domaine, d'obtenir des informations techniques indispensables (comme l'adresse IP du serveur). Les noms de domaine sont organisés sous forme d'arbre, avec la racine représentée en haut (contrairement aux botanistes, les informaticiens mettent la racine des arbres en haut). L'interrogation du DNS est faite par un logiciel nommé résolveur, qui est en général indiqué automatiquement à la machine (c'est la plupart du temps une machine du FAI, mais on peut utiliser son propre résolveur). Le résolveur commence par la racine, d'où il est aiguillé vers les TLD puis de fil en aiguille vers tous les autres noms de domaine. On voit donc que qui contrôle la racine contrôle le DNS.

L'article publié dans le Monde dit « le navigateur Chrome de Google remplace sans avertissement l’annuaire de l’ICANN par le sien ». Au milieu de toutes les vagues affirmations de ce texte, voici un fait précis, qu'on peut contrôler. Cela prend cinq minutes à n'importe quel technicien. Avec un outil d'usage courant, tcpdump, on peut voir le trafic DNS de la machine. Lançons Chrome, tentons de visiter http://nic.la/ et observons ce trafic. (Les lignes suivantes sont triviales à interpréter pour le technicien ordinaire dont je parlais.)

11:38:24.549321 IP6 2001:691:1348:7::bad:209.27121 > 2001:67c:217c:6::2.53: 58483% [1au] A? nic.la. (35)
11:38:24.551217 IP6 2001:67c:217c:6::2.53 > 2001:691:1348:7::bad:209.27121: 58483- 0/8/9 (685)

Que voit-on ? La machine d'adresse IP 2001:691:1348:7::bad:209 a fait une requête DNS au serveur 2001:67c:217c:6::2, qui est bien un serveur de la racine (leurs adresses IP sont publiques et connues).

Amusant détail, je n'utilise personnellement pas la « racine ICANN » mais une racine « alternative », Yeti. Donc, même si on a fait un choix différent de la majorité, Chrome respecte ce choix (en fait, Chrome ne parle pas directement à la racine : comme tout bon logiciel, il parle au résolveur configuré par l'utilisateur, et ce résolveur a été configuré pour utiliser telle ou telle racine). Le complot s'effondre donc : le principal reproche fait à Google dans cet article ne repose sur rien. Alors que la vérification des faits prend quelques minutes à n'importe quel technicien, les auteurs de la tribune n'ont pas vérifié, ni demandé à un technicien de le faire.

Est-ce un accident isolé dans une tribune par ailleurs raisonnable ? Non, il y a beaucoup d'autres erreurs techniques. Par exemple, les auteurs affirment « [la racine de Google est] plus rapide puisque souvent délivré d'étapes de contrôle et de surveillance ». Enregistrer les requêtes (comme le fait la NSA) ne ralentit rien, cette affirmation est donc dénuée de sens.

Autre exemple du manque de rigueur de cette tribune, la mention du .google comme étant « la racine de Google » alors qu'il s'agit d'un banal TLD... Est-ce une distinction importante ou bien est-ce que je pinaille excessivement ? Oui, c'est important car cette erreur permet de juger le sérieux d'un texte. Imaginez un article portant sur la production laitière. L'article confond à un moment vaches et chèvres. Sans importance, puisqu'après tout ce sont bien deux mammifères produisant du lait ? Mais si un article sur ce sujet comportait une telle erreur, lui accorderait-on la moindre crédibilité ? C'est pareil ici : confondre TLD et racine, dans un article sur le DNS, est un signe d'extrême légèreté.

On notera aussi que des affirmations tout aussi fausses (« Cependant Google (et Chrome) utilise leur propre racine (copie de la racine ICANN) dont une est l’adresse IP 8.8.8.8 » se trouvent depuis longtemps sur le serveur Web de la société commerciale Open-Root, pour laquelle travaillent deux des auteurs. (8.8.8.8, alias Google Public DNS, est un résolveur DNS, qui n'a donc rien à voir avec une racine. Vaches et chèvres, encore.)

Ces erreurs techniques sont d'autant plus curieuses que, si on souhaite dire du mal de Google et mettre en garde contre le pouvoir dont jouit cette société, les exemples ne manquent pas. Google a un poids important, par sa part de marché, peut influencer ce que font les internautes, et ce poids important est certainement une question politique à traiter, comme toutes les fois où une boîte privée a trop de pouvoir. Alors, pourquoi rajouter des accusations fantaisistes ? Est-ce parce qu'il y a un risque que Chrome, un jour, fasse ce qui lui est reproché dans cette tribune ? Tout est possible mais ce ne serait pas très malin de la part de Google. En effet, l'utilisation d'une autre racine se voit (comme montré avec tcpdump plus haut). Ce ne serait pas très discret de la part de Google (la tribune parle de « substitution invisible », ce qui n'a pas de sens, vu cette visibilité du trafic réseau). D'autre part, pas mal d'entreprises utilisent en interne des TLD non-existants comme .corp, qui ne sont connus que de leurs résolveurs. Si Chrome n'utilisait pas ces résolveurs, ces TLD ne fonctionneraient pas.

Autre chose frappante, ce texte a largement circulé sur les réseaux sociaux, étant repris sans nuances, sans aucune vérification. On l'a par exemple vu cité sur le site de l'émission Arrêt sur Images. Apparemment, le fait d'être publié dans le Monde a un poids qui suffit à débrayer toute critique. (Alors qu'il s'agissait d'une tribune et pas d'un article, ce qui indique que le Monde n'a pas exercé de contrôle trop serré sur le contenu.)

Depuis, il y a eu une réponse à ce texte. Elle a été annoncée sur Twitter en utilisant le raccourcisseur d'URL de Google (goo.gl). Le site d'Open-Root utilise d'ailleurs le spyware Google Analytics. Cela indique leur niveau de cohérence (mais c'est courant chez les souverainistes : de grands discours anti-GAFA à la tribune, mais l'utilisation de tous leurs outils en pratique.) Sans compter la paranoïa « nous sommes attaqués de toute part », de la part de gens qui passent dans le Monde ou à la télé quand ils veulent, et qui sont invités à tous les colloques ministériels...

Bon, je critique cette réponse sur la forme, mais sur le fond ? Sur le fond, il n'y a rien à dire, parce qu'il n'y a pas d'éléments nouveaux : la réponse cite comme preuve que Google a son propre DNS... l'existence de Google Public DNS. Confondre un résolveur DNS public avec une racine, c'est comme l'expert en élevage cité plus haut qui confondrait vache et chèvre... C'est tellement désespérant que c'est au delà de toute discussion.

Pour les reste, pas de détails, pas de tcpdump montrant Chrome faire des requêtes à la soi-disant racine Google, rien.


L'article seul

A small DNS trick to see Sci-Hub despite censorship attempts

First publication of this article on 8 May 2016


The service Sci-Hub is a great help for the scientists, allowing them to access to a lot of scientific papers that were before locked behind paywalls. The publishing companies keep trying to censor Sci-Hub and block access to this service, for instance by taking down domain names like it happened a few days ago with sci-hub.io. If you control your DNS resolver, you can easily restore access.

Sci-Hub's domain sci-hub.io was recently taken down. There are several ways to still use Sci-Hub, such as "domain hopping" (using another TLD such as sci-hub.bz) or using Tor (the address is scihub22266oqcxt.onion). But there is one which does not seem to have been publically documented yet.

For the rest of the article, we will rely on a local DNS resolver. ("local" does not imply it is on your own machine: it may be on the local network. The important point is that you can change its configuration.) A local resolver is a great tool against DNS censorship. By default, it does not see Sci-Hub domains (NXDOMAIN means "No Such Domain"). Let's test with dig:


% dig A sci-hub.io

; <<>> DiG 9.10.4 <<>> A sci-hub.io
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 45356
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 8, ADDITIONAL: 1
...
;; QUESTION SECTION:
;sci-hub.io.		IN A
...
;; Query time: 1408 msec
;; SERVER: ::1#53(::1)
...

    

OK, it failed, the domain being taken down. Let's configure our local resolver to work around the problem. Sci-Hub has a public name server that answers to the Sci-Hub domains. First, we'll be using the excellent program Unbound. We just add in unbound.conf:

forward-zone:
     name:   "sci-hub.io"
     forward-addr: 31.184.194.81
     # You can also add
     # Cloudflare's name servers kay.ns.cloudflare.com
     # and eric.ns.cloudflare.com, which reply for this domain.

and we restart Unbound and it works:


% dig A sci-hub.io                

; <<>> DiG 9.10.4 <<>> A sci-hub.io
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 34214
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;sci-hub.io.		IN A

;; ANSWER SECTION:
sci-hub.io.		604800 IN A 31.184.194.81

;; AUTHORITY SECTION:
sci-hub.io.		604800 IN NS sci-hub.io.

;; Query time: 42 msec
;; SERVER: ::1#53(::1)
;; WHEN: Sun May 08 14:08:02 UTC 2016
;; MSG SIZE  rcvd: 69

  

(DNS experts may discuss the use of forward-zone instead of stub-zone. The Sci-Hub servers accept recursive requests so both work. In my opinion, forward may be a bit more future-proof if the authoritative name server changes its IP address but a recursor stays in place at the old address.)

Doing the same with BIND is possible. Just put in its configuration file (somewhere/named.conf):

   zone "sci-hub.io" {
                 type forward;
                 forwarders {31.184.194.81;};
   };
    

The trick is to use the fact that 31.184.194.81 also allows DNS zone transfers. You can therefore configure your BIND as a slave for sci-hub.io. Once BIND is authoritative for this domain, it won't check with DNSSEC:

    zone "sci-hub.io" {
	         type slave;
                 masters {31.184.194.81;};
};

Note: the option dnssec-must-be-secure addresses a different issue and is not useful here.

I do not use dnsmasq but Canari Bleu does and says you have to add server=/sci-hub.io/31.184.194.81 in dnsmasq.conf.

Of course, this hack is far from perfect. It doesn't scale (imagine if there were dozens of censored domains to make accessible this way). It's brittle (the IP addresses can change without warning). But this sort of imperfect workarounds will become more and more common with the increase of politically or business-motivated censorship.


L'article seul

RFC 7819: Privacy considerations for DHCP

Date de publication du RFC : Avril 2016
Auteur(s) du RFC : S. Jiang (Huawei Technologies), S. Krishnan (Ericsson), T. Mrugalski (ISC)
Pour information
Réalisé dans le cadre du groupe de travail IETF dhc
Première rédaction de cet article le 3 mai 2016


Le protocole DHCP est bien connu : la grande majorité des machines « client » qui se connectent à l'Internet l'utilisent pour récupérer des éléments de configuration indispensables, comme l'adresse IP à utiliser. Mais peu de gens sont conscients que DHCP peut être dangereux pour la vie privée : le client DHCP n'est en effet pas passif, il envoie au serveur des informations qui peuvent permettre de suivre à la trace une machine mobile.

DHCP pour IPv4 est normalisé dans le RFC 2131. (Le RFC 7824 traite le cas de DHCP pour IPv6, qui pose des problèmes similaires.) Son principe de fonctionnement est simple : le client DHCP (la machine de M. Michu) envoie à la cantonade une requête pour demander des informations de configuration réseau, le serveur DHCP se reconnait, il répond avec ces informations. Voici une transaction DHCP, vue par tcpdump :

   21:32:13.284690 IP (tos 0x0, ttl 64, id 960, offset 0, flags [none], proto UDP (17), length 377)
    0.0.0.0.68 > 255.255.255.255.67: [udp sum ok] BOOTP/DHCP, Request from b8:27:eb:84:35:e3, length 349, xid 0x4feaaa6f, Flags [none] (0x0000)
	  Client-Ethernet-Address b8:27:eb:84:35:e3
	  Vendor-rfc1048 Extensions
	    Magic Cookie 0x63825363
	    DHCP-Message Option 53, length 1: Request
	    Client-ID Option 61, length 19: hardware-type 255, eb:84:35:e3:00:01:00:01:c7:92:bc:8a:b8:27:eb:ba:90:94
	    Requested-IP Option 50, length 4: 192.168.2.9
	    MSZ Option 57, length 2: 1500
	    Vendor-Class Option 60, length 46: "dhcpcd-6.9.0:Linux-4.4.8-2-ARCH:armv6l:BCM2708"
	    Hostname Option 12, length 5: "amour"
	    T145 Option 145, length 1: 1
	    Parameter-Request Option 55, length 14: 
	      Subnet-Mask, Classless-Static-Route, Static-Route, Default-Gateway
	      Domain-Name-Server, Hostname, Domain-Name, BR
	      NTP, Lease-Time, Server-ID, RN
	      RB, Option 119
	    END Option 255, length 0
21:32:13.299825 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto UDP (17), length 576)
    192.168.2.254.67 > 192.168.2.9.68: [udp sum ok] BOOTP/DHCP, Reply, length 548, xid 0x4feaaa6f, Flags [none] (0x0000)
	  Your-IP 192.168.2.9
	  Client-Ethernet-Address b8:27:eb:84:35:e3
	  Vendor-rfc1048 Extensions
	    Magic Cookie 0x63825363
	    DHCP-Message Option 53, length 1: ACK
	    Server-ID Option 54, length 4: 192.168.2.254
	    Lease-Time Option 51, length 4: 43200
	    Subnet-Mask Option 1, length 4: 255.255.255.0
	    Default-Gateway Option 3, length 4: 192.168.2.254
	    Domain-Name-Server Option 6, length 8: 192.168.2.254,149.20.64.21
	    BR Option 28, length 4: 192.168.2.255
	    END Option 255, length 0
	    PAD Option 0, length 0, occurs 264   
    

Malheureusement, dans la requête du client se trouvent plein de détails sur la machine demanderesse (section 1 du RFC). Compte-tenu de la sensibilité aux problèmes de vie privée (RFC 6973) et de l'ampleur de la surveillance de masse exercée par les États (RFC 7258), il était nécessaire de limiter cette fuite d'informations. Ce premier RFC va décrire le problème, et proposer quelques pratiques qui le limitent. Le RFC 7844 détaille un profil DHCP qui limite sérieusement la fuite. Dans une prochaine étape, il y aura peut-être des modifications au protocole DHCP mais ce n'est pas encore fait.

Pour cette analyse de sécurité, la section 2 de notre RFC introduit la notion d'identificateur stable. Un identificateur stable (stable identifier) est une information envoyée par le client DHCP qui change peu ou pas dans le temps (et qui peut donc permettre de tracer une machine mobile). La stabilité peut dépendre de la mise en œuvre logicielle utilisée. Ainsi, une adresse MAC est typiquement un identificateur stable mais, si macchanger est utilisé, ce n'est plus le cas. Un identificateur stable n'est pas forcément mondialement unique.

Le gros de ce RFC est la section 3, qui liste les identificateurs envoyés par le client DHCP. Le plus évident, car il est prévu pour cela, est l'option DHCP Client Identifier (RFC 2131, section 2, et RFC 2132, section 9.14). Il est en général stable (le RFC 1533, prédécesseur du RFC 2132, recommandait même d'utiliser une adresse MAC, mais on voit parfois un nom de domaine, ou bien un DUID - décrit dans le RFC 4361). Même si on utilise un logiciel comme macchanger pour changer d'adresse MAC, pas mal de mises en œuvre de DHCP utiliseront la valeur initiale et la stockeront... pour toujours.

Moins spectaculaire, plusieurs champs de la requête transportent des identificateurs fondés sur une adresse. C'est le cas de yiadrr, qui indique l'adresse IP actuelle du client ou chaddr qui indique l'adresse MAC. Plusieurs options font de même comme la Requested IP Address (qui permet d'indiquer l'adresse IP qu'on souhaiterait recevoir).

Autre option qui envoie un identificateur stable, et souvent unique, l'option Client FQDN (RFC 4702) qui transmet au serveur le FQDN.

Après les adresses et les noms de domaine, un autre danger se présente avec les options qui permettent au client d'indiquer le logiciel qu'il utilise. C'est le cas de l'option Vendor class (RFC 2132, section 9.13, une sorte d'équivalent du User-Agent: de HTTP, dans l'exemple plus haut, elle indique une machine ARM sous Linux), du Vendor-Identifying du RFC 3925, et de toutes les options Vendor-specific information (RFC 2132, section 8.4), qui peuvent indiquer le numéro de version du logiciel utilisé, sa configuration spécifique, etc. Certes, elles ne sont pas uniques (elles ne désignent pas une machine particulière) mais elles font quand même fuiter de l'information sur le client et, combinées avec d'autres informations, elles peuvent mener à une identification unique. Une option analogue est Client System Architecture Type (RFC 4578) qui indique le type exact d'architecture pour les clients DHCP qui vont démarrer sur le réseau (par exemple avec PXE), en téléchargeant une version particulière du système d'exploitation. Si l'architecture utilisée est un peu rare, cette option donne des informations précieuses à un observateur.

En lisant cette liste, le paranoïaque peut se dire que la NSA a envoyé des gens à l'IETF pour faire normaliser le plus grand nombre possible d'extensions indiscrètes, de façon à être sûr d'identifier tous les clients DHCP observés. Il y a même une option pour indiquer l'adresse (civile, dans le monde physique, pas sur le réseau), Civic Location, dans le RFC 4776. Il est vrai que, contrairement à la plupart des options listées ici, elle est fournie par le serveur et pas par le client, et ne permet donc pas de suivre un client à la trace. Mais elle peut permettre à un observateur de savoir où, dans le monde physique, se situe le client.

Outre tous ces champs et ces options par lesquels une information souvent excessive est transmise, DHCP dispose de certains mécanismes qui peuvent être utilisés pour compromettre la vie privée (section 4 du RFC). Par exemple, l'option Client FQDN du RFC 4702, citée plus haut, sert souvent à faire des mises à jour dynamiques du DNS (RFC 2136), et, dans ce cas, l'adresse IP du client DHCP (qui peut indiquer sa localisation) et son nom, identificateur stable, sont publiés dans le DNS, que tout le monde peut consulter. On peut connaitre les déplacements d'une machine simplement en consultant ce DNS public, sans avoir besoin d'espionner des milliers de réseaux. L'observateur peut être très discret et, en toute légalité, vous suivre.

Autre mécanisme dangereux, la stratégie d'allocation du serveur DHCP. Lorsqu'un client DHCP réclame une adresse IP, le serveur peut la choisir de plusieurs façons, et certaines ont des conséquences pour la vie privée :

  • Allocation itérative : le serveur alloue les adresses IP dans l'ordre de la plage d'adresses dont il dispose. Elle est très simple et très rapide mais fournit des adresses IP qui sont très prévisibles. En outre, avec ce système, les premières adresses de la plage seront plus souvent utilisées, ce qui rendra encore plus facile des activités comme la reconnaissance d'un réseau avant une attaque.
  • Allocation fondée sur un identificateur : le serveur a une table et y cherche un des identificateurs transmis par le client, allouant l'adresse trouvée dans la table. C'est très pratique pour l'administrateur système, car une machine donnée aura toujours la même adresse IP. Mais c'est nettement moins bon pour la vie privée du client, qui sera ainsi trivialement pistable, par son adresse IP fixe.
  • Allocation aléatoire : le serveur DHCP prend au hasard une adresse IP libre. C'est sans doute la meilleure méthode, du point de vue de la protection de la vie privée.

La taille très restreinte de l'espace d'adressage IPv4 complique le problème, en limitant les possibilités du serveur d'utiliser certaines stratégies d'allocation, comme l'allocation fondée sur un identificateur (le serveur DHCP n'a pas forcément assez d'adresses IP pour tous ses clients potentiels.)

Bon, OK, le client DHCP envoie des tas d'identificateurs stables. Mais en quoi est-ce dangereux ? Qu'est-ce qu'un observateur indiscret peut en faire (section 5 du RFC) ? Déjà, il peut découvrir le type de machine qu'est le client (directement, via des options comme Vendor Class, ou indirectement, via l'adresse MAC (dont le préfixe, l'OUI, dépend en général du matériel utilisé). L'espion peut aussi trouver le système d'exploitation utilisé.

Il peut aussi apprendre les réseaux que le client avait visité précédemment. Le client met en effet dans l'option Requested IP Address la précédente adresse IP qu'il avait obtenue. Si c'est une adresse publique (pas issue du RFC 1918), cela renseigne sur le précédent réseau utilisé.

L'observateur peut facilement trouver un identificateur stable à partir d'une requête DHCP (en combinant les options comme Client FQDN). Cela lui permet, s'il a accès au trafic de plusieurs serveurs DHCP, de suivre les déplacements d'une machine (c'est ce qui se produit dans les cas de surveillance massive, cf. RFC 7258.)

Dans certains cas, l'observateur n'a même pas besoin d'être présent sur le réseau du serveur DHCP : si on fait des mises à jour dynamiques du DNS, il lui suffit de faire des requêtes DNS pour suivre les changements d'adresse IP (et donc de réseau) du client.

Bref, un client DHCP en dit en général trop à son serveur, et cela permet aux machines mobiles d'être facilement pistées. Notre RFC ne fournit pas de solutions immédiates, une solution est décrite dans le RFC 7844, d'autres feront l'objet d'un futur travail.


Téléchargez le RFC 7819


L'article seul

Articles des différentes années : 2016  2015  2014  2013  2012  2011  2010  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.