La première mention de QUIC et HTTP/3 sur le blog NGINX remonte à quatre ans (!), et comme vous, nous attendons maintenant avec impatience la fusion imminente de notre implémentation QUIC dans la branche principale Open Source de NGINX. Étant donné la longue gestation, il est compréhensible que vous n'y ayez pas beaucoup réfléchi.
À ce stade, cependant, en tant que développeur ou administrateur de site, vous devez savoir comment QUIC transfère la responsabilité de certains détails de réseau du système d'exploitation à NGINX (et à toutes les applications HTTP). Même si le réseautage n’est pas votre truc, adopter QUIC signifie que vous soucier du réseau fait désormais (au moins un peu) partie de votre travail.
Dans cet article, nous examinons les principaux concepts de mise en réseau et de cryptage utilisés dans QUIC, en simplifiant certains détails et en omettant les informations non essentielles dans un souci de clarté. Bien que certaines nuances puissent être perdues dans le processus, notre intention est de vous fournir suffisamment d’informations pour que vous puissiez adopter efficacement QUIC dans votre environnement, ou au moins une base sur laquelle construire vos connaissances.
Si QUIC est entièrement nouveau pour vous, nous vous recommandons de lire d’abord l’un de nos articles précédents et de regarder notre vidéo de présentation.
Pour une explication plus détaillée et complète de QUIC, nous recommandons l'excellent document Manageability of the QUIC Transport Protocol du groupe de travail IETC QUIC, ainsi que les documents supplémentaires liés tout au long de ce document.
Les détails sordides de la connexion réseau entre les clients et NGINX n’ont pas été particulièrement pertinents pour la plupart des utilisateurs jusqu’à présent. Après tout, avec HTTP/1. x et HTTP/2, le système d'exploitation se charge de configurer la connexion TCP (Transmission Control Protocol) entre les clients et NGINX. NGINX utilise simplement la connexion une fois qu'elle est établie.
Avec QUIC, la responsabilité de la création, de la validation et de la gestion des connexions est transférée du système d'exploitation sous-jacent à NGINX. Au lieu de recevoir une connexion TCP établie, NGINX reçoit désormais un flux de datagrammes UDP (User Datagram Protocol), qu'il doit analyser en connexions et flux client. NGINX est désormais également responsable de la gestion de la perte de paquets, du redémarrage des connexions et du contrôle de la congestion.
De plus, QUIC combine l’initiation de connexion, la négociation de version et l’échange de clés de chiffrement en une seule opération d’établissement de connexion. Et bien que le chiffrement TLS soit géré de manière globalement similaire pour QUIC+HTTP/3 et TCP+HTTP/1+2, il existe des différences qui peuvent être importantes pour les périphériques en aval tels que les équilibreurs de charge de couche 4, les pare-feu et les dispositifs de sécurité.
En fin de compte, l’effet global de ces changements est une expérience plus sûre, plus rapide et plus fiable pour les utilisateurs, avec très peu de changements dans la configuration ou les opérations de NGINX. Les administrateurs NGINX doivent cependant comprendre au moins un peu ce qui se passe avec QUIC et NGINX, ne serait-ce que pour garder leur temps moyen d'innocence aussi court que possible en cas de problèmes.
(Il convient de noter que même si cet article se concentre sur les opérations HTTP car HTTP/3 nécessite QUIC, QUIC peut également être utilisé pour d'autres protocoles. Un bon exemple est DNS sur QUIC, tel que défini dans la RFC 9250 , DNS sur connexions QUIC dédiées .)
Maintenant que nous avons fait cette introduction, plongeons dans quelques spécificités du réseau QUIC.
QUIC introduit un changement important dans le protocole réseau sous-jacent utilisé pour transmettre les données d'application HTTP entre un client et un serveur.
Comme mentionné, TCP a toujours été le protocole de transmission des données d’application Web HTTP. TCP est conçu pour fournir des données de manière fiable sur un réseau IP. Il dispose d’un mécanisme bien défini et bien compris pour établir des connexions et accuser réception des données, ainsi que d’une variété d’algorithmes et de techniques pour gérer la perte de paquets et les retards qui sont courants sur les réseaux peu fiables et encombrés.
Bien que TCP fournisse un transport fiable, il existe des compromis en termes de performances et de latence. De plus, le cryptage des données n’est pas intégré à TCP et doit être implémenté séparément. Il a également été difficile d’améliorer ou d’étendre TCP face à l’évolution des modèles de trafic HTTP. Le traitement TCP étant effectué dans le noyau Linux, toute modification doit être conçue et testée avec soin pour éviter des effets imprévus sur les performances et la stabilité globales du système.
Un autre problème est que, dans de nombreux scénarios, le trafic HTTP entre le client et le serveur passe par plusieurs périphériques de traitement TCP, tels que des pare-feu ou des équilibreurs de charge (collectivement appelés « middleboxes »), qui peuvent être lents à mettre en œuvre les modifications des normes TCP.
QUIC utilise plutôt UDP comme protocole de transport. UDP est conçu pour transmettre des données sur un réseau IP comme TCP, mais il supprime intentionnellement l'établissement de connexion et la livraison fiable. Ce manque de surcharge rend UDP adapté à de nombreuses applications où l’efficacité et la vitesse sont plus importantes que la fiabilité.
Cependant, pour la plupart des applications Web, une livraison fiable des données est essentielle. Étant donné que la couche de transport UDP sous-jacente ne fournit pas une livraison de données fiable, ces fonctions doivent être fournies par QUIC (ou l'application elle-même). Heureusement, QUIC présente quelques avantages par rapport à TCP à cet égard :
Les flux QUIC sont les objets logiques contenant des requêtes ou des réponses HTTP/3 (ou toute autre donnée d'application). Pour la transmission entre les points de terminaison du réseau, ils sont enveloppés dans plusieurs couches logiques comme illustré dans le diagramme.
En partant de l'extérieur vers l'intérieur, les couches logiques et les objets sont :
En-tête QUIC – Contient des métadonnées sur le paquet. Il existe deux types d'en-tête :
La procédure de négociation à trois voies SYN
/ SYN-ACK
/ ACK
bien connue établit une connexion TCP :
Établir une connexion QUIC suit des étapes similaires, mais avec plus d’efficacité. Nous intégrons aussi la validation d’adresse dans la mise en place de la connexion, via la négociation cryptographique. La validation d’adresse protège contre les attaques d’amplification, où un acteur malveillant envoie au serveur un paquet avec une fausse adresse source correspondant à la cible de l’attaque. L’attaquant compte sur le fait que le serveur génère pour la victime plus de paquets, ou des paquets plus volumineux, que lui-même ne peut en produire, inondant ainsi la cible de trafic. (Pour plus de détails, consultez la section 8 de la RFC 9000, QUIC : Un transport multiplexé et sécurisé basé sur UDP.)
Lorsqu’ils établissent la connexion, vous et le serveur fournissez chacun un identifiant indépendant, codé dans l’en-tête QUIC, permettant d’identifier facilement la connexion, quelle que soit l’adresse IP source du client.
Cependant, comme l'établissement initial d'une connexion QUIC inclut également des opérations d'échange de clés de chiffrement TLS, elle est plus coûteuse en termes de calcul pour le serveur que la simple réponse SYN-ACK
qu'elle génère lors de l'établissement d'une connexion TCP. Cela crée également un vecteur potentiel pour les attaques par déni de service distribué (DDoS) , car l’adresse IP du client n’est pas validée avant que les opérations d’échange de clés n’aient lieu.
Mais vous pouvez configurer NGINX pour valider l'adresse IP du client avant le début des opérations cryptographiques complexes, en définissant la directive quic_retry
sur on
. Dans ce cas, NGINX envoie au client un paquet de nouvelle tentative contenant un jeton, que le client doit inclure dans les paquets de configuration de connexion.
Ce mécanisme ressemble à la négociation TCP en trois temps et garantit surtout que vous détenez bien l’adresse IP source que vous signalez. Sans cette vérification, les serveurs QUIC comme NGINX risquent d’être ciblés par des attaques DoS faciles utilisant des adresses IP source falsifiées. (Un autre dispositif QUIC pour limiter ces attaques impose que tous les paquets de connexion initiaux soient complétés à au moins 1200 octets, rendant leur envoi plus coûteux.)
De plus, les paquets de nouvelle tentative limitent une attaque similaire à l'inondation TCP SYN
(qui épuise les ressources du serveur à cause d’un grand nombre de poignées de main ouvertes mais inachevées en mémoire) en encodant les détails de la connexion dans l’identifiant de connexion envoyé au client ; cela présente aussi l’avantage de ne pas conserver d’information côté serveur, puisque les données de connexion se reconstituent à partir de l’identifiant et du jeton fournis ensuite par le client. Cette technique s’apparente aux cookies TCP SYN
. Par ailleurs, les serveurs QUIC comme NGINX peuvent fournir un jeton temporaire valable pour les futures connexions client, ce qui accélère la reprise de la connexion.
L'utilisation d'ID de connexion permet à la connexion d'être indépendante de la couche de transport sous-jacente, de sorte que les modifications du réseau ne doivent pas entraîner la rupture des connexions. Ceci est abordé dans Gestion élégante des modifications d'adresse IP du client .
Une fois la connexion établie (et le chiffrement activé, comme expliqué plus loin ), les requêtes et réponses HTTP peuvent circuler entre le client et NGINX. Les datagrammes UDP sont envoyés et reçus. Cependant, de nombreux facteurs peuvent entraîner la perte ou le retard de certains de ces datagrammes.
TCP dispose de mécanismes complexes pour accuser réception de la livraison des paquets, détecter la perte ou le retard des paquets et gérer la retransmission des paquets perdus, en fournissant des données correctement séquencées et complètes à la couche application. UDP ne dispose pas de cette fonctionnalité et, par conséquent, le contrôle de congestion et la détection des pertes sont implémentés dans la couche QUIC.
Lorsqu'un paquet contenant des trames nécessitant une livraison fiable n'a pas été reconnu après un délai d'attente défini, il est considéré comme perdu.
Les délais d’expiration varient en fonction du contenu du paquet. Par exemple, le délai d’expiration est plus court pour les paquets nécessaires à l’établissement du chiffrement et à la configuration de la connexion, car ils sont essentiels aux performances de la négociation QUIC.
Une description complète de la détection des pertes dépasse le cadre de ce guide. Consultez la RFC 9002 , QUIC Loss Detection and Congestion Control , pour plus de détails sur les mécanismes de détermination des délais d'attente et sur la quantité de données non reconnues autorisées à transiter.
L’adresse IP d’un client (appelée adresse IP source dans le cadre d’une session applicative) peut changer pendant la session, par exemple lorsqu’un VPN ou une passerelle modifie son adresse publique, ou lorsqu’un utilisateur de smartphone quitte une zone couverte par un réseau sans fil, ce qui le fait basculer sur un réseau cellulaire. Par ailleurs, les administrateurs réseau fixent traditionnellement des délais d’expiration plus courts pour le trafic UDP que pour les connexions TCP, ce qui augmente la probabilité de reliaison de la traduction d’adresses réseau (NAT).
QUIC fournit deux mécanismes pour réduire les perturbations qui peuvent en résulter : un client peut informer de manière proactive le serveur que son adresse va changer, et les serveurs peuvent gérer avec élégance un changement imprévu de l’adresse du client. Étant donné que l’ID de connexion reste cohérent tout au long de la transition, les trames non reconnues peuvent être retransmises à la nouvelle adresse IP.
Les modifications de l'adresse IP source lors des sessions QUIC peuvent poser problème aux équilibreurs de charge en aval (ou autres composants réseau de couche 4) qui s'appuient sur l'adresse IP source et le port pour déterminer quel serveur en amont doit recevoir un datagramme UDP donné. Pour assurer une gestion optimale du trafic, les fournisseurs de dispositifs réseau de couche 4 doivent les mettre à jour afin de gérer les identifiants de connexion QUIC. Pour en savoir plus sur l'avenir de l’équilibrage de charge avec QUIC, consultez le projet de l'IETF QUIC‑LB : Génération d’identifiants de connexion QUIC routables.
Dans Établissement de connexion , nous avons fait allusion au fait que la poignée de main QUIC initiale fait plus que simplement établir une connexion. Contrairement à la négociation TLS pour TCP, avec UDP, l'échange de clés et de paramètres de chiffrement TLS 1.3 se produit dans le cadre de la connexion initiale. Cette fonctionnalité supprime plusieurs échanges et permet un temps d’aller-retour nul (0-RTT) lorsque le client reprend une connexion précédente.
En plus d'intégrer la négociation de chiffrement dans le processus d'établissement de la connexion, QUIC crypte une plus grande partie des métadonnées que TCP+TLS. Même avant l’échange de clés, les paquets de connexion initiaux sont chiffrés ; même si un espion peut toujours obtenir les clés, cela demande plus d’efforts qu’avec des paquets non chiffrés. Cela protège mieux les données telles que l’indicateur de nom de serveur (SNI), qui est pertinent à la fois pour les attaquants et les censeurs potentiels au niveau de l’État. La figure 5 illustre comment QUIC crypte davantage de métadonnées potentiellement sensibles (en rouge) que TCP+TLS.
Toutes les données de la charge utile QUIC sont cryptées à l'aide de TLS 1.3. Il y a deux avantages : les suites de chiffrement et les algorithmes de hachage plus anciens et vulnérables ne sont pas autorisés et les mécanismes d’échange de clés de confidentialité de transmission (FS) sont obligatoires. La confidentialité persistante empêche un attaquant de déchiffrer les données même s’il capture la clé privée et une copie du trafic.
La réduction du nombre d’allers-retours qui doivent se produire entre un client et un serveur avant que les données d’application puissent être transmises améliore les performances des applications, en particulier sur les réseaux avec une latence plus élevée.
TLS 1.3 a introduit un seul aller-retour pour établir une connexion chiffrée et aucun aller-retour pour reprendre une connexion, mais avec TCP, cela signifie que la poignée de main doit se produire avant le TLS Client Hello.
Étant donné que QUIC combine des opérations cryptographiques avec la configuration de connexion, il fournit un véritable rétablissement de connexion 0-RTT, où un client peut envoyer une demande dans le tout premier paquet QUIC. Cela réduit la latence en éliminant l’aller-retour initial pour l’établissement de la connexion avant la première demande.
Dans ce cas, le client envoie une requête HTTP chiffrée avec les paramètres utilisés lors d'une connexion précédente et, à des fins de validation d'adresse, inclut un jeton fourni par le serveur lors de la connexion précédente.
Malheureusement, la reprise de connexion 0-RTT ne fournit pas de confidentialité de transfert, de sorte que la demande initiale du client n'est pas chiffrée de manière aussi sécurisée que les autres trafics de l'échange. Les demandes et réponses au-delà de la première demande sont protégées par la confidentialité persistante. Ce qui est peut-être plus problématique, c'est que la requête initiale est également vulnérable aux attaques par relecture , où un attaquant peut capturer la requête initiale et la rejouer plusieurs fois au serveur.
Pour de nombreuses applications et sites Web, l’amélioration des performances grâce à la reprise de la connexion 0-RTT l’emporte sur ces vulnérabilités potentielles, mais c’est une décision que vous devez prendre vous-même.
Cette fonctionnalité est désactivée par défaut dans NGINX. Pour l'activer, définissez la directive ssl_early_data
sur on
.
Alt-Svc
Presque tous les clients (les navigateurs en particulier) établissent des connexions initiales via TCP/TLS. Si un serveur prend en charge QUIC+HTTP/3, il signale ce fait au client en renvoyant une réponse HTTP/1.1 qui inclut le paramètre h3
dans l'en-tête Alt-Svc
. Le client choisit ensuite d’utiliser QUIC+HTTP/3 ou de s’en tenir à une version antérieure de HTTP. (À titre d’information, l’en-tête Alt-Svc
, défini dans la RFC 7838 , est antérieur à QUIC et peut également être utilisé à d’autres fins.)
Alt-Svc
est utilisé pour convertir une connexion de HTTP/1.1 à HTTP/3L'en-tête Alt-Svc
indique au client que le même service est disponible sur un autre hôte, protocole ou port (ou une combinaison de ceux-ci). De plus, les clients peuvent être informés de la durée pendant laquelle il est possible de supposer que ce service continuera à être disponible.
Quelques exemples :
Alt-Svc : h3 = ":443" |
HTTP/3 est disponible sur ce serveur sur le port 443 |
Alt-Svc : h3="new.example.com:8443" |
HTTP/3 est disponible sur le serveur new.example.com sur le port 8443 |
Alt-Svc : h3 = ":8443"; ma=600 |
HTTP/3 est disponible sur ce serveur sur le port 8443 et sera disponible pendant au moins 10 minutes |
Bien que cela ne soit pas obligatoire, dans la plupart des cas, les serveurs sont configurés pour répondre aux connexions QUIC sur le même port que TCP+TLS.
Pour configurer NGINX afin d'inclure l'en-tête Alt-Svc
, utilisez la directive add_header
. Dans cet exemple, la variable $server_port
signifie que NGINX accepte les connexions QUIC sur le port auquel le client a envoyé sa requête TCP+TLS, et 86 400 correspond à 24 heures :
add_header Alt-Svc 'h3=":$server_port"; ma=86400' ;
Ce blog fournit une introduction simplifiée à QUIC et vous donne, espérons-le, un aperçu suffisant pour comprendre les opérations clés de mise en réseau et de cryptage utilisées avec QUIC.
Pour une présentation détaillée de la configuration de NGINX avec QUIC + HTTP/3, lisez Packages binaires désormais disponibles pour la version preview de l'implémentation NGINX QUIC+HTTP/3 sur notre blog ou regardez notre webinaire, Prenez en main NGINX et QUIC+HTTP/3. Pour connaître toutes les directives NGINX pour QUIC+HTTP/3 et suivre les instructions complètes afin d’installer les binaires précompilés ou de construire à partir du code source, consultez la page NGINX QUIC.
« Cet article de blog peut faire référence à des produits qui ne sont plus disponibles et/ou qui ne sont plus pris en charge. Pour obtenir les informations les plus récentes sur les produits et solutions F5 NGINX disponibles, explorez notre famille de produits NGINX . NGINX fait désormais partie de F5. Tous les liens NGINX.com précédents redirigeront vers un contenu NGINX similaire sur F5.com."