Date de publication du RFC : Mai 2021
Auteur(s) du RFC : J. Iyengar (Fastly), M. Thomson (Mozilla)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF quic
Première rédaction de cet article le 28 mai 2021
Le protocole de transport QUIC vient d'être normalisé, dans une série de quatre RFC. J'ai écrit un résumé synthétique de QUIC, cet article porte sur le principal RFC du groupe, celui qui normalise le cœur de QUIC, le mécanisme de transport des données. QUIC, comme TCP, fournit aux protocoles applicatifs un service de transport des données fiable, et en prime avec authentification et confidentialité.
L'un des buts principaux de QUIC est de réduire la latence. La capacité des réseaux informatiques augmente sans cesse, et va continuer de la faire, alors que la latence sera bien plus difficile à réduire. Or, elle est déterminante dans la perception de « vitesse » de l'utilisateur. Quels sont les problèmes que pose actuellement l'utilisation de TCP, le principal protocole de transport de l'Internet ?
Le cahier des charges de QUIC était à peu près :
Certains de ces objectifs auraient pu être atteints en modifiant TCP. Mais TCP étant typiquement mis en œuvre dans le noyau du système d'exploitation, tout changement de TCP met un temps trop long à se diffuser. En outre, si les changements à TCP sont importants, ils peuvent être bloqués par les boitiers intermédiaires, comme si c'était un nouveau protocole.
QUIC peut donc, plutôt qu'à TCP, être comparé à SCTP tournant sur DTLS (RFC 8261), et on peut donc se demander pourquoi ne pas avoir utilisé ce système. C'est parce que :
Pour une comparaison plus détaillée de SCTP et QUIC, voir
l'Internet-Draft draft-joseph-quic-comparison-quic-sctp
.
(SCTP peut aussi tourner sur UDP - RFC 6951
mais j'ai plutôt utilisé SCTP sur DTLS comme point de comparaison,
pour avoir le chiffrement.) Notez que ces
middleboxes intrusives sont particulièrement
répandues dans les réseaux pour mobiles, type
4G (où elles sont parfois appelée
TCP proxies), puisque c'est un monde où on viole
bien plus facilement la neutralité du
réseau.
Faire mieux que TCP n'est pas évident. Ce seul RFC fait 207 pages, et il y a d'autres RFC à lire. Déjà, commençons par un peu de terminologie :
PING
sert uniquement à déclencher l'accusé de
réception, alors que STREAM
contient des
données de l'application.Maintenant, plongeons dans le RFC. Rappelez-vous qu'il est long ! Commençons par les ruisseaux (section 2 du RFC). Ils ressemblent aux ruisseaux de HTTP/2 (RFC 9113), ce qui est logique, QUIC ayant été conçu surtout en pensant à HTTP. Chaque ruisseau est un flux ordonné d'octets. Dans une même connexion QUIC, il y a plusieurs ruisseaux. Les octets d'un ruisseau sont reçus dans l'ordre où ils ont été envoyés (plus exactement, QUIC doit fournir ce service mais peut aussi fournir un service dans le désordre), ce qui n'est pas forcément le cas pour les octets d'une même connexion. (Dans le cas de HTTP, cela sert à éviter qu'une ressource lente à se charger ne bloque tout le monde.) Comme avec TCP, les données sont un flot continu, même si elles sont réparties dans plusieurs trames. La création d'un ruisseau est très rapide, il suffit d'envoyer une trame avec l'identifiant d'un ruisseau et hop, il est créé. Les ruisseaux peuvent durer très longtemps, ou au contraire tenir dans une seule trame.
J'ai parlé de l'identifiant d'un ruisseau. Ce numéro, ce stream ID est pair pour les ruisseaux créés par le client, impair s'ils sont créés par le serveur. Cela permet à client et serveur de créer des ruisseaux sans se marcher sur les pieds. Un autre bit dans l'identifiant indique si le ruisseau est bidirectionnel ou unidirectionnel.
Une application typique va donc créer un ou plusieurs ruisseaux,
y envoyer des données, en recevoir, et fermer les ruisseaux,
gentiment (trame STREAM
avec le bit
FIN
) ou brutalement (trame
RESET_STREAM
). La machine à états complète des
ruisseaux figure dans la section 3 du RFC.
Comme avec TCP, il ne s'agit pas d'envoyer des données au débit
maximum, sans se soucier des conséquences. Il faut se contrôler, à
la fois dans l'intérêt du réseau (éviter la
congestion) et dans celui du récepteur, qui a
peut-être du mal à traiter tout ce qu'on lui envoie. D'où, par
exemple, la trame STOP_SENDING
qui dit à
l'émetteur de se calmer.
Plus fondamentalement, le système de contrôle de QUIC est décrit
dans la section 4. Il fonctionne aussi bien par ruisseau qu'au
niveau de toute la connexion. C'est le récepteur qui contrôle ce que
l'émetteur peut envoyer, en disant « j'accepte au total N
octets ». Il le fait à l'établissement de la connexion puis,
lorsqu'il peut à nouveau traiter des données, via les trames
MAX_DATA
(pour l'ensemble de la connexion) et
MAX_STREAM_DATA
(valables, elles, pour un seul
ruisseau). Normalement, les quantités d'octets que l'émetteur peut
envoyer sont toujours croissantes. Par exemple, à l'établissement de
la connexion, le récepteur annonce qu'il peut traiter 1 024
octets. Puis, une fois qu'il a des ressources disponibles, il
signalera qu'il peut traiter 2 048 octets. Si l'émetteur ne lui
avait transmis que 1 024, cette augmentation lui indiquera qu'il
peut reprendre l'émission. Si l'émetteur envoie plus de données
qu'autorisé, le récepteur ferme brutalement la connexion. À noter
que les trames de type CRYPTO
ne sont pas
concernées car elles peuvent être nécessaires pour changer les
paramètres cryptographiques (RFC 9001, section 4.1.3).
J'ai parlé des connexions QUIC mais pas encore dit comment elles
étaient établies. La section 5 le détaille. Comme QUIC tourne sur
UDP, un certain
nombre de gens n'ont pas compris le rôle d'UDP et croient que QUIC
est sans connexion. Mais c'est faux, QUIC impose l'établissement
d'une connexion, c'est-à-dire d'un état partagé entre l'initiateur
(celui qui sollicite une connexion) et le répondeur. La négociation
initiale permettra entre autres de se mettre d'accord sur les
paramètres cryptographiques, mais aussi sur le protocole applicatif utilisé (par exemple
HTTP). QUIC permet d'envoyer des données dès le premier paquet (ce
qu'on nomme le « 0-RTT ») mais rappelez-vous que, dans ce cas, vous
n'êtes plus protégé contre les attaques par
rejeu. Ce n'est pas grave pour un
GET
HTTP mais cela peut être gênant dans
d'autres cas.
Une fonction essentielle aux connexions QUIC est le
connection ID. Il s'agit d'un identificateur de
la connexion, qui lui permettra notamment de survivre aux
changements de connectivité (passage de 4G dehors en WiFi chez soi,
par exemple) ou aux fantaisies des routeurs NAT qui peuvent
subitement changer les ports utilisés. Quand
un paquet QUIC arrive sur une machine, c'est ce connection
ID qui sert à démultiplexer les paquets entrants, et à
trouver les paramètres cryptographiques à utiliser pour le
déchiffrer. Il n'y a pas qu'un connection ID
mais tout un jeu, car, comme il circule en clair, il pourrait être
utilisé pour suivre à la trace un utilisateur. Ainsi, quand une
machine change d'adresse IP, la bonne pratique est de se mettre à
utiliser un connection ID qui faisait partie du
jeu de départ, mais n'a pas encore été utilisé, afin d'éviter qu'un
surveillant ne fasse le rapprochement entre les deux adresses
IP. Notez que le jeu de connection ID négocié au
début peut ensuite être agrandi avec des trames
NEW_CONNECTION_ID
.
Dans quel cas un port peut-il changer ? QUIC utilise UDP, pour maximiser les chances de passer à travers les pare-feux et les routeurs NAT. Cela pose des problèmes si le boitier intermédiaire fait des choses bizarres. Par exemple, si un routeur NAT décide de mettre fin à une connexion TCP qui n'a rien envoyé depuis longtemps, il peut génerer un message RST (ReSeT) pour couper la connexion. Rien de tel en UDP, où le routeur NAT va donc simplement supprimer de sa table de correspondance (entre adresses publiques et privées) une entrée. Après cela, les paquets envoyés par la machine externe seront jetés sans notification, ceux envoyés par la machine interne créeront une nouvelle correspondance, avec un port source différent et peut-être même une adresse IP source différente. La machine externe risque donc de ne pas les reconnaitre comme des paquets appartenant à la même connexion QUIC. En raison des systèmes de traduction d'adresses, l'adresse IP source et le port source vus par le pair peuvent changer pendant une même « session ». Pour permettre de reconnaitre une session en cours, QUIC utilise donc le connection ID, un nombre de longueur variable généré au début de la connexion (un dans chaque direction) et présent dans les paquets. (Le connection ID source n'est pas présent dans tous les paquets.)
Vous avez vu qu'une connexion QUIC peut parfaitement changer
d'adresse IP en cours de route. Cela aura certainement des
conséquences pour tous les systèmes qui enregistrent les adresses
IP comme identificateur d'un dialogue, du
journal d'un serveur HTTP (qu'est-ce que
Apache va mettre dans son
access_log
?) aux surveillances de la
HADOPI.
Pour limiter les risques qu'une correspondance dans un routeur
faisant de la traduction d'adresses n'expire, QUIC dispose de
plusieurs moyens de
keepalive comme les trames
de type PING
.
Comment l'application qui utilise QUIC va-t-elle créer des connexions et les utiliser ? La norme QUIC, dans notre RFC, ne spécifie pas d'API. Elle expose juste les services que doit rendre QUIC aux applications, notamment :
PING
, par exemple
pour s'assurer que la connexion reste ouverte,Le RFC ne le spécifie pas, mais il faudra évidemment que QUIC permette à l'application d'envoyer et de recevoir des données.
Il n'y a actuellement qu'une seule version de QUIC, la 1, normalisée dans notre RFC 9000 (cf. section 15). Dans le futur, d'autres versions apparaitront peut-être, et la section 6 du RFC explique comment se fera la future négociation de version (ce qui sera un point délicat car il faudra éviter les attaques par repli). Notez que toute version future devra se conformer aux invariants du RFC 8999, une garantie de ce qu'on trouvera toujours dans QUIC.
Un point important de QUIC est qu'il n'y a pas de mode « en
clair ». QUIC est forcément protégé par la
cryptographie. L'établissement de la
connexion impose donc la négociation de paramètres cryptographiques
(section 7). Ces paramètres sont mis dans une trame
CRYPTO
qui fait partie du premier paquet
envoyé. QUIC version 1 utilise TLS (RFC 9001). Le serveur est toujours authentifié, le client peut
l'être. C'est aussi dans cette négociation cryptographique qu'est
choisie l'application, via ALPN (RFC 7301).
Dans le cas courant, quatre paquets sont échangés,
Initial
par chacun des participants, puis
Handshake
. Mais, si le 0-RTT est accepté, des
données peuvent être envoyées par l'initiateur dès le premier
paquet.
Puisqu'UDP,
comme IP, ne protège
pas contre l'usurpation
d'adresse IP, QUIC doit valider les adresses IP utilisées,
pour éviter, par exemple, les attaques par réflexion (section
8). Si un initiateur contacte un répondeur en disant « mon adresse
IP est 2001:db8:dada::1
», il ne faut pas le
croire sur parole, et lui envoyer plein de données sans
vérification. QUIC doit valider
l'adresse IP de son correspondant, et le revalider lorsqu'il
change d'adresse IP. À l'établissement de la connexion, c'est la
réception du paquet Handshake
, proprement
chiffré, qui montre que le correspondant a bien reçu notre paquet
Initial
et a donc bien l'adresse IP qu'il
prétend avoir. En cas de changement d'adresse IP, la validation
vient du fait que le correspondant utilise un des
connection ID qui avait été échangés précédemment
ou d'un test explicite de joignabilité avec les trames
PATH_CHALLENGE
et
PATH_RESPONSE
. Sur ces migrations, voir aussi
la section 9.
Pour les futures connexions, on utilisera un jeton qui avait été
transmis dans une trame NEW_TOKEN
et qu'on a
stocké localement. (C'est ce qui permet le 0-RTT.) Le RFC ne
spécifie pas le format de ce jeton, seule la machine qui l'a créé et
qui l'envoie à sa partenaire a besoin de le comprendre (comme pour un
cookie). Le RFC conseille également de n'accepter
les jetons qu'une fois (et donc de mémoriser leur usage) pour
limiter le risques de rejeu.
Tant que la validation n'a pas été faite, une machine
QUIC ne doit pas envoyer plus de trois fois la quantité de données
reçue (pour éviter les attaques avec
amplification). C'est pour cela que le paquet
Initial
est rempli de manière à atteindre une
taille (1 200 octets, exige le RFC) qui garantit que l'autre machine
pourra répondre, même si elle a beaucoup à dire.
Une fois qu'on est connectés, on peut s'échanger des données, qui
feront l'objet d'accusés de réception de la part du voisin (trames
de type ACK
). Contrairement au TCP classique,
les accusés de réception ne sont pas forcément contigus, comme dans
l'extension SACK du RFC 2018. Si l'accusé de
réception n'est pas reçu, l'émetteur réémet, comme avec TCP.
Bon, une fois qu'on a ouvert la connexion, et échangé des
données, quand on n'a plus rien à dire, que fait-on ? On
raccroche. La section 10 du RFC explique comment se terminent les
connexions QUIC. Cela peut se produire suite à une inactivité
prolongée, suite à une fermeture explicite normale, ou bien avec le
cas particulier de la fermeture sans état. Chacun des partenaires
peut évidemment estimer que, s'il ne s'est rien passé depuis
longtemps, il peut partir. (Cette durée maximale d'attente peut être
spécifiée dans les paramètres à l'établissement de la connexion.)
Mais on peut aussi raccrocher explicitement à tout moment (par
exemple parce que le partenaire n'a pas respecté le protocole QUIC),
en envoyant une trame de type
CONNECTION_CLOSE
. Cela fermera la connexion et,
bien sûr, tous ses ruisseaux.
Pour que la trame CONNECTION_CLOSE
soit
acceptée par l'autre machine, il faut que son émetteur connaisse les
paramètres cryptographiques qui permettront de la chiffrer
proprement. Mais il y a un cas ennuyeux, celui où une des deux
machines a redémarré, tout oublié, et reçoit des paquets d'une
ancienne connexion. Comment dire à l'autre machine d'arrêter d'en
envoyer ? Avec TCP, on envoie un paquet RST
(ReSeT) et c'est bon. Mais cette simplicité est
dangereuse car elle permet également à un tiers de faire des
attaques par déni de service en envoyant des
« faux » paquets RST. Des censeurs ou des FAI voulant
bloquer du trafic pair-à-pair ont déjà
pratiqué ce genre d'attaque. La solution QUIC à ce double problème
est la fermeture sans état (stateless
reset). Cela repose sur l'envoi préalable d'un jeton (cela
peut se faire via un paramètre lors de l'établissement de la
connexion, ou via une trame
NEW_CONNECTION_ID
). Pour pouvoir utiliser ces
jetons, il faudra donc les stocker, mais il ne sera pas nécessaire
d'avoir les paramètres cryptographiques : on ne chiffre pas le
paquet de fermeture sans état, il est juste authentifié (par le
jeton). Si la perte de mémoire est totale (jeton stocké en mémoire
non stable, et perdu), il ne reste plus que les délais de garde pour
mettre fin à la connexion. Évidemment, le jeton ne peut être utilisé
qu'une fois, puisqu'un surveillant a pu le copier. Notez que les
détails de ce paquet de fermeture sans état sont soigneusement
conçus pour que ce paquet soit indistinguable d'un paquet QUIC
« normal ».
Dans un monde idéal, tout fonctionnera comme écrit dans le
RFC. Mais, dans la réalité, des machines ne vont pas suivre le
protocole et vont faire des choses anormales. La section 11 du RFC
couvre la gestion d'erreurs dans QUIC. Le problème peut être dans la
couche de transport, ou dans l'application (et, dans ce cas, il peut
être limité à un seul ruisseau). Lorsque l'erreur est dans la couche
transport et qu'elle semble irrattrapable, on ferme la connexion
avec une trame CONNECTION_CLOSE
. Si le problème
ne touche qu'un seul ruisseau, on peut se contenter d'une trame
RESET_STREAM
, qui met fin juste à ce ruisseau.
On a parlé de paquets et de trames. La section 12 précise ces termes :
Parmi les paquets, il y a les paquets longs et les paquets
courts. Les paquets longs, qui contiennent tous les détails, sont
Initial
, Handshake
,
0-RTT
et Retry
. Ce sont
surtout ceux qui servent à établir la connexion. Les paquets courts
sont le 1-RTT
, qui ne peut être utilisé
qu'après l'établissement complet de la connexion, y compris les
paramètres cryptographiques. Bref, les paquets longs (plus
exactement, à en-tête long) sont plus complets, les paquets courts
(à en-tête court) plus efficaces.
Les paquets sont protégés par la cryptographie. (QUIC n'a pas de
mode en clair.) Mais attention, elle ne protège pas la totalité du
paquet. Ainsi, le connection ID est en clair
puisque c'est lui qui sera utilisé à la destination pour trouver la
bonne connexion et donc les bons paramètres cryptographiques pour
déchiffrer. (Mais il est protégé en intégrité
donc ne peut pas être modifié par un attaquant sans que ce soit
détecté.) De même, les paquets Initial
n'ont de
protection que contre la modification, pas contre l'espionnage. En
revanche, les paquets qui transportent les données
(0-RTT
et 1-RTT
) sont
complètement protégés. Les détails de ce qui est protégé et ce qui
ne l'est pas figurent dans le RFC 9001.
La coalescence de plusieurs paquets au sein d'un seul datagramme UDP vise à augmenter les performances en diminuant le nombre de datagrammes à traiter. (J'en profite pour rappeler que la métrique importante pour un chemin sur le réseau n'est pas toujours le nombre d'octets par seconde qui peuvent passer par ce chemin. Parfois, c'est le nombre de datagrammes par seconde qui compte.) Par contre, si un datagramme qui comprend plusieurs paquets, qui eux-mêmes contiennent des trames de données de ruisseaux différents, est perdu, cela va évidemment affecter tous ces ruisseaux.
Les paquets ont un numéro, calculé différemment dans chaque direction, et partant de zéro. Ce numéro est chiffré. Les réémissions d'un paquet perdu utilisent un autre numéro que celui du paquet original, ce qui permet, contrairement à TCP, de distinguer émission et réémission.
Avec QUIC, les datagrammes ne sont jamais fragmentés (en IPv4), on met le bit DF à 1 pour éviter cela. QUIC peut utiliser la PLPMTUD (RFC 8899) pour trouver la MTU du chemin.
Le format exact des paquets est spécifié en section 17. Un paquet
long (plus exactement, à en-tête long) se reconnait par son premier
bit mis à 1. Il comprend un type (la liste est dans le RFC, elle
n'est pas extensible, il n'y a pas de registre IANA), les
deux connection ID et les données, dont la
signification dépend du type. Les paquets de type
Initial
comportent entre autres dans ces
données un jeton, qui pourra servir, par exemple pour les futurs
connexions 0-RTT. Les paquets de type Handshake
contiennent des trames de type CRYPTO
, qui
indiquent les paramètres cryptographiques. Quant aux paquets courts,
leur premier bit est à 0, et ils contiennent moins d'information,
par exemple, seul le connection ID de destination
est présent, pas celui de la source.
Dans sa partie non chiffrée, le paquet a un bit qui a suscité bien des débats, le spin bit. Comme c'est un peu long à expliquer, ce bit a son propre article.
QUIC chiffre beaucoup plus de choses que TCP. Ainsi, pour les paquets à en-tête court, en dehors du connection ID et de quelques bits dont le spin bit, rien n'est exposé. Par exemple, les accusés de réception sont chiffrés et on ne peut donc pas les observer. Le but est bien de diminuer la vue offerte au réseau (RFC 8546), alors que TCP expose tout (les accusés de réception, les estampilles temporelles, etc). QUIC chiffre tellement qu'il n'existe aucun moyen fiable, en observant le trafic, de voir ce qui est du QUIC et ce qui n'en est pas. (Certaines personnes avaient réclamé, au nom de la nécessité de surveillance, que QUIC se signale explicitement .)
Les différents types de trames sont tous listés en section 19. Il y a notamment :
PADDING
qui permet de
remplir les paquets pour rendre plus
difficile la surveillance,PING
qui permet de garder une connexion
ouverte, ou de vérifier que la
machine distante répond (il n'y a pas de
PONG
, c'est l'accusé de réception de la trame
qui en tiendra lieu),ACK
, les accusés de réception, qui
indiquent les intervalles de numéros de paquets reçus,CRYPTO
, les paramètres cryptographiques
de la connexion,STREAM
, qui contiennent les données,
et créent les ruisseaux ; envoyer une trame
de type STREAM
suffit, s'il n'est pas déjà
créé, à créer le ruisseau correspondant (ils sont identifiés par
un numéro contenu dans cette trame),CONNECTION_CLOSE
, pour mettre fin à la
connexion.Les types de trame figurent dans un registre IANA. On notera que l'encodage des trames n'est pas auto-descriptif : on ne peut comprendre une trame que si on connait son type. C'est plus rapide, mais moins souple et cela veut dire que, si on introduit de nouveaux types de trame, il faudra utiliser des paramètres au moment de l'ouverture de la connexion pour être sûr que l'autre machine comprenne ce type.
Bon, les codes d'erreur, désormais (section 20 du RFC). La liste
complète est dans un
registre IANA, je ne vais pas la reprendre ici. Notons quand
même le code d'erreur NO_ERROR
qui signifie
qu'il n'y a pas eu de problème. Il est utilisé lorsqu'on ferme une
connexion sans que pour autant quelque chose de mal se soit
produit.
Si vous voulez une vision plus concrète de QUIC, vous pouvez regarder mon article d'analyse d'une connexion QUIC.
L'une des principales motivations de QUIC est la sécurité, et il est donc logique qu'il y ait une longue section 21 consacrée à l'analyse détaillée de la sécurité de QUIC. D'abord, quel est le modèle de menace ? C'est celui du RFC 3552. En deux mots : on ne fait pas confiance au réseau, tout intermédiaire entre deux machines qui communiquent peut être malveillant. Il y a trois sortes d'attaquants : les attaquants passifs (qui ne peuvent qu'écouter), les attaquants actifs situés sur le chemin (et qui peuvent donc écouter et écrire) et les attaquants actifs non situés sur le chemin, qui peuvent écrire mais en aveugle. Voyons maintenant les attaques possibles.
La poignée de mains initiale est protégée par TLS. La sécurité de QUIC dépend donc de celle de TLS.
Les attaques par réflexion, surtout dangereuses quand elles se combinent avec une amplification sont gênées, sinon complètement empêchées, par la validation des adresses IP. QUIC ne transmet pas plus de trois fois le volume de données à une adresse IP non validée. Ce point n'a pas forcément été compris par tous, et certains ont paniqué à la simple mention de l'utilisation d'UDP. C'est par exemple le cas de cet article, qui est surtout du FUD d'un vendeur.
Du fait du chiffrement, même un attaquant actif qui serait sur le chemin et pourrait donc observer les paquets, ne peut pas injecter de faux paquets ou, plus exactement, ne peut pas espérer qu'ils seront acceptés (puisque l'attaquant ne connait pas la clé de chiffrement). L'attaquant actif qui n'est pas sur le chemin, et doit donc opérer en aveugle, est évidemment encore plus impuissant. (Avec TCP, l'attaquant actif situé sur le chemin peut insérer des paquets qui seront acceptés. Des précautions décrites dans le RFC 5961 permettent à TCP de ne pas être trop vulnérable à l'attaquant aveugle.)
La possibilité de migration des connexions QUIC (changement de port et/ou d'adresse IP) apporte évidemment de nouveaux risques. La validation du chemin doit être refaite lors de ces changements, autrement, un méchant partenaire QUIC pourrait vous rediriger vers une machine innocente.
Bien sûr, les attaques par déni de service restent
possibles. Ainsi, un attaquant actif sur le chemin qui a la
possibilité de modifier les paquets peut tout simplement les
corrompre de façon à ce qu'ils soient rejetés. Mais il y a aussi des
attaques par déni de service plus subtiles. L'attaque dite
Slowloris vise ainsi à épuiser une autre
machine en ouvrant beaucoup de connexions qui ne seront pas
utilisées. Un serveur utilisant QUIC doit donc se méfier et, par
exemple, limiter le nombre de connexions par client. Le méchant
client peut aussi ouvrir, non pas un grand nombre de connexions mais
un grand nombre de ruisseaux. C'est d'autant plus facile que
d'ouvrir le ruisseau de numéro N (ce qui ne nécessite qu'une seule
trame de type STREAM
) ouvre tous les ruisseaux
jusqu'à N, dans la limite indiquée dans les paramètres de
transport.
On a vu que dans certains cas, une machine QUIC n'a plus les paramètres qui lui permettent de fermer proprement une connexion (par exemple parce qu'elle a redémarré) et doit donc utiliser la fermeture sans état (stateless reset). Dans certains cas, un attaquant peut mettre la main sur un jeton qu'il utilisera ensuite pour fermer une connexion.
Le chiffrement, comme toute technique de sécurité, a ses
limites. Ainsi, il n'empêche pas l'analyse de
trafic (reconnaitre le fichier récupéré à sa taille, par
exemple). D'où les trames de type PADDING
pour
gêner cette attaque.
QUIC a plusieurs registres à l'IANA. Si vous voulez ajouter des valeurs à ces registres, leur politique (cf. RFC 8126) est :
L'annexe A de notre RFC contient du pseudo-code pour quelques algorithmes utiles à la mise en œuvre de QUIC. Par exemple, QUIC, contrairement à la plupart des protocoles IETF, a plusieurs champs de taille variable. Les encoder et décoder efficacement nécessite des algorithmes astucieux, suggérés dans cette annexe.
Il existe d'ores et déjà de nombreuses mises en œuvre de QUIC, l'écriture de ce RFC ayant été faite en parallèle avec d'innombrables hackathons et tests d'interopérabilité. Je vous renvoie à la page du groupe de travail, qui indique également des serveurs QUIC publics. Elles sont dans des langages de programmation très différents, par exemple celle de Cloudflare, Quiche, est en Rust. À ma connaissance, toutes tournent en espace utilisateur mais ce n'est pas obligatoire, QUIC pourrait parfaitement être intégré dans le noyau du système d'exploitation. Une autre bonne source pour la liste des mises en œuvre de QUIC est le Wikipédia anglophone. Notez que le navigateur Web libre Firefox a désormais QUIC.
Quelques lectures pour aller plus loin :
draft-martini-hrpc-quichr
(dont je remercie d'ailleurs les auteurs, qui m'ont bien aidé à
comprendre QUIC).Version PDF de cette page (mais vous pouvez aussi imprimer depuis votre navigateur, il y a une feuille de style prévue pour cela)
Source XML de cette page (cette page est distribuée sous les termes de la licence GFDL)