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 :
L’établissement d’une connexion QUIC implique des étapes similaires, mais est plus efficace. Il intègre également la validation d'adresse dans la configuration de la connexion dans le cadre de la négociation cryptographique. La validation d'adresse protège contre les attaques d'amplification du trafic, dans lesquelles un mauvais acteur envoie au serveur un paquet contenant des informations d'adresse source falsifiées pour la victime visée de l'attaque. L'attaquant espère que le serveur générera davantage de paquets ou des paquets plus volumineux pour la victime que ce qu'il peut générer lui-même, ce qui entraînera une quantité de trafic écrasante. (Pour plus de détails, voir la section 8 de la RFC 9000, QUIC : Un transport multiplexé et sécurisé basé sur UDP .)
Dans le cadre de l'établissement de la connexion, le client et le serveur fournissent des identifiants de connexion indépendants qui sont codés dans l'en-tête QUIC, fournissant une identification simple de la connexion, indépendamment de 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 un peu à la négociation TCP à trois et, surtout, établit que le client possède l’adresse IP source qu’il présente. Sans cette vérification, les serveurs QUIC comme NGINX pourraient être vulnérables à des attaques DoS faciles avec des adresses IP sources usurpées. (Un autre mécanisme QUIC qui atténue de telles attaques est l'exigence selon laquelle tous les paquets de connexion initiaux doivent être complétés à un minimum de 1 200 octets, ce qui rend leur envoi plus coûteux.)
De plus, les paquets de nouvelle tentative atténuent une attaque similaire à l'attaque par inondation TCP SYN
(où les ressources du serveur sont épuisées par un grand nombre de poignées de main ouvertes mais non terminées stockées en mémoire), en codant les détails de la connexion dans l'ID de connexion qu'il envoie au client ; cela présente l'avantage supplémentaire qu'aucune information côté serveur n'a besoin d'être conservée, car les informations de connexion peuvent être reconstituées à partir de l'ID de connexion et du jeton présentés ultérieurement par le client. Cette technique est analogue aux cookies TCP SYN
. De plus, les serveurs QUIC comme NGINX peuvent fournir un jeton expirant à utiliser dans les futures connexions du client, pour accélérer 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 contexte d'une session d'application) est susceptible de changer au cours de la session, par exemple lorsqu'un VPN ou une passerelle change son adresse publique ou qu'un utilisateur de smartphone quitte un emplacement couvert par le WiFi, ce qui force un passage à un réseau cellulaire. De plus, les administrateurs réseau ont traditionnellement défini des délais d'expiration plus courts pour le trafic UDP que pour les connexions TCP, ce qui augmente la probabilité de réassociation 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 apportées à l'adresse IP source pendant les sessions QUIC peuvent poser un problème aux équilibreurs de charge en aval (ou autres composants réseau de couche 4) qui utilisent l'adresse IP source et le port pour déterminer quel serveur en amont doit recevoir un datagramme UDP particulier. Pour garantir une gestion correcte du trafic, les fournisseurs de périphériques réseau de couche 4 devront les mettre à jour pour gérer les ID de connexion QUIC. Pour en savoir plus sur l’avenir de l’équilibrage de charge et de QUIC, consultez le projet QUIC-LB de l’IETF : Génération d’ID 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 un aperçu plus complet de la configuration de NGINX pour QUIC + HTTP/3, lisez Packages binaires désormais disponibles pour l'implémentation préliminaire de NGINX QUIC+HTTP/3 sur notre blog ou regardez notre webinaire, Familiarisez-vous avec NGINX et QUIC+HTTP/3 . Pour plus de détails sur toutes les directives NGINX pour QUIC+HTTP/3 et des instructions complètes pour l'installation de binaires pré-compilés ou la construction à partir des sources, consultez la page Web 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."