Die erste Erwähnung von QUIC und HTTP/3 im NGINX-Blog erfolgte vor vier Jahren (!), und wie Sie sehen wir nun der bevorstehenden Eingliederung unserer QUIC-Implementierung in den Open Source-Hauptzweig von NGINX mit Spannung entgegen. Angesichts der langen Entstehungszeit ist es verständlich, wenn Sie sich darüber nicht viele Gedanken gemacht haben.
An diesem Punkt müssen Sie sich als Entwickler oder Site-Administrator jedoch darüber im Klaren sein, wie QUIC die Verantwortung für einige Netzwerkdetails vom Betriebssystem auf NGINX (und alle HTTP-Apps) verlagert. Auch wenn Netzwerke nicht Ihr Ding sind, bedeutet die Einführung von QUIC, dass die Sorge um das Netzwerk nun (zumindest ein wenig) Teil Ihrer Arbeit ist.
In diesem Beitrag gehen wir auf die wichtigsten Netzwerk- und Verschlüsselungskonzepte ein, die in QUIC verwendet werden. Dabei vereinfachen wir einige Details und lassen im Interesse der Klarheit nicht wesentliche Informationen weg. Zwar gehen dabei möglicherweise einige Nuancen verloren, doch unsere Absicht besteht darin, Ihnen genügend Informationen zur Verfügung zu stellen, damit Sie QUIC effektiv in Ihrer Umgebung einführen können, oder Ihnen zumindest eine Grundlage zu bieten, auf der Sie Ihr Wissen aufbauen können.
Wenn QUIC für Sie völlig neu ist, empfehlen wir Ihnen, zunächst einen unserer früheren Beiträge zu lesen und unser Übersichtsvideo anzusehen.
Für eine ausführlichere und umfassendere Erläuterung von QUIC empfehlen wir das hervorragende Dokument „Handhabbarkeit des QUIC-Transportprotokolls“ der IETC QUIC-Arbeitsgruppe sowie die in diesem Dokument verlinkten Zusatzmaterialien.
Die schmutzigen Details der Netzwerkverbindung zwischen Clients und NGINX waren für die meisten Benutzer bisher nicht besonders relevant. Schließlich kümmert sich bei HTTP/1. x und HTTP/2 das Betriebssystem um die Einrichtung der Transmission Control Protocol (TCP)-Verbindung zwischen Clients und NGINX. NGINX verwendet die Verbindung einfach, sobald sie hergestellt ist.
Mit QUIC verlagert sich die Verantwortung für die Verbindungserstellung, -validierung und -verwaltung jedoch vom zugrunde liegenden Betriebssystem auf NGINX. Anstatt eine etablierte TCP-Verbindung zu empfangen, erhält NGINX jetzt einen Stream von User Datagram Protocol (UDP)-Datagrammen, den es in Clientverbindungen und Streams analysieren muss. NGINX ist jetzt auch für die Behandlung von Paketverlusten, Verbindungsneustarts und Überlastungskontrolle verantwortlich.
Darüber hinaus kombiniert QUIC Verbindungsinitiierung, Versionsverhandlung und Austausch von Verschlüsselungsschlüsseln in einem einzigen Verbindungsaufbauvorgang. Und obwohl die TLS-Verschlüsselung sowohl für QUIC+HTTP/3 als auch für TCP+HTTP/1+2 weitgehend ähnlich gehandhabt wird, gibt es Unterschiede, die für nachgelagerte Geräte wie Layer-4-Load Balancer, Firewalls und Sicherheitsgeräte von Bedeutung sein können.
Letztendlich sorgen diese Änderungen insgesamt für ein sichereres, schnelleres und zuverlässigeres Benutzererlebnis, wobei sich an der Konfiguration oder den Vorgängen von NGINX nur sehr wenig ändern muss. NGINX-Administratoren müssen allerdings zumindest ein wenig darüber wissen, was bei QUIC und NGINX vor sich geht, und sei es nur, um im Problemfall ihre mittlere Zeit bis zur Unschuld so kurz wie möglich zu halten.
(Es ist erwähnenswert, dass sich dieser Beitrag zwar auf HTTP-Operationen konzentriert, da HTTP/3 QUIC erfordert, QUIC jedoch auch für andere Protokolle verwendet werden kann. Ein gutes Beispiel ist DNS über QUIC, wie in RFC 9250 ( DNS über dedizierte QUIC-Verbindungen ) definiert.)
Nachdem wir diese Einführung hinter uns haben, wollen wir uns nun mit einigen Besonderheiten der QUIC-Netzwerktechnik befassen.
QUIC führt eine wesentliche Änderung am zugrunde liegenden Netzwerkprotokoll ein, das zur Übertragung von HTTP-Anwendungsdaten zwischen einem Client und einem Server verwendet wird.
Wie erwähnt war TCP schon immer das Protokoll zum Übertragen von HTTP-Webanwendungsdaten. TCP ist für die zuverlässige Datenübertragung über ein IP-Netzwerk konzipiert. Es verfügt über einen klar definierten und verständlichen Mechanismus zum Herstellen von Verbindungen und Bestätigen des Datenempfangs sowie über verschiedene Algorithmen und Verfahren zum Verwalten von Paketverlusten und Verzögerungen, die in unzuverlässigen und überlasteten Netzwerken häufig auftreten.
TCP bietet zwar einen zuverlässigen Transport, es müssen jedoch Kompromisse bei Leistung und Latenz eingegangen werden. Darüber hinaus ist die Datenverschlüsselung nicht in TCP integriert und muss separat implementiert werden. Außerdem war es angesichts der sich ändernden HTTP-Verkehrsmuster schwierig, TCP zu verbessern oder zu erweitern. Da die TCP-Verarbeitung im Linux-Kernel erfolgt, müssen alle Änderungen sorgfältig geplant und getestet werden, um unerwartete Auswirkungen auf die Gesamtleistung und Stabilität des Systems zu vermeiden.
Ein weiteres Problem besteht darin, dass der HTTP-Verkehr zwischen Client und Server in vielen Szenarien über mehrere TCP-Verarbeitungsgeräte wie Firewalls oder Load Balancer (gemeinsam als „Middleboxes“ bezeichnet) läuft, die Änderungen an TCP-Standards möglicherweise nur langsam implementieren.
QUIC verwendet stattdessen UDP als Transportprotokoll. UDP ist wie TCP für die Datenübertragung über ein IP-Netzwerk konzipiert, verzichtet jedoch absichtlich auf den Verbindungsaufbau und die zuverlässige Übermittlung. Dieser fehlende Overhead macht UDP für viele Anwendungen geeignet, bei denen Effizienz und Geschwindigkeit wichtiger sind als Zuverlässigkeit.
Für die meisten Webanwendungen ist jedoch eine zuverlässige Datenübermittlung von entscheidender Bedeutung. Da die zugrunde liegende UDP-Transportschicht keine zuverlässige Datenübertragung bietet, müssen diese Funktionen von QUIC (oder der Anwendung selbst) bereitgestellt werden. Glücklicherweise hat QUIC in dieser Hinsicht einige Vorteile gegenüber TCP:
QUIC- Streams sind die logischen Objekte, die HTTP/3-Anfragen oder -Antworten (oder andere Anwendungsdaten) enthalten. Für die Übertragung zwischen Netzwerkendpunkten werden sie, wie im Diagramm dargestellt, in mehrere logische Schichten eingebunden.
Von außen nach innen betrachtet sind die logischen Ebenen und Objekte:
QUIC-Header – Enthält Metadaten zum Paket. Es gibt zwei Arten von Headern:
Der bekannte Drei-Wege-Handshake SYN
/ SYN-ACK
/ ACK
stellt eine TCP-Verbindung her:
Das Herstellen einer QUIC-Verbindung umfasst ähnliche Schritte, ist jedoch effizienter. Außerdem wird als Teil des kryptografischen Handshakes eine Adressvalidierung in den Verbindungsaufbau integriert. Die Adressvalidierung dient dem Schutz vor Traffic-Amplification-Angriffen, bei denen ein böswilliger Akteur dem Server ein Paket mit gefälschten Quelladressinformationen für das beabsichtigte Angriffsopfer sendet. Der Angreifer hofft, dass der Server mehr oder größere Pakete an das Opfer sendet, als der Angreifer selbst erzeugen kann, was zu einem überwältigenden Datenverkehr führt. (Weitere Einzelheiten finden Sie in Abschnitt 8 von RFC 9000, QUIC: Ein auf UDP basierender multiplexierter und sicherer Transport .)
Beim Verbindungsaufbau stellen Client und Server unabhängige Verbindungs-IDs bereit, die im QUIC-Header codiert sind und eine einfache Identifizierung der Verbindung unabhängig von der Quell-IP-Adresse des Clients ermöglichen.
Da der anfängliche Aufbau einer QUIC-Verbindung jedoch auch Vorgänge zum Austausch von TLS-Verschlüsselungsschlüsseln umfasst, ist dieser für den Server rechenintensiver als die einfache SYN-ACK
-Antwort, die er beim Aufbau einer TCP-Verbindung generiert. Darüber hinaus wird ein potenzieller Vektor für Distributed -Denial-of-Service-Angriffe (DDoS) geschaffen, da die Client-IP-Adresse vor dem Schlüsselaustausch nicht validiert wird.
Sie können NGINX jedoch so konfigurieren, dass die Client-IP-Adresse validiert wird, bevor komplexe kryptografische Vorgänge beginnen, indem Sie die Direktive quic_retry
auf on
setzen. In diesem Fall sendet NGINX dem Client ein Wiederholungspaket mit einem Token, das der Client in Verbindungsaufbaupakete aufnehmen muss.
Dieser Mechanismus ähnelt in gewisser Weise dem Drei-Wege-TCP-Handshake und stellt vor allem sicher, dass der Client Eigentümer der von ihm präsentierten Quell-IP-Adresse ist. Ohne diese Prüfung könnten QUIC-Server wie NGINX anfällig für einfache DoS-Angriffe mit gefälschten Quell-IP-Adressen sein. (Ein weiterer QUIC-Mechanismus zur Abschwächung solcher Angriffe ist die Anforderung, dass alle anfänglichen Verbindungspakete auf mindestens 1.200 Bytes aufgefüllt werden müssen, was ihr Senden zu einer kostspieligeren Operation macht.)
Darüber hinaus mildern Wiederholungspakete einen Angriff ab, der dem TCP- SYN
-Flood-Angriff ähnelt (bei dem die Serverressourcen durch eine große Anzahl geöffneter, aber nicht abgeschlossener Handshakes im Speicher erschöpft sind), indem sie Verbindungsdetails in der Verbindungs-ID kodieren, die sie an den Client senden. Dies hat den weiteren Vorteil, dass keine serverseitigen Informationen aufbewahrt werden müssen, da die Verbindungsinformationen aus der Verbindungs-ID und dem Token wiederhergestellt werden können, die anschließend vom Client vorgelegt werden. Diese Technik ist analog zu TCP- SYN
-Cookies. Darüber hinaus können QUIC-Server wie NGINX ein ablaufendes Token bereitstellen, das bei zukünftigen Verbindungen vom Client verwendet werden kann, um die Wiederherstellung der Verbindung zu beschleunigen.
Durch die Verwendung von Verbindungs-IDs wird die Verbindung unabhängig von der zugrunde liegenden Transportschicht, sodass Änderungen im Netzwerk nicht zwangsläufig zu Verbindungsabbrüchen führen müssen. Dies wird unter „Regelmäßiges Verwalten von Client-IP-Adressänderungen“ erläutert.
Wenn eine Verbindung hergestellt ist (und die Verschlüsselung aktiviert ist, wie weiter unten beschrieben), können HTTP-Anfragen und -Antworten zwischen dem Client und NGINX hin- und herfließen. UDP-Datagramme werden gesendet und empfangen. Es gibt jedoch viele Faktoren, die dazu führen können, dass einige dieser Datagramme verloren gehen oder verzögert werden.
TCP verfügt über komplexe Mechanismen zur Bestätigung der Paketzustellung, zur Erkennung von Paketverlusten oder -verzögerungen und zur Verwaltung der erneuten Übertragung verlorener Pakete, sodass Daten in der richtigen Reihenfolge und vollständig an die Anwendungsschicht übermittelt werden. UDP verfügt nicht über diese Funktion, daher werden Überlastungskontrolle und Verlusterkennung in der QUIC-Schicht implementiert.
Wenn ein Paket mit Frames, die eine zuverlässige Zustellung erfordern, nach einer festgelegten Zeitüberschreitung nicht bestätigt wurde, gilt es als verloren.
Die Timeout-Zeiträume variieren je nach Paketinhalt. Beispielsweise ist das Timeout für Pakete kürzer, die zum Einrichten der Verschlüsselung und Herstellen der Verbindung benötigt werden, da sie für die Leistung des QUIC-Handshakes unerlässlich sind.
Eine vollständige Beschreibung der Verlusterkennung geht über den Rahmen dieser Einführung hinaus. Einzelheiten zu den Mechanismen zur Bestimmung von Zeitüberschreitungen und zur Menge der zulässigen unbestätigten Datenübertragung finden Sie in RFC 9002 ( QUIC Loss Detection and Congestion Control) .
Die IP-Adresse eines Clients (im Kontext einer Anwendungssitzung als Quell-IP-Adresse bezeichnet) kann sich während der Sitzung ändern, beispielsweise wenn ein VPN oder Gateway seine öffentliche Adresse ändert oder ein Smartphone-Benutzer einen Standort mit WLAN-Abdeckung verlässt, was einen Wechsel zu einem Mobilfunknetz erzwingt. Außerdem haben Netzwerkadministratoren traditionell niedrigere Timeouts für UDP-Verkehr als für TCP-Verbindungen festgelegt, was zu einer erhöhten Wahrscheinlichkeit einer erneuten Bindung der Netzwerkadressübersetzung (Network Address Translation , NAT) führt.
QUIC bietet zwei Mechanismen, um die dadurch entstehenden Störungen zu reduzieren: Ein Client kann den Server proaktiv darüber informieren, dass sich seine Adresse ändern wird, und Server können eine ungeplante Änderung der Adresse des Clients problemlos verarbeiten. Da die Verbindungs-ID während des Übergangs konsistent bleibt, können nicht bestätigte Frames an die neue IP-Adresse erneut übertragen werden.
Änderungen an der Quell-IP-Adresse während QUIC-Sitzungen können ein Problem für nachgelagerte Load Balancer (oder andere Layer-4-Netzwerkkomponenten) darstellen, die Quell-IP-Adresse und Port verwenden, um zu bestimmen, welcher Upstream-Server ein bestimmtes UDP-Datagramm empfangen soll. Um ein korrektes Verkehrsmanagement zu gewährleisten, müssen Anbieter von Layer-4-Netzwerkgeräten diese aktualisieren, um QUIC-Verbindungs-IDs verarbeiten zu können. Weitere Informationen zur Zukunft des Lastenausgleichs und von QUIC finden Sie im IETF-Entwurf QUIC-LB: Generieren von routingfähigen QUIC-Verbindungs-IDs .
Unter „Verbindungsaufbau“ haben wir darauf hingewiesen, dass der anfängliche QUIC-Handshake mehr bewirkt, als einfach nur eine Verbindung herzustellen. Anders als beim TLS-Handshake für TCP erfolgt bei UDP der Austausch von Schlüsseln und TLS 1.3-Verschlüsselungsparametern im Rahmen der ersten Verbindung. Diese Funktion entfernt mehrere Austauschvorgänge und ermöglicht eine Roundtrip-Zeit von null (0-RTT), wenn der Client eine vorherige Verbindung fortsetzt.
QUIC integriert nicht nur den Verschlüsselungs-Handshake in den Verbindungsaufbau, sondern verschlüsselt auch einen größeren Teil der Metadaten als TCP+TLS. Schon vor dem Schlüsselaustausch werden die ersten Verbindungspakete verschlüsselt; ein Lauscher kann die Schlüssel zwar trotzdem ableiten, allerdings ist der Aufwand größer als bei unverschlüsselten Paketen. Dadurch werden Daten wie der Server Name Indicator (SNI) besser geschützt, der sowohl für Angreifer als auch für potenzielle Zensoren auf staatlicher Ebene relevant ist. Abbildung 5 veranschaulicht, wie QUIC potenziell sensiblere Metadaten (in Rot) verschlüsselt als TCP+TLS.
Alle Daten in der QUIC-Nutzlast werden mit TLS 1.3 verschlüsselt. Dies bietet zwei Vorteile: Ältere, anfällige Verschlüsselungssammlungen und Hashing-Algorithmen sind nicht zulässig und Mechanismen zum Schlüsselaustausch mit Forward Secrecy (FS) sind obligatorisch. Durch Vorwärtsgeheimnis wird verhindert, dass ein Angreifer die Daten entschlüsselt, selbst wenn er den privaten Schlüssel und eine Kopie des Datenverkehrs erbeutet.
Durch die Reduzierung der Anzahl der Roundtrips, die zwischen einem Client und einem Server stattfinden müssen, bevor Anwendungsdaten übertragen werden können, wird die Leistung von Anwendungen verbessert, insbesondere in Netzwerken mit höherer Latenz.
TLS 1.3 führte einen einzigen Roundtrip zum Herstellen einer verschlüsselten Verbindung und null Roundtrips zum Fortsetzen einer Verbindung ein. Bei TCP bedeutet dies jedoch, dass der Handshake vor dem TLS-Client-Hello erfolgen muss.
Da QUIC kryptografische Operationen mit dem Verbindungsaufbau kombiniert, ermöglicht es eine echte 0-RTT-Verbindungswiederherstellung, bei der ein Client eine Anfrage im allerersten QUIC-Paket senden kann. Dadurch wird die Latenzzeit verringert, da der anfängliche Roundtrip zum Verbindungsaufbau vor der ersten Anforderung entfällt.
In diesem Fall sendet der Client eine HTTP-Anfrage, die mit den Parametern einer vorherigen Verbindung verschlüsselt ist und zur Adressvalidierung ein Token einschließt, das vom Server während der vorherigen Verbindung bereitgestellt wurde.
Leider bietet die 0-RTT-Verbindungswiederaufnahme keine Vorwärtsgeheimnis, sodass die ursprüngliche Clientanforderung nicht so sicher verschlüsselt ist wie anderer Datenverkehr im Austausch. Anfragen und Antworten nach der ersten Anfrage sind durch Forward Secrecy geschützt. Möglicherweise noch problematischer ist, dass die ursprüngliche Anfrage auch für Replay-Angriffe anfällig ist, bei denen ein Angreifer die ursprüngliche Anfrage abfangen und sie mehrmals an den Server zurückspielen kann.
Bei vielen Anwendungen und Websites überwiegt die Leistungsverbesserung durch die Wiederherstellung der Verbindung mit 0‑RTT diese potenziellen Schwachstellen, aber das ist eine Entscheidung, die Sie selbst treffen müssen.
Diese Funktion ist in NGINX standardmäßig deaktiviert. Um sie zu aktivieren, setzen Sie die Direktive ssl_early_data
auf on
.
Alt-Svc
-HeaderFast alle Clients (insbesondere Browser) stellen erste Verbindungen über TCP/TLS her. Wenn ein Server QUIC+HTTP/3 unterstützt, signalisiert er dies dem Client, indem er eine HTTP/1.1-Antwort zurückgibt, die den h3-
Parameter im Alt-Svc
-Header enthält. Der Client entscheidet dann, ob er QUIC+HTTP/3 verwenden oder bei einer früheren Version von HTTP bleiben möchte. (Interessanterweise ist der in RFC 7838 definierte Alt-Svc
-Header älter als QUIC und kann auch für andere Zwecke verwendet werden.)
Alt-Svc
-Header verwendet wird, um eine Verbindung von HTTP/1.1 nach HTTP/3 zu konvertierenDer Alt-Svc
-Header teilt einem Client mit, dass derselbe Dienst auf einem anderen Host, Protokoll oder Port (oder einer Kombination davon) verfügbar ist. Darüber hinaus kann den Kunden mitgeteilt werden, wie lange mit der Bereitstellung dieses Dienstes gerechnet werden kann.
Einige Beispiele:
Alt-Svc: h3=":443" |
HTTP/3 ist auf diesem Server auf Port 443 verfügbar |
Alt-Svc: h3="new.example.com:8443" |
HTTP/3 ist auf dem Server new.example.com auf Port 8443 verfügbar. |
Alt-Svc: h3=":8443"; ma=600 |
HTTP/3 ist auf diesem Server auf Port 8443 verfügbar und wird für mindestens 10 Minuten verfügbar sein. |
Obwohl es nicht zwingend erforderlich ist, sind Server in den meisten Fällen so konfiguriert, dass sie auf QUIC-Verbindungen auf demselben Port wie TCP+TLS antworten.
Um NGINX so zu konfigurieren, dass der Alt-Svc
-Header eingeschlossen wird, verwenden Sie die Direktive add_header
. In diesem Beispiel bedeutet die Variable $server_port
, dass NGINX QUIC-Verbindungen auf dem Port akzeptiert, an den der Client seine TCP+TLS-Anforderung gesendet hat, und 86.400 sind 24 Stunden:
add_header Alt-Svc 'h3=":$server_port"; ma=86400';
Dieser Blog bietet eine vereinfachte Einführung in QUIC und verschafft Ihnen hoffentlich einen ausreichenden Überblick, um die wichtigsten Netzwerk- und Verschlüsselungsvorgänge zu verstehen, die mit QUIC verwendet werden.
Um einen umfassenderen Einblick in die Konfiguration von NGINX für QUIC + HTTP/3 zu erhalten, lesen Sie „Binärpakete jetzt für die Vorschau der NGINX QUIC+HTTP/3-Implementierung verfügbar“ auf unserem Blog oder sehen Sie sich unser Webinar „Erste praktische Erfahrungen mit NGINX und QUIC+HTTP/3“ an . Einzelheiten zu allen NGINX-Direktiven für QUIC+HTTP/3 und vollständige Anweisungen zur Installation vorgefertigter Binärdateien oder zum Erstellen aus dem Quellcode finden Sie auf der NGINX QUIC-Webseite .
„Dieser Blogbeitrag kann auf Produkte verweisen, die nicht mehr verfügbar und/oder nicht mehr unterstützt werden. Die aktuellsten Informationen zu verfügbaren F5 NGINX-Produkten und -Lösungen finden Sie in unserer NGINX-Produktfamilie . NGINX ist jetzt Teil von F5. Alle vorherigen NGINX.com-Links werden auf ähnliche NGINX-Inhalte auf F5.com umgeleitet."