Vor unseren Augen beginnt ein neuer Meilenstein in der Internetgeschichte: Wir können davon ausgehen, dass HTTP / 3 bereits angekündigt wurde. Ende Oktober schlug Mark Nottingham von der IETF
vor, bereits einen Namen für das neue Protokoll festzulegen, über das die IETF seit 2015 baut. Anstelle von QUIC-ähnlichen Namen erschien also lautes HTTP / 3. Westliche Publikationen haben bereits und
mehr als einmal darüber geschrieben . Die Geschichte von QUIC begann 2012 im Herzen der Good Corporation. Seitdem unterstützten nur die Server von Google HTTP-over-QUIC-Verbindungen. Die Zeit vergeht jedoch und Facebook hat bereits begonnen, diese Technologie zu implementieren (7. November,
Facebook und
LiteSpeed haben die erste Interaktion über HTTP / 3 durchgeführt ); Derzeit beträgt der Anteil der Websites, die QUIC unterstützen, 1,2%. Schließlich befasst sich die WebRTC-Arbeitsgruppe
auch mit QUIC (siehe auch die
QUIC-API ), sodass in absehbarer Zukunft Echtzeit-Video / Audio über QUIC anstelle von RTP / RTCP übertragen wird. Aus diesem Grund haben wir beschlossen, dass es großartig wäre, die Details des IETF QUIC zu enthüllen: Speziell für Habr haben wir eine Übersetzung des Longread Dotting i vorbereitet. Viel Spaß!
QUIC (Quick UDP Internet Connections) ist ein neues, verschlüsseltes Standardprotokoll für die Transportschicht, das viele HTTP-Verbesserungen aufweist: sowohl zur Beschleunigung des Datenverkehrs als auch zur Erhöhung der Sicherheit. QUIC hat auch ein langfristiges Ziel - TCP und TLS zu ersetzen. In diesem Artikel werden sowohl die wichtigsten QUIC-Chips als auch die Gründe, warum das Web davon profitieren wird, sowie die Probleme bei der Unterstützung dieses völlig neuen Protokolls untersucht.
Tatsächlich gibt es zwei Protokolle mit demselben Namen: Google QUIC (gQUIC), das ursprüngliche Protokoll, das vor einigen Jahren von Google-Ingenieuren entwickelt wurde und nach einer Reihe von Experimenten von der Internet Engineering Task Force (IETF) zur Standardisierung übernommen wurde.
IETF QUIC (im Folgenden einfach QUIC) weist bereits so starke Unterschiede zu gQUIC auf, dass es als separates Protokoll betrachtet werden kann. Vom Paketformat über Handshake bis hin zur HTTP-Zuordnung hat QUIC die ursprüngliche gQUIC-Architektur durch die Zusammenarbeit mit vielen Organisationen und Entwicklern verbessert, die ein gemeinsames Ziel verfolgen: das Internet schneller und sicherer zu machen.
Welche Verbesserungen bietet QUIC?
Integrierte Sicherheit (und Leistung)
Einer der auffälligsten Unterschiede zwischen QUIC und ehrwürdigem TCP ist das ursprünglich festgelegte Ziel, ein
standardmäßig sicheres Transportprotokoll zu sein. QUIC erreicht dies durch die Verwendung von Authentifizierung und Verschlüsselung, die normalerweise auf einer höheren Ebene (z. B. in TLS) und nicht im Transportprotokoll selbst erfolgt.
Der ursprüngliche QUIC-Handshake kombiniert die übliche Drei-Wege-Kommunikation über TCP mit dem TLS 1.3-Handshake, der die Authentifizierung der Teilnehmer sowie die Koordination der kryptografischen Parameter ermöglicht. Für diejenigen, die mit TLS vertraut sind: QUIC ersetzt die TLS-Aufnahmeebene durch ein eigenes Frame-Format, verwendet jedoch gleichzeitig TLS-Handshakes.
Dies ermöglicht nicht nur, dass die Verbindung immer verschlüsselt und authentifiziert wird, sondern auch schneller, um die anfängliche Verbindung herzustellen: Ein gewöhnlicher QUIC-Handshake führt den Austausch zwischen Client und Server in einem Durchgang durch, während TCP + TLS 1.3 zwei Durchgänge durchführt.
QUIC geht jedoch noch weiter und verschlüsselt auch Verbindungsmetadaten, die von Dritten leicht kompromittiert werden können. Beispielsweise können Angreifer Paketnummern verwenden, um Benutzer über mehrere Netzwerkpfade zu leiten, wenn die Verbindungsmigration verwendet wird (siehe unten). QUIC verschlüsselt Paketnummern, sodass sie nur von den tatsächlichen Teilnehmern der Verbindung korrigiert werden können.
Die Verschlüsselung kann auch gegen „Stagnation“ wirksam sein - ein Phänomen, bei dem die Flexibilität des Protokolls aufgrund falscher Annahmen in Implementierungen (Ossifikation - in der Praxis nicht genutzt werden kann). Aus diesem Grund wurde
TLS 1.3 lange Zeit entwickelt . Wir haben es erst nach
einigen Änderungen veröffentlicht unerwünschte Blockierungen für neue TLS-Revisionen verhindern).
Blockieren des Warteschlangenanfangs (Head-of-Line-Blockieren)
Eine der wichtigsten Verbesserungen, die
HTTP / 2 uns gebracht hat, ist die Möglichkeit, verschiedene HTTP-Anforderungen in einer TCP-Verbindung zu kombinieren. Dadurch können HTTP / 2-Anwendungen Anforderungen parallel verarbeiten und den Netzwerkkanal besser nutzen.
Dies war natürlich ein bedeutender Schritt nach vorne. Weil frühere Anwendungen viele TCP + TLS-Verbindungen initiieren mussten, wenn sie mehrere HTTP-Anforderungen gleichzeitig verarbeiten wollten (z. B. wenn der Browser sowohl CSS als auch JavaScript zum Rendern der Seite empfangen muss). Das Erstellen neuer Verbindungen erfordert mehrere Handshakes sowie das Initialisieren des Überlastungsfensters. Dies bedeutet, dass das Rendern der Seite verlangsamt wird. Kombinierte HTTP-Anforderungen vermeiden dies.
Es gibt jedoch einen Nachteil: Da mehrere Anforderungen / Antworten über dieselbe TCP-Verbindung übertragen werden, sind sie alle gleichermaßen vom Paketverlust abhängig, selbst wenn die verlorenen Daten nur eine der Anforderungen betreffen. Dies wird als "Blockieren des Beginns der Warteschlange" bezeichnet.
QUIC geht tiefer und bietet erstklassige Unterstützung für das Kombinieren von Anforderungen. Beispielsweise können verschiedene HTTP-Anforderungen als unterschiedliche Transport-QUIC-Anforderungen angesehen werden. Gleichzeitig verwenden sie jedoch alle dieselbe QUIC-Verbindung. Das heißt, zusätzliche Handshakes sind nicht erforderlich, es gibt eine Überlastungsstatus: QUIC-Anforderungen werden unabhängig zugestellt. In den meisten Fällen betrifft der Paketverlust daher nur eine Anforderung.
So ist es möglich, die Zeit beispielsweise für das vollständige Rendern einer Webseite (CSS, JavaScript, Bilder und andere Ressourcen) erheblich zu verkürzen, insbesondere bei einem überlasteten Netzwerk mit hohem Paketverlust.
So einfach, oder?
Um sein Versprechen zu erfüllen, muss das QUIC-Protokoll einige der Annahmen überwinden, die viele Netzwerkanwendungen für selbstverständlich gehalten haben. Dies kann die Implementierung und Implementierung von QUIC erschweren.
QUIC kann über UDP-Datagramme bereitgestellt werden, um die Entwicklung zu erleichtern und Probleme mit Netzwerkgeräten zu vermeiden, die Pakete unbekannter Protokolle verwerfen (da die meisten Geräte UDP unterstützen). Außerdem kann QUIC im Benutzerbereich leben, sodass Browser beispielsweise neue Protokollfunktionen implementieren und an Endbenutzer weitergeben können, ohne auf Betriebssystemaktualisierungen warten zu müssen.
Das gute Ziel, Netzwerkprobleme zu reduzieren, macht es jedoch schwieriger, Pakete zu schützen und ordnungsgemäß weiterzuleiten.
Ein NAT, um alle zusammen zu kommen und sich mit einem einzigen schwarzen Willen zu vereinen
In der Regel arbeiten NAT-Router mit TCP-Verbindungen, indem sie ein Tupel von 4 Werten (Quell-IP und -Port plus IP- und Zielport) verwenden und über das Netzwerk übertragene TCP-SYN-, ACK- und FIN-Pakete überwachen. Router können bestimmen, wann eine neue Verbindung hergestellt und wann sie beendet wird. Daher ist eine präzise Verwaltung von NAT-Bindungen (Kommunikation zwischen internen und externen IP-Adressen und Ports) möglich.
Bei QUIC ist dies noch nicht möglich, weil Moderne NAT-Router kennen QUIC noch nicht, daher werden sie normalerweise auf die standardmäßige und weniger genaue UDP-Verarbeitung heruntergestuft.
Dies bedeutet
Zeitüberschreitungen von beliebiger (manchmal kurzer) Dauer , die sich auf langfristige Verbindungen auswirken können.
Wenn eine erneute Bindung auftritt (z. B. aufgrund eines Timeouts), beginnt das Gerät außerhalb des NAT-Perimeters mit dem Empfang von Paketen von einer anderen Quelle, wodurch es unmöglich wird, die Verbindung nur mit einem Tupel von 4 Werten aufrechtzuerhalten.
Und es ist nicht nur NAT! Eine QUIC-Funktion wird als Verbindungsmigration bezeichnet und ermöglicht es Geräten, nach eigenem Ermessen Verbindungen zu anderen IP-Adressen / Pfaden zu übertragen. Beispielsweise kann ein mobiler Client eine QUIC-Verbindung von einem Mobilfunknetz zu einem bereits bekannten WiFi-Netzwerk übertragen (der Benutzer hat ein Lieblingscafé betreten usw.).
QUIC versucht, dieses Problem mit dem Konzept der Verbindungs-ID zu lösen: Eine Information beliebiger Länge, die in QUIC-Paketen übertragen wird und die Identifizierung der Verbindung ermöglicht. Endpoint-Geräte können diese ID verwenden, um ihre Verbindungen zu verfolgen, ohne sich mit dem Tupel abzustimmen. In der Praxis sollten viele IDs vorhanden sein, die dieselbe Verbindung angeben, um beispielsweise zu vermeiden, dass bei der Migration der Verbindung unterschiedliche Pfade verbunden werden, da der gesamte Prozess nur von den Endgeräten und nicht von den Middleboxen gesteuert wird.
Es kann jedoch ein Problem für Telekommunikationsbetreiber geben, die Anycast- und ECMP-Routing verwenden, bei dem eine IP möglicherweise Hunderte oder Tausende von Servern identifizieren kann. Da die Grenzrouter in diesen Netzwerken noch nicht wissen, wie sie mit QUIC-Verkehr umgehen sollen, kann es vorkommen, dass UDP-Pakete von derselben QUIC-Verbindung, jedoch mit unterschiedlichen Tupeln, an unterschiedliche Server gesendet werden, was eine Trennung bedeutet.
Um dies zu vermeiden, müssen Bediener möglicherweise einen intelligenteren Level-Balancer implementieren. Dies kann programmgesteuert erreicht werden, ohne die Grenzrouter selbst zu beeinträchtigen (siehe beispielsweise das
Katran- Projekt von Facebook).
Qpack
Eine weitere nützliche Funktion von HTTP / 2 war die
Header-Komprimierung (HPACK) , mit der Endgeräte die Größe der gesendeten Daten reduzieren können, indem unnötige Anforderungen und Antworten verworfen werden.
Insbesondere verwendet HPACK unter anderem dynamische Tabellen mit Headern, die bereits von früheren HTTP-Anforderungen / -Antworten gesendet / empfangen wurden, sodass Geräte neue Anforderungen / Antworten auf zuvor angetroffene Header verweisen können (anstatt sie erneut zu senden). .
HPACK-Tabellen müssen zwischen dem Codierer (der Partei, die die Anforderung / Antwort sendet) und dem Decodierer (der empfangenden Seite) synchronisiert werden, andernfalls kann der Decodierer einfach nicht dekodieren, was er empfängt.
Bei HTTP / 2 über TCP ist diese Synchronisation transparent, da die Transportschicht (TCP) Anforderungen / Antworten in derselben Reihenfolge liefert, in der sie gesendet wurden. Das heißt, Sie können Anweisungen an den Decoder senden, um die Tabellen in einer einfachen Anforderung / Antwort zu aktualisieren. Aber mit QUIC sind die Dinge viel komplizierter.
QUIC kann mehrere HTTP-Anfragen / -Antworten gleichzeitig in verschiedene Richtungen liefern, was bedeutet, dass QUIC den Lieferauftrag in eine Richtung garantiert, während es bei mehreren Richtungen keine solche Garantie gibt.
Wenn ein Client beispielsweise eine HTTP-Anforderung A in QUIC-Stream A sowie eine Anforderung B in Stream B sendet, empfängt der Server aufgrund von Paketpermutation oder Netzwerkverlusten Anforderung B vor Anforderung A. Und wenn Anforderung B als codiert wurde wurde im Header von Anfrage A angegeben, dann kann der Server Anfrage B einfach nicht dekodieren, da er Anfrage A noch nicht gesehen hat.
Das gQUIC-Protokoll löste dieses Problem, indem einfach alle Header (aber nicht die Körper) der HTTP-Anforderungen / -Antworten innerhalb eines einzelnen gQUIC-Streams
sequentiell gemacht wurden. Dadurch wurde sichergestellt, dass alle Header in der richtigen Reihenfolge angezeigt werden, unabhängig davon, was passiert. Dies ist ein sehr einfaches Schema. Mit seiner Hilfe können vorhandene Lösungen weiterhin Code verwenden, der unter HTTP / 2 geschärft wurde. Dies erhöht andererseits die Wahrscheinlichkeit, den Beginn der Warteschlange zu blockieren, was durch QUIC verringert werden soll. Daher entwickelte die IETF QUIC-Arbeitsgruppe eine neue Zuordnung zwischen HTTP und QUIC (HTTP / QUIC) sowie ein neues Prinzip der Header-Komprimierung, QPACK.
Im endgültigen Entwurf der HTTP / QUIC- und QPACK-Spezifikationen verwendet jeder HTTP-Anforderungs- / Antwortaustausch seinen eigenen bidirektionalen QUIC-Fluss, sodass der Start der Warteschlange nicht blockiert wird. Um QPACK zu unterstützen, erstellt jeder Teilnehmer zwei zusätzliche, unidirektionale QUIC-Streams, von denen einer Tabellenaktualisierungen sendet und der andere den Empfang bestätigt. Somit kann der QPACK-Codierer die Verknüpfung zur dynamischen Tabelle erst verwenden, nachdem der Decodierer seinen Empfang bestätigt hat.
Reflexion brechen
Ein häufiges Problem bei UDP-basierten Protokollen ist ihre Anfälligkeit für Reflexionsangriffe, wenn der Angreifer einen Server zwingt, eine große Datenmenge an das Opfer zu senden. Der Angreifer fälscht seine IP, sodass der Server denkt, dass die Datenanforderung von der Adresse des Opfers stammt.
Diese Art von Angriff kann sehr effektiv sein, wenn die Serverantwort unvergleichlich größer als die Anforderung ist. In diesem Fall sprechen sie von "Gewinn".
TCP wird normalerweise nicht für solche Angriffe verwendet, da die Pakete im ursprünglichen Handshake (SYN, SYN + ACK, ...) dieselbe Länge haben und daher kein Potenzial für eine "Verstärkung" haben.
Andererseits ist der QUIC-Handshake sehr asymmetrisch: Wie bei TLS sendet der QUIC-Server zunächst seine Zertifikatkette, die sehr groß sein kann, obwohl der Client nur wenige Bytes senden sollte (eine Nachricht vom ClientHello-TLS-Client ist in das QUIC-Paket integriert ) Aus diesem Grund muss das ursprüngliche QUIC-Paket auf eine bestimmte Mindestlänge erhöht werden, auch wenn der Inhalt des Pakets viel kleiner ist. Wie dem auch sei, diese Maßnahme ist immer noch nicht sehr effektiv, da eine typische Serverantwort mehrere Pakete enthält und daher mehr als ein erweitertes Client-Paket sein kann.
Das QUIC-Protokoll definiert auch einen expliziten Quellverifizierungsmechanismus: Anstatt eine große Antwort zu geben, sendet der Server nur ein Wiederholungspaket mit einem eindeutigen Token, das der Client dann in einem neuen Paket an den Server sendet. Der Server hat also mehr Vertrauen, dass der Client keine Ersatz-IP-Adresse hat und Sie den Handshake beenden können. Abzüglich der Entscheidung - die Zeit des Handshakes erhöht sich, statt eines Durchgangs sind bereits zwei erforderlich.
Eine alternative Lösung besteht darin, die Serverantwort auf eine Größe zu reduzieren, bei der der Reflexionsangriff weniger effektiv ist - beispielsweise mithilfe von
ECDSA-Zertifikaten (normalerweise sind sie viel kleiner als RSA). Wir haben auch mit einem
TLS-Zertifikat-Komprimierungsmechanismus experimentiert, der handelsübliche Komprimierungsalgorithmen wie zlib und brotli verwendet. Dies ist eine Funktion, die zuerst in gQUIC angezeigt wurde, derzeit jedoch in TLS nicht unterstützt wird.
UDP-Leistung
Eines der ständigen Probleme von QUIC ist die vorhandene Hardware und Software, die nicht mit QUIC arbeiten kann. Wir haben bereits untersucht, wie QUIC versucht, mit Netzwerk-Middleboxen wie Routern umzugehen. Ein weiterer potenziell problematischer Bereich ist die Leistung beim Senden / Empfangen von Daten zwischen QUIC-Geräten über UDP. Seit vielen Jahren werden Anstrengungen unternommen, um TCP-Implementierungen so weit wie möglich zu optimieren, einschließlich integrierter Offload-Funktionen in Software (z. B. Betriebssystemen) und Hardware (Netzwerkschnittstellen), aber nichts davon betrifft UDP.
Es ist jedoch nur eine Frage der Zeit, bis QUIC-Implementierungen diese Verbesserungen und Vorteile übertreffen. Werfen Sie einen Blick auf die jüngsten Bemühungen,
UDP-Offloading unter Linux zu implementieren, mit dem Anwendungen mehrere UDP-Segmente zwischen dem User-Space- und dem Kernel-Space-Netzwerkstapel kombinieren und übertragen können, und zwar auf Kosten von etwa einem Segment. Ein weiteres Beispiel ist die
Nullkopie- Unterstützung
für Sockets unter Linux , dank derer Anwendungen die Kosten für das Kopieren von User-Space-Speicher in den Kernel-Space vermeiden könnten.
Fazit
Wie HTTP / 2 und TLS 1.3 sollte das QUIC-Protokoll eine Menge neuer Funktionen bieten, die die Leistung und Sicherheit sowohl von Websites als auch von anderen Teilnehmern der Internetinfrastruktur verbessern. Die IETF-Arbeitsgruppe beabsichtigt, die erste Version der QUIC-Spezifikationen bis Ende des Jahres herauszubringen. Daher ist es an der Zeit, darüber nachzudenken, wie wir die Vorteile von QUIC optimal nutzen können.