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.
Première rédaction de cet article le 11 Juin 2013
C'est tous les jours qu'il y a des problèmes sur l'Internet. Par exemple, hier soir, mon système de surveillance me prévient qu'une des machines qui porte ce blog n'est plus joignable (les requêtes HTTP échouent).
Plus joignable en IPv4 mais, en IPv6, la même machine répond bien en HTTP (je teste les deux protocoles séparément). En prime, l'examen du journal d'Apache montre que le serveur HTTP continue à recevoir de nombreuses requêtes en IPv4 avec succès.
Quelques coups de mtr donnent plus de détails. Depuis la machine qui fait la surveillance, 90 % de perte de paquets (cf. RFC 6673) dans les deux dernières étapes (le dernier routeur et le serveur Web lui-même). Depuis une machine sur un tout autre réseau, tout va bien, 0 % de pertes. Dans le premier cas, on passe par Level 3, dans le second par AboveNet. Donc, un problème sur la liaison entre Level 3 et l'hébergeur de cette machine, 6sync. Cet hébergeur explique rapidement le problème. C'était simplement encore une banale attaque par déni de service, qui visait un autre client de 6sync (aucun rapport avec moi, je vous rassure) et avait réussi à saturer le lien entre Level 3 et 6sync.
Un peu plus d'une heure de perturbation en tout, comme le montre le
joli graphique :
.
First publication of this article on 11 June 2013
Hotel networks are famous for their brokenness. It seems their network managers are fond of always finding some new and clever ways to break things. The famous Krasnapolsky hotel in Amsterdam, home of many RIPE meetings, decided to attack the DNS.
I discovered the problem during a CENTR
meeting. The DNSSEC-validating resolver on my
laptop did not work (SERVFAIL for every query). But
dig apparently did. Checking with
tcpdump :
10:47:24.578004 IP (tos 0x0, ttl 64, id 36388, offset 0, flags [none], proto UDP (17), length 56)
192.168.48.71.38053 > 192.58.128.30.53: [udp sum ok] 17756% [1au] NS? . ar: . OPT UDPsize=4096 OK (28)
10:47:25.567816 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto UDP (17), length 269)
192.58.128.30.53 > 192.168.48.71.38053: [udp sum ok] 17756 FormErr q: NS? . 13/0/0 [2d1h59m18s] NS j.root-servers.net., [2d1h59m18s] NS h.root-servers.net., [2d1h59m18s] NS g.root-servers.net., [2d1h59m18s] NS c.root-servers.net., [2d1h59m18s] NS e.root-servers.net., [2d1h59m18s] NS a.root-servers.net., [2d1h59m18s] NS m.root-servers.net., [2d1h59m18s] NS k.root-servers.net., [2d1h59m18s] NS b.root-servers.net., [2d1h59m18s] NS l.root-servers.net., [2d1h59m18s] NS f.root-servers.net., [2d1h59m18s] NS i.root-servers.net., [2d1h59m18s] NS d.root-servers.net. (241)
The first packet is a priming request from the resolver, trying to
check the list of the root name servers. The
replies is complete (full list of these servers) but with an abnormal
status: FormErr (Format Error). From RFC 1035, it means "The name server was
unable to interpret the query".
But if I try with dig? Here, I request the
DNSKEY of the root, from the server
K.root-servers.net, with the EDNS options a
real resolver would use:
% dig +bufsize=4096 +dnssec @193.0.14.129 DNSKEY . ; <<>> DiG 9.8.1-P1 <<>> +bufsize=4096 +dnssec @193.0.14.129 DNSKEY . ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41313 ;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;. IN DNSKEY ;; ANSWER SECTION: . 30672 IN DNSKEY 256 3 8 AwEAAc5byZvwmHUlCQt7WSeAr3OZ2ao4x0Yj/3UcbtFzQ0T67N7CpYmN qFmfvXxksS1/E+mtT0axFVDjiJjtklUsyqIm9ZlWGZKU3GZqI9Sfp1Bj Qkhi+yLa4m4y4z2N28rxWXsWHCY740PREnmUtgXRdthwABYaB2WPum3y RGxNCP1/ ...
Everything goes fine, it seems. No, there are three problems. I let you
check, I will explain later. But, first, why do I get a
NOERROR from dig and a
FORMERR when it's done by the resolver?
That's because dig sets the RD bit in the request (again, from the
RFC: "Recursion Desired - this bit may be set in a query and
is copied into the response. If RD is set, it directs
the name server to pursue the query recursively.
Recursive query support is optional."). Typical resolvers, unlike stub
resolvers like dig, do not set this bit. Let's try with
+norec which will disable this bit:
% dig +bufsize=4096 +dnssec +norec @193.0.14.129 DNSKEY . ; <<>> DiG 9.8.1-P1 <<>> +bufsize=4096 +dnssec +norec @193.0.14.129 DNSKEY . ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: FORMERR, id: 7135 ;; flags: qr ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;. IN DNSKEY ;; ANSWER SECTION: . 158539 IN DNSKEY 256 3 8 AwEAAc5byZvwmHUlCQt7WSeAr3OZ2ao4x0Yj/3UcbtFzQ0T67N7CpYmN qFmfvXxksS1/E+mtT0axFVDjiJjtklUsyqIm9ZlWGZKU3GZqI9Sfp1Bj Qkhi+yLa4m4y4z2N28rxWXsWHCY740PREnmUtgXRdthwABYaB2WPum3y RGxNCP1/ ...
OK, this is consistent: dig and my local resolver gets the same result, a Format Error. The network provider (Swisscom) did that to prevent people from running their own resolvers (or may be simply out of incompetence).
Do note the brokenness is not in the DHCP-provided resolver (which is almost always broken in hotel and airport networks). I queried directly the root name server. So, it's a real man-in-the-middle. As in China, the network intercepts the request (or the response) and rewrites it.
Anything else? I said there were three problems in the reply with the RD bit set. Did you find them? One is conspicuous: the DNSSEC signatures were stripped from the reply, preventing any local validation (the only safe way to do DNSSEC validation). The second is more subtle: the reply should have the AA bit set (from the RFC: "Authoritative Answer - this bit is valid in responses, and specifies that the responding name server is an authority for the domain name in question section.") since I queried directly a root name server. But it has not. Yet another information erased from the reply. And the third was noticed in this paper by Sebastian Castro: "RA [Recursion Available] is bit set when you are talking to a non-recursive server".
Of course, this sort of man-in-the-middle is very common. What's ironic here is that it takes place at the Krasnapolsky, which is an important place of the Internet in Europe. And that it happens in the Netherlands, which was the first country in the world to protect network neutrality by the law, law which is here blatantly violated.
Date de publication du RFC : Juin 2013
Auteur(s) du RFC : S. Santesson (3xA Security), M. Myers
(TraceRoute
Security), R. Ankney, A. Malpani (CA
Technologies), S. Galperin (A9), C. Adams (University of Ottawa)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF pkix
Première rédaction de cet article le 7 Juin 2013
Le protocole OCSP permet à un client X.509 (par exemple un navigateur Web engagé dans une connexion HTTPS) de s'informer en temps réel sur l'état d'un certificat, notamment afin de savoir s'il est révoqué ou pas. Ce nouveau RFC remplace (avec de légers changements) l'ancienne norme OCSP qui était dans le RFC 2560.
Normalement, le destinataire d'un certificat X.509 (par exemple le navigateur Web cité plus haut), authentifie ce dernier en utilisant les clés publiques des AC qu'il a dans son magasin, et en vérifiant dans une liste de CRL, mise à jour périodiquement, que le certificat est toujours d'actualité, qu'il n'a pas été révoqué par l'AC émettrice (section 3.3 du RFC 5280). En complément, ou à la place de ces CRL, le destinataire peut utiliser le protocole OCSP normalisé dans ce RFC. OCSP est un protocole synchrone : le destinataire du certificat émet une requête à un serveur OCSP et attend sa réponse avant de valider le certificat. Il peut ainsi obtenir des informations plus à jour qu'avec des CRL.
La requêtes OCSP contient (un survol du protocole figure en section
2 de ce RFC) le numéro de série du certificat qu'on veut authentifier. La réponse dépend
de si le répondeur (le serveur OCSP) a l'information sur ce
certificat. Si oui, il répond positivement (good,
le certificat est valable)
ou négativement (revoked, le certificat ne doit pas être accepté), en indiquant
l'heure (un certificat valable à un moment peut être révoqué par la
suite) et sa réponse est signée (typiquement
avec le certificat de l'AC). Si non, si le
répondeur n'a pas l'information, il répond unknown.
Les réponses possibles sont donc good,
revoked et unknown. Notez
que, de manière surprenante, good ne dit pas que le certificat existe,
simplement qu'il n'a pas été révoqué. (Cette question a fait l'objet
de chauds débats dans le groupe de travail : que doit faire un
répondeur OCSP lorsqu'il reçoit une requête pour un certificat qu'il
est censé connaître mais qu'il
n'a pas émis ?)
Le répondeur peut aussi être dans l'incapacité de fournir une
réponse et, dans ce cas, le message d'erreur résultant n'est pas
signé. Parmi les causes possibles d'erreur, une requête incorrecte,
une erreur dans le répondeur (équivalent du 500 Internal
server error de HTTP), un problème
temporaire qui nécessite que le client réessaie plus tard, un client
non autorisé, etc.
La réponse inclut souvent des temps : dernier moment où l'information retournée était correcte, moment de la prochaine mise à jour de l'information, moment de la signature de l'information (les réponses peuvent être pré-produites) ou moment où la révocation a eu lieu.
Mais comment un destinataire de certificat sait-il
où trouver le serveur OCSP ? Il est typiquement indiqué dans le
certificat qu'on teste, dans l'extension Authority Information
Access (section 4.2.2.1 du RFC 5280). Si la méthode d'accès est
id-ad-ocsp, le contenu de cette extension est un
URL pointant
vers le serveur OCSP.
Voici un exemple dans un certificat récupéré sur l'Internet :
% openssl x509 -text -in /tmp/site.pem
...
Authority Information Access:
OCSP - URI:http://rapidssl-ocsp.geotrust.com
CA Issuers - URI:http://rapidssl-aia.geotrust.com/rapidssl.crt
Mais cette information peut aussi être codée en dur dans le client.
La plupart du temps, l'URL en question sera un URL
HTTP, et OCSP tournera donc au dessus de ce
protocole (parfois en HTTPS). L'annexe A décrit en détail ce mécanisme. OCSP peut
utiliser GET ou POST. Dans
ce dernier cas, la requête HTTP aura le type
application/ocsp-request et la requête OCSP forme le corps de la requête
POST, après son encodage en
DER. Même chose pour la réponse, type
application/ocsp-response, et du DER dans le
corps HTTP.
Voilà, vous savez l'essentiel, la section 4 décrit tout le
protocole, en ASN.1 (en s'appuyant sur les
modules de l'annexe B). Par exemple, une requête
est une TBSRequest qui contient plusieurs
Request, chacune concernant un certificat :
OCSPRequest ::= SEQUENCE {
tbsRequest TBSRequest,
optionalSignature [0] EXPLICIT Signature OPTIONAL }
TBSRequest ::= SEQUENCE {
version [0] EXPLICIT Version DEFAULT v1,
requestorName [1] EXPLICIT GeneralName OPTIONAL,
requestList SEQUENCE OF Request,
requestExtensions [2] EXPLICIT Extensions OPTIONAL }
...
Request ::= SEQUENCE {
reqCert CertID,
singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL }
CertID ::= SEQUENCE {
hashAlgorithm AlgorithmIdentifier,
issuerNameHash OCTET STRING, -- Hash of Issuer's DN
issuerKeyHash OCTET STRING, -- Hash of Issuers public key
serialNumber CertificateSerialNumber }
Et la réponse est un code de retour et la réponse elle-même :
OCSPResponse ::= SEQUENCE {
responseStatus OCSPResponseStatus,
responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
OCSPResponseStatus ::= ENUMERATED {
successful (0), --Response has valid confirmations
malformedRequest (1), --Illegal confirmation request
internalError (2), --Internal error in issuer
tryLater (3), --Try again later
--(4) is not used
sigRequired (5), --Must sign the request
unauthorized (6) --Request unauthorized
}
ResponseBytes ::= SEQUENCE {
responseType OBJECT IDENTIFIER,
response OCTET STRING }
Avec response comportant à son tour des
structures ASN.1 arrivant finalement à :
SingleResponse ::= SEQUENCE {
certID CertID,
certStatus CertStatus,
thisUpdate GeneralizedTime,
nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL,
singleExtensions [1] EXPLICIT Extensions OPTIONAL }
CertStatus ::= CHOICE {
good [0] IMPLICIT NULL,
revoked [1] IMPLICIT RevokedInfo,
unknown [2] IMPLICIT UnknownInfo }
RevokedInfo ::= SEQUENCE {
revocationTime GeneralizedTime,
revocationReason [0] EXPLICIT CRLReason OPTIONAL }
On note que la raison de la révocation est indiquée. Elle n'est pas toujours indiquée par le répondeur OCSP (cela peut être une information sensible). La présence de cette information dans les CRL a permis à l'EFF de réaliser une intéressante étude sur les raisons des révocations (la section « How often are these attacks occurring? »).
La section 5 revient sur l'analyse de sécurité d'OCSP. On notera que les problèmes de vie privée n'y sont pas mentionnés. Pourtant, la requête OCSP indique au répondeur (en général l'AC) quels sites Web ont été visités. C'est d'ailleurs ainsi qu'il a été possible de prouver l'utilisation en Iran des vrais/faux certificats de DigiNotar, en regardant les requêtes OCSP de leurs navigateurs vers l'AC.
Un autre problème de sécurité n'est pas mentionné : que doit faire le navigateur Web qui tente d'authentifier un certificat lorsque la requête OCSP n'aboutit pas (peut-être parce qu'un Homme du Milieu bloque l'accès au serveur OCSP) ? S'il refuse d'authentifier le certificat, la connexion échoue. Mais s'il accepte, OCSP ne protège plus tellement.
Les changements depuis le RFC 2560 sont mineurs, et sont résumés dans la section 1.
Merci à Erwann Abalea pour sa relecture précise.
Date de publication du RFC : Juin 2013
Auteur(s) du RFC : B. Laurie, A. Langley, E. Kasper (Google)
Expérimental
Première rédaction de cet article le 7 Juin 2013
Plusieurs attaques spectaculaires, notamment celle contre DigiNotar, ont montré la fragilité de l'actuel système de gestion de certificats X.509. Comme n'importe quelle AC peut émettre un certificat pour n'importe quel nom de domaine, il ne suffit pas d'évaluer la sécurité de son AC, il faudrait idéalement évaluer toutes les AC. Ce RFC propose une approche différente : encourager/obliger les AC à publier « au grand jour » les certificats qu'elles émettent. Un titulaire d'un certificat qui craint qu'une AC n'émette un certificat à son nom sans son autorisation n'a alors qu'à surveiller ces publications. (Il peut aussi découvrir à cette occasion que sa propre AC s'est fait pirater ou bien est devenue méchante et émet des certificats qu'on ne lui a pas demandés.)
Ce n'est pas par hasard que les auteurs de ce RFC sont trois
employés de Google. Dans l'affaire
DigiNotar, comme dans d'autres affaires
analogues, le premier vrai/faux certificat émis par celui qui a piraté
une AC est souvent un certificat pour
gmail.com, de façon à permettre d'espionner le
trafic vers Gmail. La proposition de ce RFC
(qui est encore expérimental) est d'empêcher l'émission « discrète »
de vrais/faux certificats qui seraient ensuite utilisés uniquement à
certains endroits (l'Iran dans le cas de
DigiNotar mais cela peut aussi concerner des entreprises qui font des
attaques de l'homme du milieu contre leurs propres employés).
Le principe est donc de créer un (ou plusieurs) journal des certificats émis. Le journal doit être public, pour que Google ou n'importe qui d'autre puisse l'auditer. Il doit être en mode « ajout seulement » pour éviter qu'on puisse réécrire l'histoire. Les certificats sont déjà signés mais le journal a ses propres signatures, pour prouver son intégrité. Conceptuellement, ce journal est une liste de certificats dans l'ordre de leur création. Toute AC peut y ajouter des certificats (la liste ne peut pas être ouverte en écriture à tous, de crainte qu'elle ne soit remplie rapidement de certificats bidons). En pratique, le RFC estime que la liste des AC autorisées à écrire dans le journal sera l'union des listes des AC acceptées dans les principaux navigateurs Web (voir aussi la section 4.7).
À chaque insertion, le journal renvoie à l'AC une estampille temporelle signée, permettant à l'AC de prouver qu'elle a bien enregistré le certificat. Si une AC peut présenter cette signature mais que le certificat est absent du journal, l'observateur aura la preuve que le journal ne marche pas correctement. Le format exact de cette estampille temporelle est décrit en section 3.2. Elle devra être envoyée au client par les serveurs TLS, comme preuve de la bonne foi de l'AC (cf. sections 3.3 et 5.2).
Les titulaires de certificats importants, comme Google, mais aussi des chercheurs, des agences de sécurité, etc, pourront alors suivre l'activité de ce(s) journal (journaux) public(s) (section 5.3 du RFC). Ce qu'ils feront en cas de détection d'un certificat anormal (portant sur leur nom de domaine, mais qu'ils n'ont pas demandé) n'est pas spécifié dans le RFC : cela dépend de la politique de l'organisation concernée. Ce RFC fournit un mécanisme, son usage n'est pas de son ressort. Ce journal n'empêchera donc pas l'émission de vrais/faux certificats, ni leur usage, mais il les rendra visibles plus facilement et sans doute plus vite.
Pour que cela fonctionne, il faudra que les clients TLS vérifient que le certificat présenté est bien dans le journal (autrement, le méchant n'aurait qu'à ne pas enregistrer son vrai/faux certificat, cf. section 5.4 du RFC).
En pratique, la réalisation de ce journal utilise un arbre de Merkle, une structure de données qui permet de mettre en œuvre un système où l'ajout de certificats est possible, mais pas leur retrait. La section 2 du RFC détaille l'utilisation de ces arbres et la cryptographie utilisée.
Le protocole utilisé entre les AC et le journal, comme celui
utilisé entre les clients TLD et le journal, sera
HTTP et le format des données sera
JSON (section 4). Ainsi, pour ajouter un
certificat nouvellement émis au journal géré sur
sunlight-log.example.net, l'AC fera :
POST https://sunlight-log.example.net/ct/v1/add-chain
et le corps de la requête HTTP sera un tableau JSON de certificats encodés en Base64. La réponse contiendra notamment l'estampille temporelle (SCT pour Signed Certificate Timestamp). Pour récupérer des certificats, le programme de surveillance fera par exemple :
GET https://sunlight-log.example.net/ct/v1/get-entries
D'autres URL permettront de récupérer les condensats cryptographiques contenus dans l'arbre de Merkle, pour s'assurer qu'il est cohérent.
Notez que Google a produit une mise en œuvre de ce RFC, qui semble activement développée. Il y a aussi une liste de diffusion sur ce projet. Sinon, si vous voulez en savoir plus sur cette idée de vérification publique, consultez « Efficient Data Structures for Tamper-Evident Logging » de Scott A. Crosby et Dan S. Wallach.
Quelles sont les chances de succès de cette idée ? Tant que peu d'AC participent, ces journaux ne serviront pas à grand'chose (le méchant attaquera uniquement les AC non participantes). L'idée est qu'à moyen terme, la pression sur les AC (directement ou bien via les navigateurs Web qui ne feraient plus confiance aux AC non participantes) pourra faire que tous les certificats devront être dans le journal et que l'examen de celui-ci suffira à détecter les « vrais/faux certificats ».
Merci à Florian Maury pour sa relecture très détaillée.
Date de publication du RFC : Mai 2013
Auteur(s) du RFC : D. McPherson (VeriSign), F.J. Baker (Cisco Systems), J.M. Halpern (Ericsson)
Pour information
Réalisé dans le cadre du groupe de travail IETF savi
Première rédaction de cet article le 30 Mai 2013
On sait que, sur l'Internet, il est possible et même facile d'usurper une adresse IP , c'est-à-dire d'émettre un paquet IP avec une adresse source allouée à quelq'un d'autre (ou pas allouée du tout). Le projet SAVI (Source Address Validation Improvement) vise à améliorer la validation de l'adresse source, de manière à rendre l'usurpation plus rare et plus difficile. Ce RFC décrit la menace à laquelle SAVI répondra et étudie les contre-mesures existantes.
L'Internet emploie un protocole de réseau sans connexion (que ce soit en IPv4 ou en IPv6). Lorsqu'une machine veut communiquer avec une autre, elle met son adresse IP comme source d'un paquet, celle de son correspondant en destination et elle envoie le paquet. Substituer l'adresse IP d'une autre machine à la sienne est donc aussi simple que d'écrire une autre chaîne de bits à la place de l'adresse authentique. Le réseau n'essaie pas d'empêcher cela. Certes, le fraudeur ne pourra pas forcément recevoir les réponses (elles arriveront à celui dont l'adresse a été usurpée) mais ce n'est pas forcément un problème dans un réseau sans connexion. Il existe des mécanismes pour empêcher cette usurpation, le plus connu étant BCP 38 (les RFC 2827 et RFC 3704) mais ils sont insuffisamment déployés, car ils n'apportent pas de bénéfices à celui qui les déploie, uniquement aux autres acteurs de l'Internet. En outre, BCP 38 ne protège pas toujours suffisamment. Par exemple, s'il est mis en œuvre dans le premier routeur, il n'empêchera pas les machines du LAN d'usurper les adresses de leurs voisines.
L'une des idées de SAVI est donc de compléter BCP 38 avec des validations locales, apportant un bénéfice local, et qui permettraient une meilleure traçabilité.
Quelques termes à apprendre pour bien suivre les documents sur SAVI :
La section 3 détaille ensuite les attaques rendues possibles, ou facilitées par l'usurpation d'adresses IP source (la section 4 couvrira les contre-mesures). D'abord, les attaques en aveugle : l'assaillant, qui a usurpé l'adresse IP source, ne peut pas recevoir les réponses à ses paquets. Il peut les envoyer, ces paquets, mais c'est tout. Cela lui complique évidemment sérieusement la vie. Certaines attaques restent possibles. Il y a celles ne nécessitant qu'un seul paquet (et donc pas de réponse). Par exemple, si un paquet spécialement construit plante le logiciel du routeur qui le traite, un attaquant peut monter une attaque par déni de service en envoyant un unique packet of death. Un autre cas est celui où, en envoyant un paquet où l'adresse source et destination sont identiques, le destinataire se réponde à lui-même, puis à la réponse de la réponse, et entretienne ainsi lui-même la boucle sans fin (une bogue de cette famille avait frappé PowerDNS).
Une autre attaque en aveugle est le RST (ReSeT) TCP usurpé (section 2.3 du RFC 4953). Un seul paquet TCP accepté (l'attaquant doit deviner un numéro de séquence contenu dans la fenêtre en cours) va couper la connexion (notez que les protocoles applicatifs comme TLS et SSH ne sont d'aucune utilité contre cette attaque). Cela peut être très gênant pour les connexions censées durer longtemps (sessions BGP par exemple). Il existe des contre-mesures (voir le RFC 5961) mais empêcher l'usurpation d'adresse IP empêcherait complètement cette attaque.
Après les attaques en aveugle formées d'un seul paquet, place aux attaques volumétriques, reposant sur l'envoi d'un grand nombre de paquets. L'idée est de remplir certaines tables de taille fixe (par exemple la table des connexions entrantes) ou, encore plus simplement, de saturer le réseau de la victime. L'attaquant n'ayant pas besoin de réponse, il a tout intérêt, dans ces paquets, à usurper l'adresse IP source pour déguiser son identité. On constate que beaucoup de gens n'ont pas encore compris la facilité avec laquelle cette usurpation est possible, et croient réellement que l'adresse IP source qu'ils observent dans les paquets entrants est réellement celle de leur attaquant (pensez à cela la prochaine fois que vous lirez dans les médias quelque chose du genre « attaque par déni de service contre tel organisme, l'examen de l'attaque montrait que l'attaquant venait de Russie/Chine/Moyen-Orient »). Pire, la victime bloque parfois les paquets IP entrants en fonction de cette adresse source, réalisant ainsi une autre attaque par déni de service, contre la victime de l'usurpation d'adresse. Certaines attaques peuvent d'ailleurs être montées dans ce seul but.
Une autre raison pour l'attaquant d'usurper l'adresse IP source est la possibilité d'attaque par réflexion : comme au billard, on va viser une autre boule que celle qu'on veut vraiment toucher. L'attaquant envoie un paquet UDP au réflecteur (qui n'est pas sa vraie victime, juste un complice involontaire) en usurpant l'adresse IP source de la victime. Le réflecteur va alors répondre à ce qu'il croit être l'émetteur et qui est en fait la victime, qui sera ainsi bombardée par le ou les réflecteurs. La réflexion sert à l'attaquant à dissimuler ses traces (le paquet va suivre un tout autre chemin dans le réseau) mais elle est surtout intéressante couplée avec l'amplification. Avec certains protocoles, la réponse va être plus grande, voire beaucoup plus grande, que la requête. Avec une amplification de 20, l'attaquant pourra ainsi obtenir un bombardement de 1 Gb/s en ne dépensant lui-même que 50 Mb/s. Plusieurs protocoles permettent l'amplification, comme NTP, SNMP et surtout le DNS comme ce fut le cas lors de l'attaque de 2006 (le RFC ne les cite pas mais des attaques plus violentes ont eu lieu en 2012 et 2013).
Le RFC classe aussi dans les attaques volumétriques les actions visant à empoisonner les données d'un serveur distant. Le cas le plus courant est celui des empoisonnements DNS où le méchant va tenter de répondre avant le serveur légitime (cas, par exemple, des attaques Kaminsky). Ici, le volume élevé des requêtes n'est pas dû au désir de saturer la victime, mais à la nécessité de faire beaucoup d'essais pour en voir un accepté. (Dans le cas du DNS, il s'agit d'essayer beaucoup de Query ID et de ports source UDP.) À noter qu'il existe aussi des attaques par empoisonnement contre les caches ARP.
Cela, c'était les attaques en aveugle. Mais, parfois, un attaquant qui usurpe une adresse IP peut observer les réponses, par exemple parce qu'il est sur le même réseau local à diffusion que la victime de l'usurpation ou bien, si le réseau local ne diffuse pas à tous, parce qu'il a empoisonné les caches ARP. L'attaquant a alors bien plus de possibilités comme le détournement d'une connexion TCP à son profit, les tests de vulnérabilité d'un objectif sans se trahir, la subversion des protocoles de routage en se faisant passer pour un des routeurs participants, etc.
La section 4 décrit ensuite les contre-mesures qui peuvent être
adoptées aujourd'hui et qui sont effectivement déployées, au moins
partiellement. Par exemple, un commutateur peut
(en violant légèrement le modèle en couches),
refuser les paquets dont l'adresse IP source ne correspond pas à
l'adresse MAC du paquet (que le commutateur a pu apprendre en
examinant les requêtes et réponses ARP). Ou bien ceux qui viennent d'un autre port
physique que d'habitude. Si les paquets de
192.168.7.64 venaient toujours du port 3 et que,
tout à coup, ils viennent du port 4, le commutateur peut soupçonner
une usurpation (ou tout simplement une machine qui a été déplacée : la
sécurité peut se tromper).
On peut donc jeter un paquet lorsque son adresse IP source ne correspond pas aux informations qu'on possède. Notez bien que, plus on s'éloigne de la source des paquets, plus il est difficile d'être sûr que c'est bien une usurpation. Néanmoins, le RFC identifie cinq endroits où peut se faire cet examen de validité, du plus proche de la source au plus éloigné :
2001:db8:32:a17::/64 à l'Internet peut
raisonnablement jeter un paquet venant du réseau local et prétendant
avoir comme source 2001:db8:cafe::666. Notez que
le routeur ne peut en général rien faire contre une machine qui
usurperait une adresse du même réseau local (ici,
2001:db8:32:a17::b00c qui se ferait passer pour
2001:db8:32:a17::babe). Dans des cas moins
triviaux (routeurs avec beaucoup d'interfaces et ayant de nombreux préfixes derrière eux), pour savoir quels
préfixes sont acceptables, le routeur peut simplement consulter une
ACL maintenue manuellement ou alors utiliser
RPF (RFC 3704).En pratique, il y a des tas de détails qui compliquent la validation d'adresse IP source. Par exemple, pour un commutateur réseau, le cas simple est celui où il y a une et une seule machine derrière chaque port physique et où chaque adresse MAC ne correspond qu'à une seule adresse IP. Si ce n'est pas le cas, le problème devient plus difficile. Pensez par exemple à une machine physique, connectée par le port d'un commutateur mais portant plusieurs machines virtuelles, chacune avec sa propre adresse IP et sans doute sa propre adresse MAC. Ce cas est en fait un commutateur interne, le commutateur physique n'étant que le deuxième commutateur sur le trajet et n'ayant donc que des capacités de validtaion limitées. Idéalement, c'est le commutateur virtuel dans le système de virtualisation qui devrait faire respecter les règles SAVI, mais l'administrateur réseaux n'en a pas forcément le contrôle et ne lui fait pas forcément confiance.
Pour apprendre le lien entre une adresse MAC et une adresse IPv4, la meilleure solution pour un commutateur est d'écouter les requêtes et les réponses DHCP et de considérer qu'elles font autorité au sujet de ce lien. Par exemple, en voyant passer cette réponse (vue avec tcpdump) :
09:49:23.191187 00:10:db:ff:40:70 > 18:03:73:66:e5:68, ethertype IPv4 (0x0800), length 368: (tos 0x0, ttl 64, id 16537, offset 0, flags [none], proto UDP (17), length 354)
192.0.2.20.67 > 192.0.2.54.68: BOOTP/DHCP, Reply, length 326, hops 1, xid 0x903b4b00, Flags [none]
Your-IP 192.0.2.54
Client-Ethernet-Address 18:03:73:66:e5:68
...
Le commutateur sait alors que l'adresse IP
192.0.2.54 a été allouée à
18:03:73:66:e5:68 et qu'un paquet IP dont
l'adresse MAC source serait 18:03:73:66:e5:68 et
l'adresse IP source serait autre chose que
192.0.2.54 est probablement une usurpation et
doit être jeté.
Pour IPv6, outre le trafic DHCP, le commutateur doit écouter les paquets DAD (Duplicate Address Detection) du protocole d'auto-configuration (RFC 4862). Le commutateur sera alors au courant des adresses IP légitimement enregistrées, et de l'adresse MAC correspondante, et pourra se servir de cette information pour valider. Par contre, contrairement à ce qu'on pourrait penser, le protocole d'authentification 802.1x n'aide pas : il authentifie un utilisateur mais ne limite pas les adresses IP qu'il peut utiliser. Enfin, il existe des techniques cryptographiques qui pourraient être utiles pour SAVI comme le SEND du RFC 3971 mais qui sont tellement peu déployées qu'on ne peut pas réellement compter dessus.
Certaines topologies de réseau, quoique parfaitement légales, peuvent sérieusement handicaper SAVI (section 5). Par exemple, si toutes les adresses sont statiques et stables, le problème est relativement bien circonscrit. Mais dans beaucoup de réseaux, ce n'est pas le cas et des adresses sont attribuées dynamiquement. Une même adresse IP sera, dans le temps, allouée à plusieurs adresses MAC et une même adresse MAC n'aura pas forcément la même adresse IP à chaque visite de ce réseau. (Ceux qui utilisent arpwatch sur un tel réseau savent le nombre d'« alarmes » que cela génère. SAVI a exactement le même problème.) D'autre part, si certaines machines sont simples (une adresses MAC, une adresse IP), d'autres sont plus complexes pour le validateur. Un exemple typique est un routeur. Par définition, il émet sur le réseau local des paquets avec sa propre adresse MAC mais des adresses IP source qui ne sont pas la sienne. Il est donc difficile de valider ces paquets.
Autre cas rigolo, notamment en cas de virtualisation : si une machine se déplace dans le data center mais garde son adresse IP. Les commutateurs vont devoir oublier la vieille information sur le port où est connecté cette machine et apprendre la nouvelle. (On appelle cela « mettre à jour son état SAVI ».)
La mobilité entraîne aussi des problèmes. Dans IP, elle peut se réaliser de plusieurs façons. Dans l'une, dite « en jambe de chien », la machine mobile émet des paquets avec son adresse IP source stable (home address), quel que soit le réseau physique où elle est attachée. Un tel mécanisme est évidemment incompatible avec toute solution de validation. Il faut donc que tous les paquets du mobile, aussi bien en émission qu'en réception, soient relayés par la station de base située sur son réseau d'attachement habituel.
Un petit mot aussi sur IPv6 : il crée des difficultés supplémentaires en raison de l'auto-configuration, très pratique mais, par son caractère local, non contrôlé centralement, pas forcément très sûre. Et son espace d'adressage très large (une bonne chose, et la principale raison pour laquelle il est important de déployer IPv6) a comme effet de bord la facilité à utiliser beaucoup d'adresses usurpées. En IPv4, un usurpateur a en théorie 2^32 adresses à usurper et, en pratique, plutôt moins de 2^24 (uniquement celles de son réseau local). En IPv6, même si on arrive à limiter l'usurpateur à son réseau local, il aura 2^64 adresses, ce qui permet de court-circuiter certains mécanismes de sécurité.
La section 6 revient en détail sur la question de la granularité de la validation. Aujourd'hui, il est relativement facile d'empêcher les usurpations inter-sites (où un attaquant prend l'adresse IP d'une machine sur un autre site). Mais empêcher les usurpations intra-sites est plus complexe or, justement, la plupart des attaques viennent de l'intérieur.
Notez que SAVI se limite aux couches basses : il n'est pas prévu de
vérifier les adresses IP qui apparaissent dans les applications (par
exemple dans le champ Received: des messages
formatés suivant le RFC 5322).
Enfin, la section 7 revient sur les questions de sécurité à un haut niveau. Elle rappelle que SAVI n'a pas pour but de produire des preuves, au sens judiciaire du terme (dans le meilleur cas, la validation permet de s'assurer de l'adresse IP, mais certaines machines sont multi-utilisateurs). Elle rappelle aussi que SAVI est une technique relativement légère et que, même si elle était massivement déployé, il ne faudrait pas utiliser les adresses IP source comme authentiques. La seule solution fiable pour être certain de l'identité de son correspondant est la cryptographie.
Cette section 7 revient aussi en détail sur les conséquences de SAVI pour la vie privée. Une adresse IP peut être vue, dans certains cas, comme une donnée identifiant une personne et le fait de la valider a donc des implications. Le RFC note bien que la validation SAVI ne nécessite pas d'enregistrer de l'information et que, si on réalise cet enregistrement avec des adresses IP, on peut engager sa responsabilité morale et/ou légale.
Aujourd'hui, des fonctions de type SAVI sont présentes dans pas mal de systèmes (par exemple les commutateurs haut de gamme) mais pas forcément toujours activées. Le RFC 5210 contient un compte-rendu d'expériences à ce sujet.
Date de publication du RFC : Mai 2013
Auteur(s) du RFC : M. Tuexen (Muenster Univ. of Appl. Sciences), R. R. Stewart (Adara Networks)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF tsvwg
Première rédaction de cet article le 30 Mai 2013
Normalement, un nouveau protocole de transport comme SCTP ne devrait avoir besoin de l'autorisation de personne pour être déployé entre deux machines majeures et consentantes. Le modèle de l'Internet, fondé sur le protocole IP, permet aux machines terminales, sans autorisation d'un intermédiaire, de communiquer en mettant ce qu'elles veulent dans les paquets IP. Cela, c'est la théorie. En pratique, par incompétence, sécurité ultra-rigide ou paresse, des tas d'intermédiaires se permettent de se placer sur le chemin entre deux machines et ne laissent passer qu'un petit nombre de protocoles de transport (typiquement uniquement TCP et UDP). Un nouvel arrivé (SCTP a quand même été normalisé dans le RFC 2960 en 2000 donc, « nouveau » est relatif ; la norme actuelle est le RFC 4960) a donc le plus grand mal à se faire une place au soleil. On en est donc réduit à des astuces plus ou moins propres comme celle décrite dans ce RFC : encapsuler SCTP dans de l'UDP.
La principale cible visée est donc le grand nombre de machines coincées derrière un routeur NAT. Mais cette encapsulation peut aussi servir pour mettre en œuvre SCTP sans avoir accès au noyau, entièrement dans une application, sans avoir de privilèges particulier (ce qui est souvent nécessaire pour implémenter un protocole de transport). Attention, il ne s'agit pas de faire un tunnel pour mettre en relation deux réseaux, mais de faire communiquer deux machines terminales qui voudraient faire du SCTP et qui en sont empêchées par une middlebox (cf. section 4).
Pourquoi UDP, au fait, et pas TCP ? Parce que SCTP fournit tous les services de TCP (notamment le contrôle de congestion et la fiabilité) et qu'il ferait donc double emploi avec TCP.
Notez que rien n'empêcherait de faire un routeur NAT qui permettrait SCTP, comme ils permettent aujourd'hui de faire du TCP et de l'UDP. C'est juste que de tels routeurs, s'ils existent, sont très rares.
Bon, et comment SCTP sur UDP fonctionne (section 5) ? On utilise par défaut le port de destination et de source 9899. Toutefois, celui-ci aura pu être modifié en route par un routeur NAT et le port à l'arrivée sera donc peut-être différent. D'autre part, certaines machines peuvent se trouver dans l'obigation d'écouter sur un autre port et il faut donc qu'une mise en œuvre de ce RFC soit capable d'utiliser un port différent par correspondant (cf. l'API plus loin), et de se souvenir de ces ports. On met le paquet SCTP dans un paquet UDP qui sera lui-même transporté dans IP (peut-être avec des en-têtes d'extension, dans le cas d'IPv6). La somme de contrôle UDP doit être mise (même en IPv4 où elle est normalement facultative ; et, pour IPv6, on n'a pas le droit d'utiliser l'exception du RFC 6935).
C'est simple mais il y a quelques petits pièges. D'abord, avec les messages ICMP (section 5.5) : lors de leur réception, il n'y aura pas forcément assez d'octets du message original pour trouver l'association SCTP à qui envoyer le message ICMP. Il faudra alors jeter ce dernier sans remords. La mise en œuvre de SCTP doit donc être capable de se débrouiller sans les messages ICMP, dont la réception ne peut pas être garantie.
Deuxième piège, commun à toutes les techniques d'encapsulation, la MTU (section 5.6). SCTP doit penser à diminuer la MTU de la taille de l'en-tête UDP. Et se souvenir qu'ICMP est encore moins garanti lorsqu'on utilise l'encapsulation UDP donc les procédures de découverte de la MTU du chemin (RFC 4820 et RFC 4821) doivent fonctionner même si on ne reçoit pas les messages ICMP.
Dernier piège, mais crucial, le contrôle des adresses IP source
des paquets UDP. Pour les associations SCTP à une seule adresse IP, il ne faut
pas indiquer l'adresse IP de la machine dans les
sous-paquets (chunks) de type INIT
(section 3.3.2 du RFC 4960) mais la mettre dans
le paquet UDP (ce que fait UDP par défaut). Et si la machine a
plusieurs adresses IP, il faut se servir des mécanismes des RFC 5061 et RFC 4895 pour les faire connaître au correspondant, et non pas mettre les adresses IP dans les sous-paquets
SCTP car l'intervention d'un routeur NAT modifierait l'adresse source,
rendant ces sous-paquets invalides.
Et pour les applications, quels mécanismes sont nécessaires pour
faire fonctionner cette encapsulation ? La section 6 propose des
changements à l'API du RFC 6458, avec l'ajout d'une option
SCTP_REMOTE_UDP_ENCAPS_PORT qui prendra en
paramètre une structure :
struct sctp_udpencaps {
sctp_assoc_t sue_assoc_id;
struct sockaddr_storage sue_address;
uint16_t sue_port;
};
Ce qui permettra de définir/connaître les adresses IP et les ports utilisés par l'encapsulation UDP.
Depuis sa version 9.1, FreeBSD a la capacité
d'utiliser cette encapsulation pour envoyer des paquets SCTP. Un
portage a été fait vers Mac OS X, disponible en
http://sctp.fh-muenster.de.
Date de publication du RFC : Mai 2013
Auteur(s) du RFC : J. Schaad (Soaring Hawk Consulting), H. Prafullchandra (Hy-Trust)
Chemin des normes
Première rédaction de cet article le 30 Mai 2013
Lorsqu'on détient une clé cryptographique privée et qu'on veut le prouver à un correspondant, la méthode la plus simple et la plus standard est de signer un message avec cette clé et de l'envoyer audit correspondant, qui, en vérifiant la signature, s'assurera qu'on était bien en possession de la clé privée. Mais dans certains cas, signer n'est pas possible. Ce RFC décrit trois algorithmes qui permettent de prouver qu'on connait une clé, sans signer. Il remplace le RFC 2875.
Ce test de POP (Proof Of Possession) est un de ceux que doit faire, par exemple, une autorité de certification, avant de signer un certificat. (Le RFC 4211, annexe C, explique pourquoi c'est important.) Ainsi, une CSR (demande de signature d'un certificat) faite par OpenSSL est signée et cela peut se vérifier :
% openssl req -verify -in server.csr -noout verify OK
Le format CRMF du RFC 4211 et le format PKCS#10 permettent tous les deux d'envoyer une demande de signature de certificat à une AC mais seul CRMF a un moyen d'inclure une POP pour les algorithmes ne permettant pas de signature. PKCS#10 (RFC 2986) n'a rien. Cela existe, de tels algorithmes, ne permettant pas de signature ? Oui, c'est le cas de Diffie-Hellman et de ECDH.
Les trois algorithmes de POP de notre RFC sont le Diffie-Hellman statique en section 4, le logarithme discret en section 6 et l'ECDH statique en section 6. Ne me demandez pas de vous les expliquer, cela dépasse largement mes compétences en cryptographie. Lisez le RFC pour cela. (Et révisez le RFC 6090 pour le troisième, qui utilise les courbes elliptiques.) Notre RFC 6955 fournit les algorithmes et les modules ASN.1 qui les décrivent.
La section 1.1 décrit les changements depuis le RFC 2875. Les deux algorithmes du précédent RFC ont été réécrits pour permettra leur paramétrisation par rapport à la fonction de condensation (obligatoirement SHA-1 dans l'ancien RFC, alors que plusieurs fonctions sont désormais possibles, notamment la famille SHA-2). Et un troisième algorithme a été ajouté, pour ECDH.
Première rédaction de cet article le 26 Mai 2013
Il y a des chercheurs ambitieux. En voici qui proposent un protocole qui veut remplacer à la fois TCP et TLS et IPsec. Ils exagèrent ? Pas complètement. Le projet est prometteur (mais encore à ses tout débuts) mais il y a quelques points noirs qu'ils « oublient » de mentionner.
Le projet MinimaLT (à ne pas confondre avec l'application Apple qui s'écrit minimALT) ne semble pas avoir encore publié de code. Il y un article assez détaillé (lien alternatif), un joli poster publicitaire et c'est tout. Donc, pour l'instant, tout est à étudier avec prudence.
À quel problème s'attaque MinimaLT ? Les auteurs estiment que du TCP sans chiffrement est vraiment trop dangereux dans l'Internet d'aujourd'hui et qu'il faudrait du chiffrement partout. Des protocoles comme TLS (RFC 6347) ou IPsec (RFC 4301) visent à fournir de la cryptographie mais souffrent de différentes faiblesses, soit de performance (ce qui amène certains à ne pas imposer TLS, de peur des conséquences sur les délais pour l'utilisateur) ou de complexité (qui utilise réellement IPsec, à part des tunnels point-à-point entre deux sites de la même organisation ?).
MinimaLT vise donc à rendre le chiffrement moins coûteux et plus simple. Le principe de base est de créer à la demande un tunnel chiffré dès que deux machines communiquent. Ensuite, tout le trafic MinimaLT entre ces deux machines (même s'il provient de deux applications sans aucun rapport entre elles) passe par ce tunnel. On ne paiera donc qu'une fois certains coûts cryptographiques, alors qu'avec TLS on les paie à chaque connexion.
Et pour authentifier la machine en face, afin d'être sûr qu'on n'est pas en train de parler au vilain Homme du Milieu ? MinimaLT utilise pour cela des certificats X.509 trouvés dans le DNS. J'en parlerai plus longuement plus loin car c'est le principal point noir de MinimaLT.
Quel est l'intérêt de ces tunnels ? C'est que l'établissement d'un contexte cryptographique (les clés utilisées, notamment) nécessite pas mal d'échanges entre les deux machines et introduit donc une latence importante. MinimaLT (dont le nom veut dire Minimal Latency Tunneling) ne peut pas complètement faire disparaître ces échanges mais il les amortit sur un plus grand nombre de connexions. La première fois qu'Alice parle à Bob, il faudra attendre. Mais le tunnel reste ouvert ensuite et pourra servir aux communications suivantes. L'établissement de ces connexions dans le tunnel pourra être très rapide puisque l'essentiel du boulot a déjà été fait.
Cela a des conséquences dont l'article parle peu : en cas de communications intermittentes, il faut maintenir un état entre deux sessions, et en cas de communications intensives (pensez à Gmail utilisant MinimaLT), il y a beaucoup d'état à maintenir. Mais, surtout, cela rend les comparaisons de performances plus délicates : lorsqu'on mesure le nombre de connexions qu'on peut ouvrir par seconde et qu'on compare MinimaLT avec TCP ou TCP+TLS, on compare des pommes et des oranges... Les résultats présentés dans l'article sont d'autant plus difficiles à lire que les auteurs ne disent pas à chaque fois clairement s'ils mesurent en partant d'un état « froid » (rigoureusement aucun état) ou « chaud » (tunnel déjà établi).
On notera que le tunnel fonctionne sur UDP, afin de réussir à passer les middleboxes qui infestent l'Internet. C'est dommage mais c'est réaliste : la solution architecturalement propre (créer un nouveau protocole de transport) ne serait pas déployable, avec toutes les machines sur le trajet qui se croient autorisées à bloquer tous les protocoles qu'elles ne connaissent pas (SCTP avait le même problème et a fait le même choix, cf. RFC 6951.). MinimaLT doit ensuite réinventer toutes les fonctions de TCP (délivrance des messages garantie, et dans l'ordre, contrôle de congestion) ce qui est beaucoup de travail et offre beaucoup de possibilités d'erreur.
Un gros problème de toute solution de chiffrement est d'établir l'authenticité du pair situé en face. Si Alice croit parler à Bob mais qu'elle parle en fait à Mallory, le chiffrement ne servira à rien. Il faut donc s'assurer de l'identité du pair. Ce point, pourtant crucial, est très vite traité dans l'article. On comprend qu'il existe un annuaire des caractéristiques des machines, comprenant leurs clés cryptographiques et des certificats qui lient ces clés aux noms des machines. Le DNS est utilisé pour réaliser cet annuaire. DNSSEC n'est pas mentionné car la sécurité repose sur la signature des certificats récupérés dans le DNS. MinimaLT reprend donc tous les problèmes de sécurité de X.509, notamment l'absence de lien entre une AC et un domaine (n'importe quelle AC peut signer pour n'importe quel domaine, sans que le titulaire du domaine ne puisse s'y opposer, cf. RFC 6394). À noter que l'idée de mettre des certificats dans le DNS est ancienne mais que l'article ne cite pas un seul des travaux antérieurs (par exemple, DANE - RFC 6698 - n'est même pas mentionné en passant).
(Un expert en sécurité anonyme me fait aussi remarquer que MinimalLT ne permet apparemment que d'authentifier le répondant, pas l'initiateur de la connexion, contrairement à TLS et IPsec.)
Enfin, il faut préciser que l'interface de MinimaLT avec les applications n'est guère discutée. L'article note à juste titre que les mises en œuvre de TLS sont typiquement trop difficiles à utiliser par les applications, avec trop de possibilités d'erreur entraînant des failles de sécurité (voir l'article « The most dangerous code »). Mais utiliser une autre API veut dire qu'il faudra adapter toutes les applications. MinimaLT est conçu pour un nouveau système d'exploitation, sans base installée, Ethos, donc ce cas ne sera peut-être pas trop un problème. Mais il y a aussi un portage sur Linux où la question se posera.
L'article originel est riche et je n'ai pas parlé de tout, je vous encourage donc à le lire. Une discussion a lieu sur Reddit mais pour l'instant avec peu de contenu. Merci à l'expert sécurité anonyme pour sa relecture de cet article.
Date de publication du RFC : Mai 2013
Auteur(s) du RFC : M. Jethanandani (Ciena Corporation), K. Patel (Cisco Systems), L. Zheng (Huawei Technologies)
Pour information
Réalisé dans le cadre du groupe de travail IETF karp
Première rédaction de cet article le 25 Mai 2013
Dans le cadre du travail du groupe KARP de l'IETF, consacré à la sécurisation des protocoles de routage de l'Internet, ce RFC est consacré à l'analyse de la sécurité des protocoles de routage utilisant TCP, notamment BGP.
Deux petits rappels : KARP travaille sur les protocoles eux-mêmes, ni sur le contenu des informations transmises (c'est le rôle de SIDR, qui a produit le système RPKI+ROA), ni sur les pratiques quotidiennes d'administration des routeurs. Son rôle est d'améliorer la sécurité des protocoles, et pour cela il commence par des analyses de la sécurité des protocoles existants, suivant une méthode décrite dans le RFC 6518. Il y avait déjà eu une analyse d'OSPF (RFC 6863) et ce nouveau RFC s'attaque à des protocoles très différents mais qui ont en commun d'utiliser TCP comme transport : BGP (RFC 4271) et LDP (RFC 5036), ainsi que les moins connus PCEP (Path Computation Element Communication Protocol, RFC 5440) et MSDP (RFC 3618). Ils appartiennent tous à la catégorie un-vers-un du RFC 6518 (les messages d'un routeur sont transmis à un seul autre routeur).
Donc, aujourd'hui, quels sont les risques de sécurité pour ces protocoles et les défenses existantes ? D'abord, ceux et celles spécifiques à la couche transport. Il y a les attaques par déni de service et les attaques où l'ennemi va tenter d'établir une session avec sa victime, sans en avoir normalement le droit. Parmi les contre-mesures (RFC 4732 pour un point de vue plus général), il y a des ACL par adresse IP (tous ces protocoles utilisant TCP, il n'y a normalement pas de possibilité pour un attaquant en dehors du chemin d'usurper une adresse IP, si tout le monde suit bien le RFC 4953 et le RFC 5961) et le fait d'écouter les connexions entrantes uniquement sur les interfaces où on s'attend à avoir des pairs. Pour éviter les attaques de méchants lointains, il y a la technique GTSM du RFC 5082, qui consiste à n'accepter des paquets que s'ils ont un TTL maximal (ou proche du maximum).
Cela ne suffit pas contre des assaillants situés sur le chemin (par exemple parce qu'ils sont sur le réseau local). Ceux-ci peuvent établir une connexion avec une fausse adresse IP, ou bien simplement envoyer des resets TCP pour couper les sessions existantes (notez que TLS ou SSH ne protégeraient pas contre ce dernier risque car ils fonctionnent au-dessus de TCP). Pour assurer l'authentification et l'intégrité de la connexion TCP, on a l'« authentification MD5 » du RFC 2385, normalement remplacée par l'AO du RFC 5925. AO est très supérieur, fournissant notamment l'agilité cryptographique (la possibilité de changer d'algorithme si la cryptanalyse en a trop affaibli un, ce qui est le cas de MD5). Mais AO est loin d'avoir remplacé MD5.
Et puis il y a les problèmes qui ne dépendent pas du transport utilisé, comme l'absence d'un protocole de gestion des clés (KMP pour Key Management Protocol). Actuellement, la gestion des clés dans tous ces protocoles est purement manuelle et, résultat, les clés cryptographiques des routeurs ne sont quasiment jamais changées, même lorsqu'un administrateur quitte la société.
Maintenant, place à chaque protocole individuellement. Le RFC fait une présentation de chaque protocole (section 2), puis de l'état de sécurité idéal qu'on souhaite atteindre (section 3), puis de la différence entre l'état actuel et cet idéal (section 4). Enfin, la section 5 étudie les questions de transition vers une meilleure solution de sécurité (tous ces protocoles étant pair-à-pair, il faut que les deux pairs soient d'accord pour la nouvelle technique de sécurité). Ici, je procède différemment en traitant tous les aspects de chaque protocole successivement (enfin, pas chacun, je ne couvre que BGP et LDP, ne connaissant pas vraiment PCEP et MSDP). Donc, honneur à BGP pour commencer, puisque c'est sans doute le protocole de routage le plus important pour l'Internet (section 2.3). Comme il ne fonctionne que sur TCP, sa sécurité est en bonne partie celle de ce protocole de transport. Autrement, il devra attendre le déploiement d'AO, puis d'un KMP pour que sa sécurité s'améliore.
LDP, lui, est utilisé par
MPLS et le RFC général de sécurité sur MPLS, le
RFC 5920 est donc une utile lecture, ainsi que
la section 5 du RFC 5036. LDP (sections
2.4, 3.1 et 4.1 de notre RFC) peut, lui, fonctionner sur TCP ou sur UDP. Ce
dernier sert notamment aux messages Hello
d'établissement d'une session. Cet établissement n'est donc pas
protégé par les mesures de sécurité de TCP. En fait, il n'existe même
quasiment aucune protection pour ces messages.
Et pour TCP ? LDP peut utiliser l'authentification MD5 du RFC 2385 mais on a vu que MD5 n'était pas conseillé
(RFC 6151 et section 2.9 du RFC 5036) et LDP ne permet pas encore d'utiliser AO (RFC 5925).
L'état de sécurité idéal pour LDP serait clairement un état où les
messages Hello seraient authentifiés. En
attendant, les contre-mesures minimales sont de n'accepter des
Hello que sur les interfaces réseau qui en ont
réellement besoin, et d'utiliser GSTM. Cela ne supprime pas toutes les
attaques, mais un travail est déjà en cours pour l'authentification
des Hello (Internet-Draft draft-zheng-mpls-ldp-hello-crypto-auth).
Date de publication du RFC : Mai 2013
Auteur(s) du RFC : P. Saint-Andre (Cisco Systems)
Première rédaction de cet article le 24 Mai 2013
Voici un nouvel espace de nommage pour les
URN, urn:example, qui
servira pour les exemples et la documentation.
Les URN sont normalisés dans le RFC 2141 et offrent un moyen de construire des
URI stables et indépendants de toute notion de
localisation. L'URN commence par urn: puis par un
NID (namespace identifier). Le RFC 3406
définit trois genres de NID, formel, informel et expérimental (nom
commençant par x-). Lorsqu'on a besoin d'URN pour
une documentation ou un cours, on utilisait en général ces NID
expérimentaux. Mais les identificateurs commençant par
x- sont désormais mal vus dans le monde
IETF (cf. RFC 6648) et ce
nouveau RFC propose donc d'abandonner ces NID expérimentaux et, pour
les exemples, d'utiliser le NID example. De tels
noms réservés pour les exemples sont courants dans les RFC (par
exemple le RFC 2606 pour les noms de
domaine ou le RFC 5612 pour les
numéros d'organisations).
Ainsi, on peut désormais créer comme ça, gratuitement, l'URN
urn:example:foo:bar et être sûr qu'il n'entrera
jamais en collision avec un « vrai » URN. (Par contre, deux URN
example peuvent être accidentellement identiques
puisqu'aucune autorité ne les attribue.) Ces URN ne doivent être
utilisés qu'à des fins d'exemple et pas pour court-circuiter les
mécanismes normaux d'allocation des URN formels et informels, décrits dans le RFC 3406.
Première rédaction de cet article le 23 Mai 2013
Vous avez confiance dans les composants électroniques de votre
ordinateur ? Vous croyez que, lorsque vous tapez ou sélectionnez
http://www.impots.gouv.fr/, vous vous retrouverez
bien là où vous pouvez déclarer vos revenus ? Vous avez
tort. L'électronique, c'est fragile. Un bit 1 peut se changer en 0
subitement (ou le contraire) et, à partir de là, le
http://kremlin.ru/ se change en
http://kremlin.re/... C'est le bit
flipping (le changement de la valeur d'un bit), qui permet
le bitsquatting (l'enregistrement par un méchant
d'un domaine proche d'un
bit du domaine dont on veut détourner le trafic).
Mais pourquoi un 0 se transformerait-il en 1 subitement ? Il existe des tas de raisons physiques possibles, d'un rayon cosmique (la Terre en reçoit en permanence) à la radioactivité en passant par la simple agitation thermique. Moins il y a d'atomes pour faire un bit (avec les progrès de la miniaturisation) et plus le risque est important. Mais les ordinateurs n'ont pas de moyen de se défendre, de la redondance, des contrôles ? Si, cela existe, cela se nomme les mémoires ECC mais elles sont plus chères et n'équipent pas les engins de bas de gamme. Ceux-ci, bon marché mais connectés à l'Internet, sont de plus en plus nombreux.
Quels sont les changements possibles ? En regardant la table
ASCII, on voit que e est représenté par
01100101 et u par 01110101. Un changement du quatrième bit suffit donc
à passer de la Russie à l'île de la
Réunion comme dans l'exemple ci-dessus. Mais le
bit flipping ne change pas que des lettres en
lettres. Par exemple, n est représenté par 01101110 et le
point par 00101110. En changeant le deuxième bit,
on change tout dans le nom de domaine. windowsupdate.com peut
devenir wi.dowsupdate.com en modifiant un seul
bit. Même chose entre o (01101111) et la
barre oblique (00101111). Un
https://ecampus.phoenix.edu tapé dans un
navigateur peut devenir
https://ecampus.ph/enix.edu, qui est dans un tout
autre TLD.
Mais les protocoles de sécurité comme X.509 ou DNSSEC ne vont pas s'y opposer ? Si le bit flipping avait lieu dans le réseau, sans doute. Mais il a souvent lieu dans la machine originale. Auquel cas, ces protocoles ne peuvent pas aider, le problème étant dès le début. S'il a lieu dans le réseau, notons que les simples mécanismes de contrôle existants comme la somme de contrôle UDP suffisent à l'attraper.
Bon, le bit flipping est possible. Est-il fréquent ? Pose-t-il un vrai problème en pratique ? La première question est délicate car on ne connait pas le nombre de fois où un nom de domaine est manipulé et copié dans une machine. Même si le pourcentage de bit flipping est très faible, il faut le multiplier par le nombre de machines existantes et par le nombre de fois qu'elles tripotent des noms de domaine. En fait, personne ne sait vraiment.
Et le risque de sécurité ? C'est que quelqu'un de mal intentionné n'enregistre le nom avec un bit changé et n'intercepte alors du trafic légitime, comme dans l'exemple du Kremlin ci-dessus. L'expérience (voir la bibliographie) montre que ces noms bitsquattés attirent effectivement du trafic, même s'il n'est pas toujours facile d'être certain de son origine. À la dernière réunion OARC à Dublin, Jaeson Schultz a présenté une entreprise de bitsquatting de grande envergure, afin d'étudier le phénomène, et ses mesures semblent indiquer que le bit flipping est plus répandu qu'on en le pensait.
Il a aussi étudié le passé et montré que
wwwnfacebook.com, bitsquatting
de www.facebook.com, avait été enregistré deux
ans avant la publication du premier papier sur le
bitsquatting. Cela ne veut pas dire que celui qui a
fait l'enregistrement connaissait le phénomène du bit
flipping, peut-être le
domainer a-t-il essayé beaucoup de noms et
constaté empiriquement que celui-ci recevait du trafic.
Mais il est difficile de faire la part de ce qui est du vrai bit flipping. Il peut s'agir de fautes de frappe (Schultz note que des domaines très éloignés sur le clavier mais proches en bits reçoivent eux aussi du trafic, donc les fautes de frappe n'expliquent pas tout) ou d'un simple bruit de fond (enregistrez n'importe quel nom de domaine, vous aurez du trafic).
L'article de Schultz contient aussi des suggestions de techniques pour limiter le bitsquatting mais aucune ne me semble réaliste. J'en ai quand même déployé une dans le source de cet article : les noms de domaine dans les URL sont en majuscules (il y a moins de possibilités de bit flipping en majuscule).
Un peu de bibliographie :
Première rédaction de cet article le 20 Mai 2013
Le DNS utilise traditionnellement surtout UDP comme protocole de transport. TCP est parfaitement légal mais, en pratique, il a été cantonné aux transferts de zone et à quelques requêtes où la réponse était trop grosse pour passer en UDP. La montée des attaques utilisant le DNS avec réflexion et amplification a changé les choses et de plus en plus de gens se demandent si le DNS ne va pas utiliser TCP plus fréquemment.
Écartons d'abord un mythe encore propagé par certains ignorants :
non, le DNS n'utilise pas que
UDP. Outre les transferts de zone (cf. RFC 5936), le DNS utilise TCP dès que la réponse est
de taille trop importante pour être transmise en UDP. C'est combien
d'octets, « trop importante » ? Cela dépend. Autrefois, il y avait une
limite en dur à 512 octets. Elle a été remplacée depuis longtemps par
l'extension EDNS (aujourd'hui décrite par le
RFC 6891) qui permet d'indiquer la taille des
réponses qu'on peut recevoir. Le serveur répondeur ayant également sa propre
limite, la taille maximale pratique est le minimum de la taille
annoncée que le demandeur et de la taille configurée dans le serveur
répondeur. Pour la plupart des logiciels DNS, ces deux tailles valent
par défaut 4 096 octets, mais peuvent être modifiées. Vous verrez
ainsi que les serveurs de noms de
.com ont une limite
configurée à 1 460 octets. Même si le demandeur propose d'avantage
(8 192 octets dans l'exemple suivant), le serveur enverra une réponse
tronquée (bit TC mis à un) et le demandeur réessaiera alors en
TCP. Voyons avec dig :
% dig +bufsize=8192 @a.gtld-servers.net ANY com. ;; Truncated, retrying in TCP mode. ... ;; flags: qr aa rd; QUERY: 1, ANSWER: 21, AUTHORITY: 0, ADDITIONAL: 16 ... ;; SERVER: 192.5.6.30#53(192.5.6.30) ;; WHEN: Mon May 20 17:21:15 2013 ;; MSG SIZE rcvd: 1792
dig a automatiquement réessayé en TCP. Si on lui dit de ne pas le faire :
% dig +bufsize=8192 +noignore @a.gtld-servers.net ANY com. ;; flags: qr aa tc rd; QUERY: 1, ANSWER: 20, AUTHORITY: 0, ADDITIONAL: 1 ... ;; SERVER: 192.5.6.30#53(192.5.6.30) ;; WHEN: Mon May 20 17:23:24 2013 ;; MSG SIZE rcvd: 1365
Le tc dans la réponse indique qu'elle a été
tronquée (regardez le compteur ANSWER et la
taille de la réponse).
Cette possibilité de se rabattre en TCP est cruciale si la réponse est de trop grande taille (ce qui est plus fréquent aujourd'hui, avec IPv6, les IDN et surtout DNSSEC). C'est pour cela qu'il est essentiel de s'assurer que la configuration du réseau permette les requêtes et les réponses TCP, comme exigé par le RFC 5966. C'est aussi pour cela que l'outil Zonecheck a, par défaut, une politique de tests qui impose que le serveur réponde en TCP. (Un point qui a toujours fait l'objet d'un consensus chez les experts à chaque discussion.)
Au fait, pourquoi le serveur a t-il une limite de taille en UDP et
pas en TCP ? Car, en UDP, on n'a aucun moyen de garantir la véracité
de l'adresse IP source utilisée. Cela permet
des attaques par réflexion + amplification, qui ne sont pas possibles
en TCP. Limiter la taille des réponses, comme le fait
.com, limite donc les dégâts.
OK, bon, on a le droit d'utiliser TCP si on veut. Si un employé ou un consultant en sécurité dit qu'il faut débrayer / bloquer TCP, on sait qu'on peut muter l'employé et virer le consultant, ils ne connaissent pas leur métier. Mais le fait qu'on puisse utiliser TCP veut-il dire qu'il le faut ? Notons qu'un client DNS peut toujours utiliser TCP dès le début, sans attendre une réponse tronquée :
% dig +tcp @a.gtld-servers.net ANY com. ... ;; flags: qr aa rd; QUERY: 1, ANSWER: 21, AUTHORITY: 0, ADDITIONAL: 16 ... ;; SERVER: 192.5.6.30#53(192.5.6.30) ;; WHEN: Mon May 20 17:51:26 2013 ;; MSG SIZE rcvd: 1792
Mais quels sont les problèmes si tous les clients DNS faisaient ainsi ? Il y en a deux : bien des réseaux bloquent stupidement les requêtes DNS TCP (cf. le cas du consultant en sécurité incompétent, ainsi que les excellents tests TCP de Zonecheck, cités plus haut). Ensuite, UDP est bien plus léger pour le serveur. Il peut être mis en œuvre sans état (notez que ce n'est pas toujours fait ainsi sur les systèmes modernes) et la même machine peut donc servir bien plus de requêtes par seconde en UDP.
Au dernier atelier OARC à Dublin, le 12 mai, deux excellents exposés étaient revenus sur cette question. Celui de Francis Dupont présentait le problème des performances TCP, les réglages souhaitables sur les serveurs et les clients (ceux par défaut conviennent rarement) et les résultats de ses mesures (après réglages, 30 kr/s en TCP sur une machine qui en fait 130 kr/s en UDP). Cela indique que TCP reste plus lent (ce qui est logique) mais que l'écart est peut-être supportable (le DNS va de toute façon nécessiter des investissements, entre autre en raison des attaques par réflexion). Et des optimisations sont possibles, comme de laisser les connexions TCP ouvertes (c'est l'établissement de la connexion TCP qui est coûteux, et on peut faire passer plusieurs requêtes DNS sur une seule connexion).
Autre exposé très intéressant, celui d'Ed Lewis, exposé très provoquant sur la sécurité du DNS, le genre d'exposé qui remet tout à plat et où personne n'est d'accord à 100 % mais qui disait plein de choses justes, comme le fait que nous serons probablement amenés à dépendre de plus en plus de TCP dans le futur.
Et mon opinion ? Je pense qu'en effet, les défauts d'UDP (notamment en cas d'attaques par réflexion) deviendront de plus en plus insupportables avec le temps et que les problèmes de performance de TCP doivent être relativisés : aujourd'hui, avec l'expérience des serveurs HTTP, faire des serveurs qui encaissent des dizaines de milliers de connexion par seconde n'est plus de la magie noire... Experts TCP, il y aura donc peut-être bientôt du travail pour vous dans le monde DNS.
Première rédaction de cet article le 16 Mai 2013
Aujourd'hui, le site Web de la RATP,
a été en panne de 11h à
16h environ (la reprise a été cahotique, avec de nombreuses rechutes
jusqu'en soirée). Que s'est-il passé ? Comme pour chaque panne d'un service
Internet, c'est l'occasion d'en tirer des leçons pour améliorer la
résilience.http://www.ratp.fr/
Sur les réseaux sociaux, les utilisateurs mécontents ont signalé le problème en disant que « le site Web ne marche pas » ou que « l'appli (pour mobile) ne marche pas ». Mais la vraie cause n'étant pas là. Regardons pendant la panne avec wget :
% wget http://www.ratp.fr/ --2013-05-16 11:52:21-- http://www.ratp.fr/ Resolving www.ratp.fr... failed: Name or service not known. wget: unable to resolve host address `www.ratp.fr'
Le message d'erreur est clair : le client HTTP
wget n'a pas réussi à charger le site car il n'a pas pu résoudre le
nom en adresse IP. C'était donc un problème DNS,
apparemment. Regardons le DNS pendant la panne avec
dig. Quels sont les serveurs de noms de ratp.fr ?
% dig NS ratp.fr ... ;; ANSWER SECTION: ratp.fr. 3600 IN NS indom10.indomco.com. ratp.fr. 3600 IN NS ns1.ratp.fr. ratp.fr. 3600 IN NS indom30.indomco.fr. ratp.fr. 3600 IN NS ns0.ratp.fr. ...
Et demandons à l'un d'eux l'adresse de
www.ratp.fr :
% dig @ns0.ratp.fr. A www.ratp.fr ... ;; AUTHORITY SECTION: www.ratp.fr. 3600 IN NS altns1.ratp.fr. www.ratp.fr. 3600 IN NS altns2.ratp.fr. ;; ADDITIONAL SECTION: altns1.ratp.fr. 3600 IN A 195.200.228.2 altns2.ratp.fr. 3600 IN A 195.200.228.130 ;; Query time: 4 msec ;; SERVER: 193.104.162.15#53(193.104.162.15) ;; WHEN: Thu May 16 11:53:02 2013 ;; MSG SIZE rcvd: 114
Ah, on n'a pas directement l'adresse mais une
délégation. Le DNS repose sur un système
arborescent de délégations depuis la racine
jusqu'à la machine qui connait la réponse. Dans
.fr, il n'y a en général
pas de délégation entre le deuxième et le troisième
composant du nom de domaine mais, ici, c'est le
cas : www.ratp.fr n'est pas dans la même
zone que ratp.fr.
Avant de revenir sur les raisons de cette délégation inhabituelle
(mais parfaitement légale), continuons la recherche de l'adresse IP de
www.ratp.fr :
% dig @altns1.ratp.fr. A www.ratp.fr ; <<>> DiG 9.7.3 <<>> @altns1.ratp.fr. A www.ratp.fr ; (1 server found) ;; global options: +cmd ;; connection timed out; no servers could be reached
Et c'est pareil pour altns2.ratp.fr. La zone n'a
que deux serveurs de noms, ce qui est peu, et les deux sont en panne
en même temps. Pas étonnant que le nom ne puisse pas être résolu.
Pourquoi ces deux serveurs sont en panne simultanément ? La
proximité de leurs adresses IP fait penser qu'ils sont sans doute au
même endroit, et qu'ils ont été victimes de la même panne de courant
ou de réseau ou de la même attaque par déni de service. La RATP n'a pas suivi un principe de base de la
résilience : éloigner les serveurs de noms, pour que la même panne ne
les coupe pas tous en même temps. On note que la zone
ratp.fr suit les bons principes (quatre serveurs,
bien éloignés). Mais www.ratp.fr ne le fait hélas pas.
Mais pourquoi cette délégation relativement inhabituelle du nom
www ? Le plus probable est que le site Web se
trouve derrière un équipement de répartition de charge et que cet équipement prend également en charge le
DNS, changeant les réponses suivant la demande. Une fois le service
réparé, on peut d'ailleurs constater que ces engins envoient des
réponses avec une durée de vie très courte (300 secondes). Ces
équipements conçus pour les gens du Web (qui ne connaissent pas
forcément le DNS) sont souvent bogués jusqu'au trognon. Ainsi, un des
serveurs répond parfois FORMERR (Format
Error) et renvoie une réponse syntaxiquement incorrecte (le Messages has 11 extra bytes at end) :
% dig @altns1.ratp.fr A www.ratp.fr ... ;; ->>HEADER<<- opcode: QUERY, status: FORMERR, id: 12599 ;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0 ;; WARNING: recursion requested but not available ;; WARNING: Messages has 11 extra bytes at end ;; QUESTION SECTION: ;www.ratp.fr. IN A ;; Query time: 37 msec ;; SERVER: 195.200.228.2#53(195.200.228.2) ;; WHEN: Thu May 16 22:17:06 2013 ;; MSG SIZE rcvd: 40
Ce comportement disparait si on coupe EDNS.
Merci à Jean-Baptiste Favre pour le premier signalement.
Date de publication du RFC : Mai 2013
Auteur(s) du RFC : H. Flanagan (RFC Series Editor), N. Brownlee (Independent Submissions Editor)
Pour information
Première rédaction de cet article le 15 Mai 2013
Cela fait longtemps que le format des RFC est critiqué, à l'IETF ou ailleurs. Pour d'excellentes raisons (détaillées plus loin), ce format est très ancien et très rigide, sans concessions aux gadgets modernes. Il n'a pas encore été possible de le modifier, à la fois en raison des difficultés de prise de décision au sein de la communauté, et aussi parce que le problème est réellement difficile. Contrairement à ce que prétendent certains yakafokon, trouver un format idéal n'est pas trivial. Ce RFC est la première étape d'une tentative de réforme, commençant par un cahier des charges sur les changements souhaitables. Les règles rigides de formatage (longueur des pages et des lignes) disparaissent, l'Unicode fait son entrée dans les RFC, et la possibilité d'inclure des images apparait.
Une des raisons de la stagnation du projet de changement depuis des années était la réorganisation de la fonction de RFC Editor. Désormais, les nouvelles règles sur cette fonction sont écrites (RFC 6635), une nouvelle RFC Editor a pris ses fonctions, jeune et dynamique (Heather Flanagan, un des auteurs de ce RFC), et il va peut être être enfin possible de faire évoluer le format traditionnel.
Le format actuel est documenté dans le RFC 2223 : texte brut sans enrichissement, en ASCII, pages de 58 lignes, lignes de 72 caractères au maximum, pas de notes de base de page, références croisées par numéro de section et pas de page, etc. PostScript était autorisé et quelques RFC ont été publiés ainsi. Une tentative de mise à jour de ce RFC, avec écriture d'une proposition de nouvelle version, avait eu lieu en 2004 mais avait été abandonné. J'avais déjà écrit un article détaillé expliquant le pourquoi du format traditionnel et les raisons pour lesquelles il est difficile à changer.
La section 1 de ce RFC commence par rappeler la longue histoire des RFC. Ils ont commencé il y a plus de quarante ans, et dans les débuts, certains étaient écrits à la main (!), d'autres tapés à la machine, d'autres encore produits par les outils de formatage invraisemblables qu'on trouvait sur les mainframes de l'époque. Résultat, certains sont devenus illisibles avec le temps, les outils tombant en désuétude. Ce problème de permanence est un des problèmes les plus cruciaux pour les RFC et explique pourquoi le RFC Editor n'a jamais été très chaud à l'idée d'utiliser le logiciel à la mode du moment : l'informatique en a déjà enterré beaucoup.
Au bout d'un moment, un format standard a émergé, fondé sur du texte brut et un encodage en ASCII. À partir de là, la série des RFC a vécu une longue période de calme et de stabilité et cette permanence (songez aux formats à la mode vite disparus comme WordPerfect) a beaucoup contribué à son succès. On peut relire aujourd'hui sans problème un RFC de 1980 comme le RFC 768. Ce n'est pas que le format ait été jugé parfaitement satisfaisant par tout le monde, ni qu'aucune proposition de changement n'ait été faite, bien au contraire. Mais aucun des ces propositions n'a connu de consensus : toutes résolvaient un problème précis... en en créant plusieurs autres.
Avant de regarder les propositions actuellement sur la table, il faut bien comprendre qu'il y a plusieurs endroits dans le cycle de vie d'un RFC où un format standard est nécessaire ou utile. Cette terminologie est très importante car l'incompréhension de ces étapes du cycle de vie est l'une des causes principales de la confusion des débats sur la réforme des RFC :
http://tools.ietf.org par exemple voici ce RFC), du PDF formaté différemment, etc.Évidemment, les choses ont changé depuis (le RFC 2223 date de seize ans...) Quels sont les points qui suscitent le plus de protestations ? D'abord, l'utilisation d'art ASCII et lui seul pour les graphiques. Elle a l'avantage d'encourager les auteurs à écrire des descriptions textuelles claires, plutôt que de passer du temps à faire de jolis dessins. Sans les limitations de l'art ASCII, les diagrammes seraient probablement moins concis. D'un autre côté, des choses comme les automates finis sont vite illisibles en art ASCII et les protocoles où il y a plus de trois acteurs qui interagissent sont difficiles à dessiner. Des graphiques plus élaborés que l'art ASCII permettraient également de représenter des équations mathématiques complexes.
Après les images, le sujet le plus chaud est évidemment l'encodage. ASCII a des tas d'avantages : standard, très répandu, facile à manipuler (outils de recherche, par exemple), plus pratique lorsqu'il faut renumériser un document (oui, le cas s'est déjà produit dans le passé)... Et la langue des RFC étant de toute façon l'anglais, les limites d'ASCII ne sont pas trop graves.
Mais il y a quand même des limites : lorsqu'un RFC parle
d'internationalisation (comme le RFC 5890 ou le
RFC 6530, ou comme de plus en plus de normes), c'est bien dommage de ne pas pouvoir
donner d'exemple lisible dans ce RFC. Devoir écrire
U+00c9 pour parler de É est
pénible... Des exemples comme ceux de XMPP
(RFC 6121, section 5.2.3) bénéficieraient de
l'acceptation d'Unicode dans les RFC.
Et certains auteurs de RFC ont des noms qui ne peuvent pas s'écrire correctement en ASCII et ils regrettent de devoir les modifier.
Autres points sur lesquels des gens ont souvent râlé contre le format actuel : la pagination et l'ajustement du texte. La pagination en unités fixes fait vraiment rétro : elle avait un sens quand les RFC étaient souvent imprimés pour être lus mais à l'ère des tablettes, cela semble bien dépassé. Plus compliqué est le cas de l'ajustement du texte. La largeur de colonne fixe qui est la norme actuelle convenait aux VT100 mais pas aux écrans modernes, avec leurs tailles très variables.
Enfin, ce n'est pas tout de définir des formats, il faut aussi des outils qui rendent la production de RFC conforme à ces formats facile (pour avoir une idée des difficultés, lire le RFC 5385). Ces outils doivent-ils être développés à l'IETF ou bien doit-on utiliser des outils standard ? Les exigences de l'IETF sont-elles tellement spécifiques qu'on ne puisse pas utiliser des outils existants ? D'un autre côté, les outils spécifiques donnent plus de souplesse et de pouvoir et, aujourd'hui, il en existe déjà beaucoup (par exemple, la version 2 de xml2rfc - une réécriture complète, abandonnant TCL pour Python, pour produire des RFC suivant le schéma du RFC 2629, est bien meilleure que la précédente) donc on peut dire que le modèle « faisons tout nous-même » marche bien (il y a beaucoup d'informaticiens à l'IETF).
Enfin, s'il y a des réclamations des lecteurs et des auteurs, il y en a aussi du RFC Editor : il voudrait pouvoir abandonner nroff (65 % des RFC aujourd'hui sont soumis au format XML, qu'il faut traduire en nroff au lieu de l'utiliser directement comme format d'entrée pour les différentes publications).
Après les contraintes et les réclamations, les décisions (section 3). D'abord, ce qui ne change pas :
Ensuite, les nouvelles exigences effectivement retenues, notamment :
Et il y a aussi des exigences qui ont été supprimées :
Voilà, le cahier des charges est posé, il reste à définir le
nouveau format, développer les outils, et déployer le tout... Ce sera
pour le prochain épisode. À la réunion IETF 86 a été annoncé
le choix de s'appuyer sur le format XML comme format canonique, avec
comme formats de publication le texte brut, HTML, PDF et
EPUB (voir la FAQ sur ces décisions.)
Deux Internet-Drafts sont
en cours, un sur le format, draft-rfc-format-flanagan,
et un sur le style, draft-flanagan-style.
Date de publication du RFC : Mai 2013
Auteur(s) du RFC : F. Gont (Huawei)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF 6man
Première rédaction de cet article le 15 Mai 2013
Une particularité amusante de la gestion de la fragmentation dans IPv6 est qu'un paquet peut très bien avoir un en-tête de fragmentation sans être fragmenté du tout. Cela se nomme un « fragment atomique » (le terme est très malheureux car il n'a rien à voir avec les « datagrammes atomiques » du RFC 6864). Ils n'ont aucun intérêt pratique mais sont engendrés par certains systèmes lorsqu'ils reçoivent un message ICMP Packet too big indiquant une MTU inférieure à 1280 octets (la taille miminale pour une MTU IPv6). Le problème est que ces fragments atomiques sont ensuite traités par bien des systèmes comme des vrais fragments, permettant ainsi certaines attaques subtiles. Ce nouveau RFC demande donc que les fragments atomiques soient gérés à part, compte tenu de leurs particularités.
Si vous voulez réviser les règles de la fragmentation dans IPv6, c'est dans le RFC 2460. Contrairement à IPv4, seules les machines de départ (pas les routeurs intermédiaires) peuvent fragmenter. Si une machine de départ doit envoyer un paquet qui est trop grand pour la MTU, elle le fragmente en plusieurs morceaux, chaque morceau indiquant son décalage par rapport au début du paquet original. Même si ce n'est pas explicite dans ce RFC, le recouvrement des fragments était autorisé, ce qui complique sérieusement le réassemblage et pouvait permettre d'échapper à certains IDS. Il n'est donc pas étonnant que le RFC 5722 ait finalement interdit ces fragments recouvrants. Bon, et les fragments atomiques, ils sont fabriqués pourquoi ? La section 5 du RFC 2460 ne laisse pas le choix aux mises en œuvre d'IPv6 : normalement, elles doivent fabriquer un fragment atomique (un paquet qui a l'en-tête de fragmentation, sans pour autant être fragmenté) si la taille indiquée par le paquet ICMP est inférieure aux 1280 octets minimaux d'IPv6 (c'est pour aider certains mécanismes de traduction IPv4<->IPv6). Dans un fragment atomique, le décalage (fragment offset) sera de zéro (puisque ce fragment est le premier) et le bit M sera à Zéro (puisque ce fragment est le dernier du datagramme). Comme ces paquets ICMP Packet too big ne sont pas authentifiés, même quand c'est possible (section 5.3 du RFC 4443 et RFC 5927), un attaquant peut donc faire fabriquer des fragments atomiques assez facilement.
Ensuite, comme bien des systèmes traitent ces fragments atomiques en même temps que les fragments normaux, ils peuvent, par exemple, être fusionnés avec d'autres fragments prétendant venir de la même source.
Les problèmes de sécurité liés aux fragments sont bien connus : voir notamment le RFC 5722 mais aussi le RFC 6274 qui décrit ces attaques pour IPv4 (beaucoup sont communes aux deux versions). Ce problème est encore aggravé par le fait que certains systèmes génèrent des identificateurs de fragment trop prévisibles, permettant à l'attaquant de savoir où il devra frapper.
La section 4 décrit ensuite les nouvelles règles, visant à résoudre ce problème. En deux mots, en recevant un fragment atomique (que l'on reconnait à la combinaison décalage=0 et bit M =0), on doit le traiter différemment des autres fragments et il ne peut être réassemblé qu'à partir du fragment unique.
L'annexe A contient un tableau listant un certain nombre de systèmes d'exploitation actuels en indiquant s'ils génèrent des fragments atomiques, et s'ils mettent en œuvre ce RFC (les traitent différemment des autres fragments). La plupart des systèmes génèrent ces fragments atomiques lorsqu'ils reçoivent le faux paquet ICMP Too big (une exception est NetBSD). Et plusieurs d'entre eux (Linux récent, NetBSD, OpenBSD) suivent déjà la recommandation de ce RFC et ne sont donc normalement pas vulnérables aux attaques décrites ici.
Date de publication du RFC : Mai 2013
Auteur(s) du RFC : D. Thaler (Microsoft)
Pour information
Première rédaction de cet article le 10 Mai 2013
Utiliser des identificateurs (noms
de domaine, URI, noms
d'utilisateur, adresses de courrier, etc) comme
clés d'accès à des informations de sécurité est courant. Par exemple,
on autorise machin@truc.example et lui seul à
accéder à certains contenus. Cela implique une
comparaison entre l'identificateur présenté et
ceux stockés dans une base. En apparence, rien de plus simple que de
comparer deux chaînes de caractères. En réalité, il existe plein de
pièges, que documente ce RFC de
l'IAB. Si tout le monde n'utilise pas
exactement le même algorithme de comparaison (et certains sont mal
spécifiés ou mal connus et permettent donc des variations), alors on
peut avoir aussi bien des dénis de service (utilisateur légitime
refusé) que des augmentations de privilèges (utilisateur illégitime
accepté).
L'informaticien naïf peut croire que comparer deux identificateurs, c'est simplement faire une comparaison bit à bit de leur représentation mais non, c'est plus compliqué que cela.
Pour comprendre le problème, la section 1 du RFC commence par parler du cycle de vie d'un identificateur. Il est d'abord généré, par exemple par une autorité centrale. Il est ensuite souvent stocké en deux endroits, chez l'utilisateur qui va s'en servir et dans une base des identificateurs enregistrés. Par exemple, si c'est une autorité centrale qui a fabriqué l'identificateur, elle le met dans sa base de données (cas, par exemple, d'un registre de noms de domaine). Naturellement, il y a des tas de possibilités différentes. Par exemple, un identificateur peut être une clé publique cryptographique, générée localement et stockée de même.
L'identificateur est ensuite distribué à ceux et celles qui en auront besoin. Cela peut se faire par des moyens numériques mais aussi par des moyens traditionnels comme une carte de visite ou une communication téléphonique. Pensez à un URL que l'on utilise dans des publicités, dans l'espoir que des gens tapent ensuite cet URL dans la barre d'adresse de leur navigateur. Ce passage par des moyens de communication non numériques est une des sources de problèmes car taper correctement un identificateur lu en vitesse sur le flanc d'un autobus n'est pas trivial.
Enfin, quelqu'un va utiliser cet identificateur. Par exemple, il va
essayer d'envoyer un message à
barack@whitehouse.gov et espère que cela
atteindra la boîte aux lettres de quelqu'un de l'équipe du
Président. Ou bien un utilisateur va récupérer un identificateur et
essayer de le comparer avec celui qu'il connait. C'est le cas d'un
navigateur Web voulant valider un certificat
X.509 (RFC 6125).
À noter qu'il existe plein d'autres complications possibles. Par
exemple, une entité peut être désignée par plusieurs identificateurs
(ce RFC est à la fois http://www.ietf.org/rfc/rfc6943.txt et
http://www.rfc-editor.org/rfc/rfc6943.txt, un être humain
peut être référencé par son numéro de passeport ou bien par son
numéro de Sécu). Notre RFC ne se préoccupe pas
de ce cas, se limitant à celui, déjà assez difficile, de la
comparaison de deux identificateurs pour voir s'ils sont identiques.
Cela peut se faire de trois façons (section 1.1, et voir aussi le RFC 6885 qui avait introduit ces trois cas) :
2001:db8:1::1317 dans une
ACL, il n'y a aucune ambiguité pour déterminer
si l'adresse présentée est égale ou non à celle-ci. (Attention, ce
n'est vrai que pour la forme binaire des adresses IP, pas pour leur
représentation textuelle.)Une technique courante pour faciliter les comparaisons des identificateurs définis est la canonicalisation. On réduit d'abord l'identificateur à une forme canonique et on fait ensuite une comparaison absolue (bit à bit). Pour des noms de domaines, on peut par exemple toujours les passer en minuscules avant de comparer. Dans le cas d'identificateurs Unicode, c'est évidemment plus complexe mais il existe plusieurs algorithmes de canonicalisation Unicode. L'important est que toutes les parties impliquées utilisent le même.
On peut bien sûr comparer sans canonicaliser mais avoir une forme canonique est tellement pratique (par exemple pour l'affichage) que cela vaut toujours la peine d'en définir une. Ce faisant, on définit aussi un algorithme de comparaison.
La section 2 cite des exemples d'utilisation d'identificateurs dans
des contextes de sécurité. Par exemple, trouver une clé en échange
d'un nom (a principal, dit-on en sécurité),
chercher dans une ACL si une entité est
autorisée, compter l'activité d'une entité donnée (et il faut donc
ajouter son activité dans la bonne ligne du tableau). Le point
important est qu'il faut que tout le monde utilise le même
algorithme. Si on stocke l'activité d'adresses de courrier
électronique sans les canonicaliser, et que quelqu'un change son
adresse de jean@durand.example à
jean@Durand.EXAMPLE (pourtant la même adresse),
il pourra apparaître comme vierge, comme n'ayant pas d'activité
précédente.
Les cas réels peuvent être très compliqués. Par exemple, en HTTPS, on compare ce qu'a tapé un utilisateur dans la barre d'adresses du navigateur avec ce que contient le certificat (RFC 6125). Plusieurs protocoles différents sont en jeu (de la définition des URL à celle de X.509) et plusieurs acteurs (des utilisateurs qui tapent plus ou moins bien, sur des systèmes très variés, et tout le monde des AC), chacun de ces acteurs pouvant avoir ses propres règles.
En cas d'algorithmes différents utilisés par des parties
différentes, on peut avoir aussi bien des faux
positifs que des faux négatifs. Les
faux positifs, c'est quand deux identificateurs sont considérés comme
identiques alors qu'ils ne devraient pas. (Je me souviens d'un vieux
système Unix où le nom de
login était silencieusement tronqué à huit
caractères, donc bortzmeyer et
bortzmeye étaient considérés identiques.) Si les
privilèges sont attribués en fonction de cette égalité, on a un gain
en privilèges. Si, par contre, les privilèges sont refusés en fonction
de cette égalité (cas d'une liste noire), on a
un refus d'un service légitime. Le faux négatif, c'est le contraire :
deux identificateurs considérés comme différents alors qu'ils sont
équivalents (cas de jean@durand.example et
jean@Durand.EXAMPLE plus haut, si on oublie que
le nom de domaine est insensible à la casse). Les conséquences sont
opposées : si les
privilèges sont attribués en fonction de cette égalité, on a un refus
de service. Si, par contre, les privilèges sont refusés en fonction
de cette égalité, on a un gain de privilèges, à tort.
Évidemment, le gain de privilèges est plus grave que le refus de service et c'est pour cela qu'on trouve, par exemple, dans la section 6.1 du RFC 3986 « comparison methods are designed to minimize false negatives while strictly avoiding false positives ». (Cet exemple suppose que les privilèges sont accordés en fonction de l'égalité et que les faux positifs sont bien plus graves.)
Le RFC donne un exemple où les identificateurs sont des
URI. La société Foo paie
example.com pour accéder à un service nommé
Stuff. Alice, employée de Foo, a un compte identifié par
http://example.com/Stuff/FooCorp/alice. En
comparant des URI, Foo tient compte du fragment (la partie après le
#, section 3.5 du RFC 3986) ce qu'example.com ne fait pas. Et
Foo permet les # dans les noms de compte. Un autre employé de Foo, le
malhonnête Chuck, se fait créer un compte avec l'identificateur
http://example.com/Stuff/FooCorp/alice#stuff. Foo
ne voit pas le problème puisque cet identificateur n'existe pas. Chuck
va donc pouvoir obtenir des autorisations d'accès de Foo. Il
peut ensuite se connecter auprès d'example.com
comme étant
http://example.com/Stuff/FooCorp/alice,
l'identificateur d'Alice. Certes, l'autorisation de Chuck n'était
valable que pour
http://example.com/Stuff/FooCorp/alice#stuff mais
rappelez-vous qu'example.com compare les URI en
ignorant les fragments... Voici un cas où les différences entre les
mécanismes de comparaison d'identificateurs ont permis un
accroissement illégitime de privilèges.
Après cet exemple, la section 3 fait le tour des identificateurs
les plus courants et de leurs pièges spécifiques. D'abord, les noms de
machines. Ce sont normalement un sous-ensemble des noms de domaines (RFC 6055) mais notre RFC utilise ce terme
dans un sens plus large, pour parler de tous les fois où un
identificateur ou composant d'identificateur est appelé Host. Ils sont souvent utilisés comme
identificateurs, soit directement (par exemple dans le RFC 5280), soit indirectement, comme partie d'un identificateur (le RFC cite
l'exemple des URI et des adresses de courrier). Le RFC note bien que
ce terme de nom de machine (hostname) est
ambigu. Ainsi, dans tyrion.lannister.got, le nom
de machine est-il tyrion ou bien
tyrion.lannister.got (section 3.1 du RFC 1034) ? Cela peut entraîner des
problèmes lorsqu'on veut décider si la machine
tyrion a accès aux privilèges de la machine
tyrion.lannister.got...
Dans le sens large qu'il a ici « nom de machine » peut aussi être
une adresse IP littérale. Cela entraîne
d'autres confusions possibles. Par exemple, si le
TLD .42 existe et qu'un
nom 103.2.1.42 est enregistré, comment le
distinguer de l'adresse IPv4
103.2.1.42 ? Normalement, la section 2.1 du RFC 1123 règle la question : on doit tester l'adresse
IP d'abord et 103.2.1.42 n'est donc jamais un
nom. Mais il n'est pas sûr que tous les programmes appliquent le RFC 1123... Certaines personnes pensent donc qu'il y
a un risque à accepter des TLD numériques, même si le RFC 1123 est clair.
Autre source d'ambiguité : la norme POSIX
1003.1 de l'IEEE admet pour une adresse IPv4
plusieurs formes, pas seulement la forme classique en quatre
composants séparés par des points. Ainsi, 10.0.258,
0xA000201 et 012.0x102 sont
des représentations légales de la même adresse, 10.0.1.2. Certaines normes se
tirent d'affaire en imposant la forme stricte, celle avec les quatre
composants décimaux séparés par des points. C'est le cas des URI, par
exemple (« an IPv4 address in dotted-
decimal form »). Même chose avec
inet_pton qui n'accepte que la forme
stricte. Si les différentes formes sont acceptées, on peut avoir un
problème d'ambiguité.
Et avec IPv6 ? Il y a également plusieurs
représentations texte possibles (mais, à mon avis, moins susceptibles
de poser des problèmes en pratique), par exemple
2001:db8::1 et
2001:DB8:0:0:0:0:0:1 pour la même adresse, sans
compter des cas plus tordus comme les identificateurs de zone dans les
URL (RFC 6874). Contrairement à IPv4, il existe
une représentation canonique, normalisée dans le RFC 5952 mais elle n'est pas forcément utilisée par tous.
L'internationalisation (RFC 2277) ajoute
évidemment quelques questions. Par exemple, la section 3.2.2 du RFC 3986 autorise un nom de domaine
Unicode à être écrit en encodage pour-cent
ou en punycode (le second
étant recommandé mais pas imposé). Comment
comparer caf%C3%A9.fr et
xn--caf-dma.fr ? Comme souvent en matière
d'internationalisation (qui n'a jamais été complètement acceptée par
certains), le RFC pinaille même plus loin en imaginant le cas
(purement hypothétique) d'un registre qui accepterait l'enregistrement
de noms commençant par xn--, entrainant ainsi une
confusion avec des IDN.
Autre façon de comparer des noms : les résoudre en adresses IP et comparer les adresses. C'est ce que fait la bibliothèque standard Java par défaut (classe URL). Cette méthode a évidemment toujours été dangereuse, mais c'est encore pire maintenant, avec les adresses IP privées, les trucs du DNS pour avoir une réponse dépendant de la source, les mobiles, etc. Elle était conçue pour lutter contre des failles de sécurité comme le changement DNS mais le jeu en vaut-il la chandelle ? Sans compter qu'il est contestable d'attendre le DNS juste pour comparer deux identificateurs.
Après les noms de machines, les ports. L'URL
http://www.example.com:443/ est-il égal à
http://www.example.com:https,
https ayant été enregistré (RFC 6335) comme équivalent de 443 ? (Cet exemple est facile : la
seconde forme est illégale dans un URL HTTP. Mais, dans d'autres cas,
cela peut être ambigu.)
On a souvent vu les URI dans les deux sections précédentes, consacrées aux noms de machines et aux ports. Le principal problème de la comparaison d'URI est qu'un URI est formé de plusieurs composants, chacun suivant des règles de comparaison différentes. Second problème, il existe plusieurs mécanismes standard de comparaison d'URI (RFC 3986, section 6.2, qui décrit l'échelle des comparaisons, de la plus simple à la plus complète). Le but de cette variété est de permettre aux diverses applications des URI d'optimiser pour les performances ou pour la sécurité. L'inconvénient est que deux comparateurs d'URI peuvent donner des résultats différents sans même qu'on puisse accuser l'un d'eux d'être bogué ou non standard.
Certains composants de l'URI posent des problèmes particuliers :
les plans définissent la syntaxe spécifique d'un type d'URI et il ne
faut donc jamais essayer de comparer deux URI de plans différents
(http et ftp par exemple,
même si, dans ce cas, la syntaxe est la même).
Un autre cas souvent oublié dans les URI est la partie nommée
userinfo avant le @, par
exemple dans
ftp://alice:bob@example.com/bar. Doit-elle être
considérée significative en comparant des URI ? Le RFC ne fournit pas
de règles à ce sujet.
Le chemin après le nom de machine pose un autre problème, celui des
caractères . et
.. qui, normalement, indiquent un chemin relatif.
Mais la section 5.2.4 du RFC 3986 fournit un
algorithme pour les retirer, transformant
http://example.com/a/b/c/./../../g en
http://example.com/a/g. Un nouveau piège pour la
comparaison ?
Continuons vers la fin de l'URI. Après le ?
il y a une requête. Doit-elle être prise en compte dans la
comparaison ? Là encore, pas de réponse simple, c'est à l'application
de décider si
http://www.example.org/foo/bar?ref=323 est
identique à http://www.example.org/foo/bar. Un
exemple où cette question se pose est celle d'un site de référencement
d'URI, avec les nombreux cas où la requête ne stocke en fait qu'une
variable de suivi de la circulation de l'URI (lu sur
Twitter, lu sur
Facebook, etc).
Reste le fragment, la dernière partie d'un URI, après le #. En général, lorsqu'on utilise un URI comme identificateur dans un contexte de sécurité, on ignore le fragment (voir l'exemple plus haut avec Chuck et Alice...) Mais ce n'est pas une règle qui marche dans tous les cas. Là encore, l'important est la cohérence : que toutes les applications qui gèrent cet URI fassent pareil.
Comme pour les noms de machine, dans l'exemple Java plus haut, on pourrait se dire qu'une façon simple de comparer deux URI est de les déréférencer et de voir s'ils pointent vers des contenus identiques. Mais tous les URI ne sont pas déréférençables, on n'a pas forcément envie d'imposer une connexion Internet en état de marche juste pour comparer deux identificateurs et, de toute façon, un tel algorithme serait très fragile (que faire si on trouve le même document XML mais avec des encodages différents ?) En outre, toute démarche active comme celle-ci est dangereuse pour la vie privée (elle informe les gérants des serveurs Web de ce que l'on est en train de faire, comme le font les Web bugs).
Après les URI, place à une catégorie d'identificateurs très souvent
utilisés pour identifier une entité, les adresses de courrier (RFC 5322 pour leur syntaxe, et RFC 6532 pour le cas où elles sont internationalisées). Une
adresse de courrier, comme un URI, a plusieurs parties, qui suivent
des règles différentes pour la comparaison. La partie à droite du
@ est un nom de domaine et ce cas a été traité
plus haut. La partie gauche, dite partie locale, est un identificateur
indéfini : ses règles ne sont pas connues à l'extérieur et on ne peut
donc pas savoir, par exemple, si rms@gnu.org et
RMS@gnu.org sont le même utilisateur, ou si
stephane+ps@bortzmeyer.org est le même que
stephane+ump@bortzmeyer.org. Dans le cas où des
adresses de courrier sont utilisées dans un certificat, on choisit
souvent une comparaison bit à bit... qui peut donner plein de faux négatifs.
Après cette liste à la Prévert de problèmes,
la section 4 de notre RFC tente une synthèse. Elle identifie quatre
problèmes. Le premier est la confusion. Un
identificateur est utilisé sans que son type soit clair. Par exemple,
si je tape telnet 1000, est-ce l'adresse
IPv4 0.0.3.232 ou bien
l'adresse IPv6 ::3:e8 ?
Et si je tape ping 10.1.2.42, est-ce que
10.1.2.42 est un nom ou une adresse (le TLD
.42 peut exister) ?
Résoudre la confusion nécessite un algorithme clair. Dans le
premier exemple ci-dessus, il n'y a pas de
confusion. 100 ne peut pas être une adresse IPv6
légale (la présence ou l'absence d'un : suffit à
les reconnaître). Le second exemple est normalement clair : l'adresse
IP a priorité donc 10.1.2.42 ne peut pas être un
nom même si le TLD .42 existe. Si cette règle de
précédence est respectée par les implémentations, il n'y aura pas de
problèmes (identificateurs définis). Mon avis personnel est que ce RFC
pinaille quand même très fort sur ce point, en s'interrogeant
gravement sur des problèmes théoriquement intéressants mais extrêmement
tordus et donc rares en pratique.
Deuxième problème, l'internationalisation. Un logiciel n'a aucun
problème à comparer google.com et
goog1e.com et à dire qu'ils sont
différents. C'est plus difficile pour un humain (vous aviez repéré le
L qui était en fait un 1 ?) Toutes les fois où un humain est impliqué,
dans la saisie ou la reconnaissance d'un identificateur, ce genre d'erreur peut se produire. Comme le montre cet exemple, cela n'a
d'ailleurs rien de spécifique aux chaînes de caractères Unicode. Mais
ce problème est souvent cité comme argument contre
l'internationalisation. Bref, le point important : la sécurité ne
devrait pas dépendre d'une vérification visuelle faite par un
humain. (Cf. l'article
de Weber et le RFC 6885.)
Problème suivant, la portée. Certains
identificateurs ne sont pas uniques au niveau
mondial. localhost est un bon exemple. C'est
également le cas des adresses du RFC 1918. On
peut aussi citer l'adresse de courrier alice qui,
utilisée depuis une machine d'example.com
arrivera à une Alice et, depuis une machine d'un autre domaine, à une
autre. Dans ce dernier cas, la bonne solution est de toujours utiliser
une adresse unique (par exemple
alice@example.com) même dans un contexte local :
l'expérience prouve que les identificateurs fuient souvent d'un
domaine local vers un autre.
Enfin, dernier problème identifié par cette section 4, la
durée. Certains identificateurs ne sont pas
éternels et peuvent disparaître, ou désigner une autre entité. Par
exemple, bob@example.com peut désigner un Bob
aujourd'hui et, s'il quitte l'entreprise et qu'un autre est embauché,
un Bob complètement différent dans quelques mois. C'est la même chose
pour les adresses IP et des tas d'utilisateurs ont déjà souffert de se
voir attribuer une adresse IP qui avait une mauvaise réputation.
La section 5 résume les conseils les plus importants : se méfier des identifcateurs indéfinis, prévoir une comparaison absolue ou définie pour tous les identificateurs futurs, penser aux mécanismes pour valider les identificateurs (RFC 3696). Le gros risque restera toujours le cas où plus d'un protocole utilise un identificateur donné, car les différents protocoles n'auront pas forcément les mêmes règles de comparaison des identificateurs.
Date de publication du RFC : Mai 2013
Auteur(s) du RFC : J. Levine (Taughannock Networks), P. Hoffman (VPN Consortium)
Pour information
Première rédaction de cet article le 7 Mai 2013
Beaucoup d'utilisateurs des noms de domaine pensent que deux noms qui,
pour eux, sont « le même », devraient être traitées d'un bloc par le
DNS et/ou par les systèmes d'enregistrement de
noms. Tout le problème est évidemment de définir « le même » : il n'y
a en général pas d'accord entre les utilisateurs sur ce point. Ainsi,
des anglophones peuvent penser que
meter.example et
metre.example sont « le même nom » et devraient
donc se comporter ainsi. D'autres pensent que
pizzeria-napoli.example et
pizzerianapoli.example sont « le même nom ». Et,
évidemment, depuis l'arrivée des IDN, le
potentiel pour des noms « identiques » a encore augmenté. Il a donc
été proposé que ces variantes d'un « même » nom
soient explicitement reconnues. Ce RFC ne
suggère pas de mécanisme en ce genre (je pense personnellement que le
problème est bien trop flou et subjectif pour cela). Il se contente de
regarder les pratiques actuellement déployées par les
registres en matière de « variantes ».
Des exemples de caractères qui sont une « variante » d'un autre ne
manquent pas dans les écritures du monde. Ainsi, la
Chine a connu sous Mao
une réforme orthographique, passant des
sinogrammes
« traditionnels » aux
« simplifiés ». La plupart des sinophones
considèrent que 雲 et 云
sont des variantes du même mot. Dans les langues utilisant
l'alphabet latin avec des
accents, certains considèrent que le mot avec
et sans accent sont des variantes l'un de l'autre. Le RFC note qu'en
français certains omettent les accents sur les majuscules (c'est
incorrect, mais cela se fait parfois) et que donc
INTERNÉ et INTERNE sont
considérés comme « équivalents ». Ce qui est sûr, c'est
qu'historiquement, les difficultés à manier les caractères
non-ASCII dans beaucoup d'environnements
informatiques avaient mené bien des utilisateurs à considérer les
accents comme purement décoratifs, et pouvant être omis.
Est-ce que ce vague sentiment que deux groupes de caractères sont
« la même chose » peut être formalisé dans une définition rigoureuse
des « variantes » ? Il y a eu quelques tentatives comme à
l'ICANN, ou à l'IETF dans le RFC 3743 (non standard). Mais un autre
document de la même ICANN concluait
qu'il n'existait pas de définition utilisable. Ensuite, sur le
comportement attendu de deux noms identiques ne fait pas non plus
l'objet d'un consensus. Par exemple, si on veut, non pas seulement une
réponse identique dans le DNS, mais un vécu de
l'utilisateur identique, par exemple sur le
Web, il n'y a aucune solution purement DNS (en
raison du comportement de HTTP avec le champ
Host:). Si vous voulez lire davantage sur cette
question, je vous renvoie à mon article « Que veut dire synchroniser deux
domaines ? ».
Ce RFC n'essaie donc pas de régler ce problème (très ancien et sans doute insoluble). Il fait un tour d'horizon des pratiques des gTLD (qui sont contractuellement obligés par l'ICANN de rédiger leurs pratiques IDN et de les déposer à l'ICANN, et qui rendent accessibles le contenu de leurs zones, permettant aux chercheurs de l'étudier) et d'un certain nombre de ccTLD. Ces obligations de l'ICANN sont décrites dans « Guidelines for the Implementation of Internationalized Domain Names ». Le RFC note que ces règles ne sont guère respectées, les politiques déposées à l'ICANN étant souvent dépassées et plus à jour (URL cassés, personnes désormais parties, etc). (Mon opinion personnelle est que ces « IDN Guidelines » n'ont aucun sens et sont motivées par des frayeurs bureaucratiques plutôt que par des considérations pratiques.)
Pensez à réviser la terminologie en section 2. Un lot (bundle, on dit aussi IDL package) est un ensemble de noms qui sont tous des variantes les uns des autres (RFC 3743). Un nom est alloué (allocated) ou enregistré s'il est attribué à un titulaire. Il est actif (active) s'il apparait dans le DNS. Il est bloqué (blocked) s'il ne peut pas être alloué du tout et réservé (witheld) s'il ne peut être alloué que dans certaines conditions.
La section 4 décrit les politiques des gTLD (avec vérification dans
les fichiers de zone de la réalité de ces politiques). Certains sont
faciles : .aero,
.coop ou .pro n'ont pas
d'IDN (même chose pour .xxx). D'autres ont un grand intérêt pour les IDN. Ainsi,
.asia a évidemment une
politique
IDN détaillée, avec gestion de lots, via les enregistrements
NS (les variantes ont le même jeu de
NS). .cat a un cas plus
simple que .asia puisqu'il ne reconnait qu'une
seule langue, le catalan. La liste des
caractères autorisés est
publiée et elle comprend des caractères comme le l·l
(considéré comme un caractère en catalan mais représenté par trois
caractères Unicode). Lorsqu'on enregistre un nom IDN, l'ASCII
« équivalent » est aussi enregistré et un DNAME
(RFC 6672) est mis dans le fichier de
zones (il semble que cela soit le seul gTLD à procéder ainsi). Par
exemple :
xn--caball-gva.cat. 43200 IN DNAME caballe.cat.
Le nom IDN caballé.cat pointant vers
l'ASCII caballe.cat (et merci à DNSDB pour permettre l'exploration facile du DNS
à la recherche d'exemples).
Contrairement à .asia et a fortiori à
.cat,
.com doit gérer toutes les
écritures du monde. VeriSign a transmis à
l'ICANN des tables pour des écritures
hiéroglyphiques et pour
l'araméen... Les politiques suivies sont
décrites en détail dans plusieurs documents (voir la liste dans la
bibliographie du RFC). Pour l'écriture
chinoise, et pour elle seule, les variantes d'un nom
alloué sont
bloquées. (.net et
.name suivent la même
politique que .com.)
.org publie une liste des langues gérées (notez que
c'est absurde puisque IDN gère des écritures, pas des langues, mais
cette confusion est fréquente dans les cercles ICANN, où il est
toujours mal admis que des gens osent utiliser d'autres écritures que
celle des États-Unis). Les tables déposées à l'ICANN sont un
sous-ensemble de ces tables publiées par le registre (pas de mise à
jour ?) Les documentations officielles de .org font allusion à une politique
de gestion des variantes mais apparemment sans dire en quoi consiste
cette politique.
.tel a beaucoup d'IDN
et une politique
publique. Les noms avec l'écriture
japonaise utilisent un système de blocage (le premier
arrivé empêche l'allocation des variantes) alors que pour l'écriture
chinoise, les variantes sont publiées (avec des enregistrements NS identiques).
La section 5 passe aux ccTLD. Je ne vais pas tous les citer mais
ils ont souvent des politiques
intéressantes. .cl publie sa
politique, qui ne tient pas compte d'éventuelles variantes.
.cn a évidemment plus
de travail : leur politique est publiée sous forme d'un
RFC, le RFC 4713. Les
variantes sont publiées, avec des enregistrements NS. Par contre,
.ir n'a pas d'IDN. Comme
un certain nombre de registres des pays utilisant
l'écriture arabe (qui va de droite à gauche),
ils considèrent que le mélange d'un nom en écriture arabe avec un
TLD en écriture latine (allant de gauche à droite) n'est pas
souhaitable. (Mais il y a des IDN dans le TLD équivalent en écriture arabe, ایران.)
Bien que TLD d'un pays majoritairement anglophone,
.nz a une politique IDN (qui ne
parle pas des variantes) pour le maori. On
notera que le domaine compte des DNAME par exemple
māori.dns.net.nz qui pointe vers l'équivalent
ASCII :
xn--mori-qsa.dns.net.nz. 86400 IN DNAME maori.dns.net.nz.
Contrairement aux autres ccTLD, il semble que
.ru ne publie pas sa
politique directement, uniquement via la table déposée à l'ICANN.
La politique utilisée par
.fr n'est pas étudiée dans
ce RFC. Elle est disponible
en ligne.
La liste des caractères acceptés figure en section 2 (ce sont les
caractères utilisés pour les langues d'Europe de l'Ouest). S'il y a eu
un système de variantes pendant la période d'ouverture (section 4), il
a ensuite disparu.
Voilà, si vous voulez approfondir la question et voir la politique des autres TLD, consulter ce RFC. J'espère en tout cas avoir donné une bonne idée de la variété des écritures du monde et des solutions pour les gérer dans les noms de domaine.
Date de publication du RFC : Avril 2013
Auteur(s) du RFC : S. Rose (NIST)
Réalisé dans le cadre du groupe de travail IETF dnsext
Première rédaction de cet article le 2 Mai 2013
Mais quel algorithme de cryptographie choisir pour mes signatures DNSSEC, se demande l'ingénieur système ? Il y a bien un registre IANA des algorithmes normalisés mais c'est juste une liste non qualifiée, qui mêle des algorithmes de caractéristiques très différentes. Ce nouveau RFC vise à répondre à cette question en disant quels sont les algorithmes recommandés.
La première liste d'algorithmes possibles avait été faite dans le RFC 4034. D'autres algorithmes avaient été ajoutés par la suite. Certains sont devenus populaires. Par exemple, RSA avec SHA-2 est utilisé pour presque tous les TLD importants et est donc difficilement contournable pour un résolveur validant. D'autres ont été peu à peu abandonnés, parfois parce que les progrès de la cryptanalyse les menaçaient trop, parfois simplement parce qu'ils n'avaient pas un bon marketing.
Aujourd'hui, le développeur qui écrit ou modifie un logiciel résolveur validant (comme Unbound ou BIND) doit donc se taper pas mal de RFC mais aussi pas mal de sagesse collective distillée dans plusieurs listes de diffusion pour se faire une bonne idée des algorithmes que son logiciel devrait gérer et de ceux qu'il peut laisser tomber sans trop gêner ses utilisateurs.
Ce RFC 6944 détermine pour chaque algorithme s'il est indispensable (on n'a pas le droit de faire l'impasse), recommandé (ce serait vraiment bien de l'avoir, sauf raison contraire impérieuse), facultatif (si vous n'avez rien d'autre à faire de vos soirées que de programmer) ou tout simplement à éviter (pour le cas de faiblesses cryptographiques graves et avérées). La liste se trouve dans la section 2.3 : RSA avec SHA-1 est le seul indispensable. RSA avec SHA-1 plus NSEC3 (voir plus loin l'explication de ce cas particulier), RSA SHA-256 ou SHA-512 (connus collectivement comme SHA-2), ECDSA avec SHA-256 ou SHA-384 sont recommandés. Tous les autres sont facultatifs (c'est par exemple le cas de GOST dans le RFC 5933) sauf RSA avec MD5 qui est à éviter (RFC 6151).
La section 2.2 justifie ces choix : RSA+SHA-1 est l'algorithme de référence, celui qui assure l'interopérabilité (tout logiciel compatible DNSSEC doit le mettre en œuvre). Normalisé pour DNSSEC avant l'apparition de NSEC3 dans le RFC 5155, il existe en deux variantes, une sans NSEC3 (celle qui est indispensable) et une avec (qui est recommandée car la plupart des TLD utilisent NSEC3). RSA+SHA-2 est recommandé car, comme indiqué plus haut, la racine et la plupart des TLD l'utilisent. Un résolveur qui ne comprendrait pas ces algorithmes ne servirait pas à grand'chose.
Au contraire, ECDSA est très peu utilisé en pratique. Mais les courbes elliptiques suscitent beaucoup d'intérêt, et sont une alternative au cas où il y aurait un gros problème avec RSA. D'où le statut « Recommandé ».
Des nouveaux algorithmes vont certainement apparaître dans le registre (cf. RFC 6014). Ils seront automatiquement considérés comme facultatifs, jusqu'à la sortie d'un nouveau RFC qui remplacerait ce RFC 6944.
Date de publication du RFC : Avril 2013
Auteur(s) du RFC : Alan DeKok (Network RADIUS), Avi Lior
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF radext
Première rédaction de cet article le 1 Mai 2013
RADIUS, un protocole utilisé pour l'authentification (et la configuration) d'accès à l'Internet, est ancien et marche toujours. Lorsque vous accédez à l'Internet depuis chez vous, sans vous en rendre compte, vous avez probablement indirectement utilisé RADIUS. Il marche toujours très bien mais, rançon du succès, il a été tellement étendu qu'un certain nombre de champs du message RADIUS sont désormais pleins : toutes les options possibles seront allouées très bientôt. Ce nouveau RFC décrit un mécanisme d'extension de RADIUS, permettant de continuer l'enregistrement de nouvelles options, au prix de quelques bricolages.
Il y a peu de gens qui manipulent RADIUS (RFC 2865) explicitement. Ce protocole se trouve en effet caché dans le réseau du FAI, entre la machine qui contrôle l'accès (le NAS) et un serveur RADIUS qui contient les données sur les utilisateurs. RADIUS permet de ne pas avoir à copier les informations d'authentification, ou les paramètres d'un utilisateur donné, directement dans tous les NAS, mais de les centraliser dans un petit nombre de serveurs RADIUS.
La requête, et surtout la réponse RADIUS peuvent contenir un
certain nombre d'attributs (RFC 2865, section 5) comme « nom de l'utilisateur », « mot de
passe », « adresse IP à attribuer », etc. Le champ
« Attribute » est en TLV et
le type (User-Name = 1,
User-Password = 2,
Framed-IP-Address = 8, etc) est encodé sur un
seul octet. La liste (un registre
IANA) est aujourd'hui bien remplie et devrait l'être
complètement en 2014 ou
2015. C'est le principal problème de RADIUS
aujourd'hui (section 1 de notre RFC). Mais il y en a d'autres comme le
fait que la longueur d'un attribut soit codé sur un octet seulement
(donc 253 octets maximum pour la valeur d'un attribut, puisqu'il faut
retirer le type et la longueur).
Notre RFC fait donc les changements suivants :
Voilà, c'est l'essentiel du RFC. Ceux qui étendent le protocole RADIUS vont sans doute migrer vers les nouveaux types, dès aujourd'hui, ou bien lorsque les anciens seront épuisés.
Des exemples d'encodage figurent en section 9. Par exemple, un
attribut utilisant un type étendu (ici, 241.1) et ayant une valeur de type texte
(la chaîne "bob") se représentera f1 06 01 62 6f
62 (f1, le type, 241,
06 la longueur totale, 01 le
sous-type du type étendu, 1 (à la place du premier octet de la
valeur), 62 6f 62 la vraie valeur, la chaîne
de caractères). Plus compliqué, un attribut 241.2 contenant un TLV
dont le type est 1, la longueur 4 et la valeur 23
45, sera représenté f1 07 02 01 04 23
45.
Avec les étendus longs (Long Extended
Type), un attribut 245.1 contenant le même "bob" sera
f5 07 01 00 62 6f 62 (f5 est
le type, la longueur est de sept octets, 01 est
la suite du type, l'octet supplémentaire est à 0 (donc le bit M
aussi : pas d'autres attributs à attendre) et la valeur est la chaîne
"bob" (62 6f 62 en
ASCII). Si un type 245.4 encode plus de 251
octets (ici, 260 octets de valeur), on
aura le premier attribut qui commencera par f5 ff 04
80 (longueur totale à 256 octets, l'octet supplémentaire vaut 80, indiquant que le bit M
est à Un) et un deuxième attribut qui commencera par f5 13
04 00 (octet supplémenaire à 0 donc bit M à Zéro, ce second
attribut est le dernier). La longueur totale est ff +
13 soit 260 octets pour la valeur.
Si vous voulez tester vous-même ces nouveaux types et leur encodage, l'annexe A du RFC contient un programme en C qui permet exactement cela (copie locale du source). Il s'utilise ainsi :
% echo '241.1 "bob"' | ./radius-attr-generator
241.1 "bob" -> f1 06 01 62 6f 62
% echo '243.2 42' | ./radius-attr-generator
243.2 42 -> f3 04 02 42
# Plus drôle, un TLV dans un TLV :
% echo '241.4 { 1 23 45 } { 3 { 1 ab cd } }' | ./radius-attr-generator
241.4 { 1 23 45 } { 3 { 1 ab cd } } -> f1 0d 04 01 04 23 45 03 06 01 04 ab cd
Parmi les autres nouveautés du RFC, il y a la formalisation de la
convention de nommage informel des attributs : mots séparés par des
tirets (par exemple Framed-MTU), attributs
spécifiques à un vendeur préfixés par le nom du vendeur (par exemple
Starbucks-Latte-Size pour un vendeur nommé
Starbucks).
Le changement apporté au protocole n'est pas trivial, mais soigneusement conçu pour maintenir la compatibilité. La section 5 du RFC note toutefois quelques problèmes potentiels. D'abord, certains vendeurs se sont approprié des numéros de types qui étaient marqués comme réservés (et qui sont désormais utilisés pour les types étendus). Comme le notait le RFC 6158, c'est un comportement anti-social. Maintenant que ces numéros réservés sont utilisés, ces attributs spécifiques au vendeur anti-social ne marcheront plus (bien fait).
Autre problème potentiel, il est fréquent que les messages RADIUS soient relayés par un serveur intermédiaire (RFC 2865, section 2.3), notamment en cas d'itinérance. Idéalement, le relais devrait ignorer les attributs qu'il ne comprennent pas. Si, par contre, il rejette les messages contenant ces attributs nouveaux, un client et un serveur conformes au nouveau format ne pourront pas communiquer à travers un tel relais. Notre RFC rappelle bien qu'un relais devrait être transparent et relayer même ce qu'il ne comprend pas.
Les sections 6.6 et 10.3 fournissent les règles d'enregistrement des nouveaux types. Il est recommandé d'y aller mollo : les nouveaux espaces sont plus grands mais pas infinis. Le registre IANA stocke désormais des attributs des nouveaux types.
Devoir ajuster a posteriori un protocole, qui avait été conçu d'une certaine manière, et qui esr assez rigide, est toujours une opération délicate, spécialement lorsqu'il faut maintenir la compatibilité avec l'existant. Des tas de propositions ont été faites depuis des années, pour étendre RADIUS. La section 7 du RFC documente pourquoi celle-ci a été choisie. D'abord, elle est relativement simple, avec peu de modifications du format. Son principal inconvénient est que le format des Long Extended Type est assez baroque.
Quant au mécanisme pour agrandir la taille possible des valeurs, il a d'abord été conçu pour ne pas changer les attributs dont la valeur restait petite. D'après une étude de 2010 (citée en section 7.1) portant sur tous les dictionnaires Radius connus, les entiers représentent près de la moitié des valeurs d'attributs RADIUS publics. En ajoutant les autres types de taille fixe (adresses IP, par exemple), on arrive à plus de la moitié. Il fallait donc éviter de faire payer ces types peu consommateurs en octets.
Plusieurs des mises en œuvre de Radius gèrent déjà ces extensions, par exemple FreeRADIUS. Il faut dire qu'il n'y a guère le choix, vue l'imminence de l'épuisement.
Date de publication du RFC : Avril 2013
Auteur(s) du RFC : G. Fairhurst (University of Aberdeen), M. Westerlund (Ericsson)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF 6man
Première rédaction de cet article le 1 Mai 2013
Le RFC 2460 qui normalise IPv6 indique dans sa section 8.1 que les paquets UDP sur IPv6 doivent avoir une somme de contrôle (elle était facultative en IPv4) calculée selon le RFC 1071. Dans quels cas est-elle réellement nécessaire ? Peut-on s'en passer parfois ? Ce nouveau RFC discute des conditions qui peuvent permettre de mettre zéro dans le champ Checksum, indiquant qu'on n'a pas utilisé de somme de contrôle. Pour résumer : si on veut se passer de somme de contrôle, cela doit se faire application par application, il faut être sûr qu'on supporte les paquets corrompus ou délivrés à tort, et il faut tester le chemin emprunté pour être sûr que les « nouveaux » paquets passent bien.
Ce RFC discute des solutions à un problème de performance d'UDP et des conditions dans lesquels on peut ne plus mettre de somme de contrôle. Il sert donc d'arrière-plan au RFC normatif, le RFC 6935 qui définit les nouvelles règles pour UDP sur IPv6 (somme de contrôle facultative) et fait donc un choix ferme parmi les propositions discutées ici. Notez toutefois qu'il y a pas mal de recouvrement et de redites entre les deux RFC.
UDP est très utilisé, et pour beaucoup d'applications (le RFC 5405 donne des conseils à ce sujet). Un des usages fréquents est pour construire des tunnels, afin de pouvoir passer à travers les millions de middleboxes stupides qui infestent l'Internet, et qui bloquent souvent tous les protocoles autres que UDP et TCP. Or, un routeur d'entrée ou de sortie de tunnel peut avoir à encapsuler ou décapsuler des millions de paquets par seconde et la génération ou la vérification des sommes de contrôle de chaque paquet peut avoir un effet mesurable sur ses performances (sections 1.3.2 et 1.3.3). D'autant plus qu'il n'est pas toujours possible d'utiliser le matériel spécialisé du routeur pour cela car il ne donne souvent accès qu'aux N premiers octets du paquet (avec N typiquement < 128), alors que le calcul de la somme de contrôle nécessite d'accéder à tout le paquet.
En UDP/IPv4, la solution est de couper la somme de contrôle sur le paquet externe (le protocole interne, qui n'est pas forcément UDP, reste protégé par sa propre somme de contrôle), ce qui est légal en IPv4. Le tunnel devient alors un lien virtuel non fiable, pouvant corrompre des paquets (comme c'est le cas d'un certain nombre de liens physiques). C'est par exemple la solution recommandée pour un gros consommateur de tunnels UDP, LISP. Il est donc tentant de l'utiliser également en UDP/IPv6.
Cela peut poser des problèmes avec certaines middleboxes qui vérifient la somme de contrôle UDP et n'accepteront pas d'y trouver zéro. Décréter que la somme de contrôle UDP en IPv6 devient facultative ne signifie donc pas que ces paquets optimisés pourront voyager dès demain sur tout l'Internet : un certain nombre de pare-feux les bloqueront. Cela peut sembler un problème rédhibitoire (on utilisait UDP justement pour passer facilement à travers les middleboxes puis on réforme les règles d'UDP, créant des paquets qui sembleront illégaux à beaucoup de ces middleboxes) mais il faut noter que la plupart des ces middleboxes ne font pas encore d'IPv6 et que donc les premiers déploiements ont des chances de se faire avec des middleboxes conformes à la nouvelle règle.
À part l'UDP existant, et l'UDP avec somme facultative du RFC 6935, quelles sont les autres technologies disponibles pour des tunnels (section 2 du RFC) ? Il y a UDP Lite (RFC 3828), avec une somme de contrôle qui ne couvre que le début du paquet (et est donc rapide à calculer), et qui est certes mis en œuvre dans le noyau Linux mais qui est peu reconnu par les middleboxes. Il utilise un identifiant (champ Next Header qui identifie en général le protocole de transport) différent de celui d'UDP (136 contre le 17 d'UDP) et est donc souvent bloqué par des pare-feux trop zélés. Il y a les techniques de tunnels génériques comme IP-in-IP et GRE. Elles n'ont pas de somme de contrôle du tout et sont donc rapides. Ce sont les solutions idéales pour les tunnels mais elles aussi utilisent un champ Next Header qui peut ne pas être connu de la middlebox (94 pour IP-in-IP et 47 pour GRE) et ils passent certainement moins souvent qu'UDP (d'où le choix d'UDP pour LISP). Notons aussi que la section 6 déconseille les tunnels récursifs (un tunnel dans un tunnel dans un tunnel...) qui augmentent les risques d'erreur pour le paquet le plus interne (et ajoutent une grande complexité à la fragmentation).
La section 3 examine ensuite les choses qui peuvent aller mal avec la solution retenue par le RFC 6935. Si on ne met pas de somme de contrôle dans le paquet UDP (ou, plus exactement, qu'on met zéro, indiquant qu'on n'a pas calculé de somme et que le récepteur ne doit pas vérifier), et qu'un bit du paquet est modifié, que peut-il se passer d'horrible ? Pour IPv4, la somme de contrôle UDP ne servait qu'à protéger les numéros de port et les données, des informations comme l'adresse IP de destination étaient protégées par la somme de contrôle de la couche 3. Celle-ci a disparu en IPv6 et la somme de contrôle UDP doit donc tout faire. Si elle est erronée, on n'est même pas sûr que le paquet nous était bien destiné (l'adresse IP de destination a pu être modifiée).
Comme l'expliquent le RFC 3819 ou des études comme « When the CRC and TCP Checksum Disagree », la corruption arrive réellement dans l'Internet. Des mesures ont indiqué jusqu'à 1 paquet corrompu sur 10 000 (cela dépend fortement du chemin suivi : le taux de corruption est quasi-nul sur certains chemins). Le RFC note (section 3.2) qu'on ne sait pas exactement où la corruption survient : cela peut être dans la RAM du routeur, sur le câble, dans les récepteurs et les émetteurs optiques ou électriques, etc.
Si c'est l'adresse IP de destination qui est modifiée, le paquet peut n'arriver nulle part, ou bien arriver à une machine qui ne l'attend pas. Si aucun programme n'écoute sur le port en question, le paquet est jeté (et un message d'erreur envoyé à la source, qui sera bien surprise). Si un programme écoute, il va recevoir un paquet invalide. Mëme chose si c'est le port de destination seul qui a été corrompu. Si l'application n'a pas de mécanisme (comme des numéros de séquence) pour détecter le problème, le paquet invalide pourra être accepté. Donc, une règle importante : une application qui est prête à débrayer les sommes de contrôle UDP doit être prête à réagir proprement si elle reçoit un datagramme envoyé à tort. C'est une des raisons pour lesquelles le RFC exige que la suppression de la somme de contrôle UDP ne se fasse pas globalement, pour toute la machine ou pour toute l'interface réseau, mais uniquement sur requête explicite d'une application majeure et consentante (section 3.5)
Si c'est l'adresse IP source qui est corrompue, le paquet arrivera sans doute à la bonne destination (mais pas à coup sûr, par exemple en cas de filtrage RFC 2827). Si l'application garde en mémoire ses correspondants, le paquet de ce correspondant inconnu sera jeté. Si elle ne le fait pas, si une réponse est envoyée... elle le sera au mauvais correspondant.
Et si c'est l'information de fragmentation qui est corrompue ? Cela peut empêcher le réassemblage (menant à la perte du paquet) mais aussi, ce qui est bien pire, conduire à des réassemblages erronés (par exemple, si le champ ID est modifié, attribuant le fragment à un autre datagramme). Comme le note le RFC 5722, il faut multiplier les tests lors du réassemblage.
Nous avons vu plus haut qu'un certain nombre de boîtiers intermédiaires jetteraient probablement sans autre forme de procès ces « nouveaux » paquets UDP avec une somme de contrôle nulle (ils étaient illégaux avant la sortie du RFC 6935). Il est donc essentiel, pour une application qui veut utiliser cette nouveauté, de tester le chemin et de vérifier que rien sur le trajet ne jette les paquets sans somme de contrôle. Il faut aussi penser à répéter ce test de temps en temps : le chemin peut changer (par exemple parce que BGP l'a décidé) et passer tout à coup par des boîtiers différents. (Et il faut faire le test dans les deux sens, ne serait-ce que parce que le routage n'est pas forcément symétrique.)
Dans tous les cas, il faut se rappeler que la somme de contrôle ne fournit de protection que contre la corruption accidentelle. Ce n'est pas un mécanisme d'authentification, et elle ne protège pas du tout contre un attaquant (qui peut modifier le paquet sans changer la somme de contrôle).
Les règles d'applicabilité sont formalisées dans les sections 4 (pour les implémentations) et 5 (pour l'usage de ces implémentations). Les programmes qui mettent en œuvre UDP sur IPv6 :
Cela, c'était pour l'implémentation d'UDP et d'IPv6 (qui, dans un Unix, est dans le noyau). Maintenant, pour les applications qui l'utilisent, la section 5 dit qu'elles :
Voilà, les règles d'applicabilités sont posées. Mais le RFC compte aussi une annexe intéressante, l'annexe A, qui est consacrée aux propositions alternatives. La solution choisie par le RFC 6935 a été d'autoriser les sommes de contrôle nulles. Mais on aurait pu faire différemment. Par exemple, le problème de performance et d'accès à la totalité du paquet aurait pu être traité par les calculs incrémentaux de somme de contôle du RFC 1624 (mais ils ne marchent pas quand il y a fragmentation IP). On aurait pu, comme cité, utiliser un protocole comme UDP Lite, ou UDPTT. Il avait aussi été proposé une mesure unilatérale, qu'un receveur ignore la somme de contrôle, quoiqu'ait mis l'émetteur (c'était plus simple mais il était alors impossible de détecter la corruption, pour tous les paquets). D'autres avaient suggéré une nouvelle option dans un en-tête Destination Options, ce qui revenait, à mon avis, à réintroduire une somme de contrôle en couche 3, ce qu'IPv6 avait délibérement abandonné. De toute façon, beaucoup de middleboxes auraient jeté les paquets avec cet en-tête (qui est rare, en pratique). Ces différentes propositions sont examinées en fonction de plusieurs critères : traversabilité des middleboxes, performances, déployabilité et résistance à la corruption de paquets.
Pour la traversée des middleboxes, l'UDP actuel ou bien un UDP avec un calcul incrémental des sommes de contrôle, est ce qui marche le mieux. Aucun changement à faire. L'UDP sans somme de contrôle du RFC 6935 aura sans doute quelques soucis (actuellement, de tels paquets sont illégaux), ainsi que les paquets avec l'en-tête Destination Options (pourtant légaux). Et les tunnels génériques seront sans doute bloqués par défaut par la plupart des pare-feux, ainsi qu'UDP Lite.
C'est à peu près la même chose pour la déployabilité : l'UDP actuel existe déjà et n'a pas à être déployé. Les sommes de contrôle facultatives du RFC 6935 nécessiteront au moins un changement dans les extrêmités (ne pas calculer la somme, ne pas la vérifier) mais aussi dans certaines middleboxes qui se mêlent de vérifier la somme de contrôle, alors qu'on ne leur a rien demandé.
Pour les performances, l'UDP actuel est certainement le pire, puisqu'il faut calculer la somme de contrôle sur la totalité du paquet. C'est bien cela qui a motivé tout ce travail sur la réforme des sommes de contrôle UDP. UDP Lite, qui ne vérifie qu'une partie du paquet, et l'UDP réformé du RFC 6935 ont des bien meilleures performances (c'est aussi le cas des tunnels génériques).
Bref, il n'y a pas de solution parfaite, qui résolve tous les problèmes. Si on veut avant tout passer partout, l'UDP actuel est la meilleure solution. Si on veut une solution propre architecturalement, IP-in-IP est parfait. Si on se préoccupe des performances, l'UDP avec somme de contrôle facultative du RFC 6935 est une bonne approche et reçoit un avis favorable dans ce RFC.
Articles des différentes années : 2013 2012 2011 2010 2009 2008 2007 Précédentes années
Syndication : Flux Atom avec seulement les résumés et Flux Atom avec tout le contenu