7. Sicherheitsüberlegungen (Security Considerations)
Dieser Abschnitt beschreibt potenzielle Sicherheitsbedenken mit QPACK:
-
Verwendung der Komprimierung als längenbasiertes Orakel zur Überprüfung von Vermutungen über Geheimnisse, die in einen gemeinsamen Komprimierungskontext komprimiert werden.
-
Denial-of-Service, der aus der Erschöpfung der Verarbeitungs- oder Speicherkapazität bei einem Decoder resultiert.
7.1 Sondierung des dynamischen Tabellenzustands (Probing Dynamic Table State)
QPACK reduziert die kodierte Größe von Feldabschnitten, indem es die inhärente Redundanz in Protokollen wie HTTP ausnutzt. Das ultimative Ziel hiervon ist es, die Menge der Daten zu reduzieren, die zum Senden von HTTP-Anfragen oder -Antworten erforderlich ist.
Der Komprimierungskontext, der zum Kodieren von Header- und Trailer-Feldern verwendet wird, kann von einem Angreifer sondiert werden, der sowohl zu kodierende und zu übertragende Felder definieren als auch die Länge dieser Felder nach der Kodierung beobachten kann. Wenn ein Angreifer beides tun kann, kann er Anfragen adaptiv modifizieren, um Vermutungen über den dynamischen Tabellenzustand zu bestätigen. Wenn eine Vermutung in eine kürzere Länge komprimiert wird, kann der Angreifer die kodierte Länge beobachten und darauf schließen, dass die Vermutung korrekt war.
Dies ist auch über das Transport Layer Security-Protokoll ([TLS]) und das QUIC-Transportprotokoll ([QUIC-TRANSPORT]) möglich, da TLS und QUIC zwar Vertraulichkeitsschutz für Inhalte bieten, aber nur einen begrenzten Schutz für die Länge dieses Inhalts bieten.
Hinweis: Padding-Schemata bieten nur begrenzten Schutz gegen einen Angreifer mit diesen Fähigkeiten und erzwingen möglicherweise nur eine erhöhte Anzahl von Vermutungen, um die mit einer bestimmten Vermutung verbundene Länge zu lernen. Padding-Schemata wirken auch direkt gegen die Komprimierung, indem sie die Anzahl der übertragenen Bits erhöhen.
Angriffe wie CRIME ([CRIME]) demonstrierten die Existenz dieser allgemeinen Angreiferfähigkeiten. Der spezifische Angriff nutzte die Tatsache aus, dass DEFLATE ([RFC1951]) Redundanz basierend auf Präfix-Matching entfernt. Dies ermöglichte es dem Angreifer, Vermutungen Zeichen für Zeichen zu bestätigen, wodurch ein Angriff mit exponentieller Zeit in einen Angriff mit linearer Zeit umgewandelt wurde.
7.1.1 Anwendbarkeit auf QPACK und HTTP (Applicability to QPACK and HTTP)
QPACK mildert, aber verhindert nicht vollständig, Angriffe nach dem Vorbild von CRIME ([CRIME]), indem es eine Vermutung zwingt, einer ganzen Feldzeile zu entsprechen, anstatt einzelnen Zeichen. Ein Angreifer kann nur lernen, ob eine Vermutung korrekt ist oder nicht, sodass der Angreifer auf eine Brute-Force-Vermutung für die mit einem gegebenen Feldnamen verbundenen Feldwerte reduziert wird.
Daher hängt die Machbarkeit der Wiederherstellung spezifischer Feldwerte von der Entropie der Werte ab. Infolgedessen ist es unwahrscheinlich, dass Werte mit hoher Entropie erfolgreich wiederhergestellt werden. Werte mit niedriger Entropie bleiben jedoch anfällig.
Angriffe dieser Art sind immer dann möglich, wenn zwei sich gegenseitig misstrauende Entitäten Anfragen oder Antworten kontrollieren, die auf eine einzige HTTP/3-Verbindung platziert werden. Wenn der gemeinsame QPACK-Kompressor es einer Entität ermöglicht, Einträge zur dynamischen Tabelle hinzuzufügen, und der anderen, auf diese Einträge zu verweisen, während sie gewählte Feldzeilen kodiert, kann der Angreifer (die zweite Entität) den Zustand der Tabelle lernen, indem er die Länge der kodierten Ausgabe beobachtet.
Beispielsweise können Anfragen oder Antworten von sich gegenseitig misstrauenden Entitäten auftreten, wenn ein Vermittler entweder:
-
Anfragen von mehreren Clients auf einer einzigen Verbindung zu einem Ursprungsserver sendet, oder
-
Antworten von mehreren Ursprungsservern nimmt und sie auf einer gemeinsamen Verbindung zu einem Client platziert.
Webbrowser müssen auch davon ausgehen, dass Anfragen, die auf derselben Verbindung von verschiedenen Web-Ursprüngen ([RFC6454]) gestellt werden, von sich gegenseitig misstrauenden Entitäten gestellt werden. Andere Szenarien mit sich gegenseitig misstrauenden Entitäten sind ebenfalls möglich.
7.1.2 Abhilfe (Mitigation)
Benutzer von HTTP, die Vertraulichkeit für Header- oder Trailer-Felder benötigen, können Werte mit ausreichender Entropie verwenden, um Vermutungen unmöglich zu machen. Dies ist jedoch als allgemeine Lösung unpraktisch, da es alle Benutzer von HTTP zwingt, Maßnahmen zur Abwehr von Angriffen zu ergreifen. Es würde neue Einschränkungen für die Verwendung von HTTP auferlegen.
Anstatt Benutzern von HTTP Einschränkungen aufzuerlegen, kann eine QPACK-Implementierung stattdessen einschränken, wie Komprimierung angewendet wird, um das Potenzial für das Sondieren der dynamischen Tabelle zu begrenzen.
Eine ideale Lösung trennt den Zugriff auf die dynamische Tabelle basierend auf der Entität, die die Nachricht konstruiert. Feldwerte, die zur Tabelle hinzugefügt werden, werden einer Entität zugeordnet, und nur die Entität, die einen bestimmten Wert erstellt hat, kann diesen Wert extrahieren.
Um die Komprimierungsleistung dieser Option zu verbessern, könnten bestimmte Einträge als öffentlich markiert werden. Beispielsweise könnte ein Webbrowser die Werte des Accept-Encoding-Header-Feldes in allen Anfragen verfügbar machen.
Ein Encoder ohne gute Kenntnis der Herkunft von Feldwerten könnte stattdessen eine Strafe für viele Feldzeilen mit demselben Feldnamen und unterschiedlichen Werten einführen. Diese Strafe könnte dazu führen, dass eine große Anzahl von Versuchen, einen Feldwert zu erraten, dazu führt, dass das Feld in zukünftigen Nachrichten nicht mit den dynamischen Tabelleneinträgen verglichen wird, wodurch weitere Vermutungen effektiv verhindert werden.
Diese Reaktion könnte umgekehrt proportional zur Länge des Feldwerts gemacht werden. Das Deaktivieren des Zugriffs auf die dynamische Tabelle für einen bestimmten Feldnamen könnte für kürzere Werte schneller oder mit höherer Wahrscheinlichkeit auftreten als für längere Werte.
Diese Abhilfe ist am effektivsten zwischen zwei Endpunkten. Wenn Nachrichten von einem Vermittler ohne Kenntnis darüber, welche Entität eine bestimmte Nachricht konstruiert hat, neu kodiert werden, könnte der Vermittler versehentlich Komprimierungskontexte zusammenführen, die der ursprüngliche Encoder speziell getrennt gehalten hatte.
Hinweis: Das einfache Entfernen von Einträgen, die dem Feld aus der dynamischen Tabelle entsprechen, kann ineffektiv sein, wenn der Angreifer über eine zuverlässige Möglichkeit verfügt, die Wiederinstallation von Werten zu verursachen. Beispielsweise enthält eine Anfrage zum Laden eines Bildes in einem Webbrowser typischerweise das Cookie-Header-Feld (ein potenziell sehr geschätztes Ziel für diese Art von Angriff), und Websites können leicht erzwingen, dass ein Bild geladen wird, wodurch der Eintrag in der dynamischen Tabelle aktualisiert wird.
7.1.3 Niemals indizierte Literale (Never-Indexed Literals)
Implementierungen können auch wählen, sensible Felder zu schützen, indem sie sie nicht komprimieren und stattdessen ihren Wert als Literale kodieren.
Die Weigerung, eine Feldzeile in die dynamische Tabelle einzufügen, ist nur wirksam, wenn dies auf allen Hops vermieden wird. Das niemals indizierte Literal-Bit (siehe Abschnitt 4.5.4) kann verwendet werden, um Vermittlern zu signalisieren, dass ein bestimmter Wert absichtlich als Literal gesendet wurde.
Ein Vermittler DARF NICHT einen Wert, der eine literale Darstellung mit gesetztem 'N'-Bit verwendet, mit einer anderen Darstellung, die ihn indizieren würde, neu kodieren. Wenn QPACK für die Neukodierung verwendet wird, MUSS eine literale Darstellung mit gesetztem 'N'-Bit verwendet werden. Wenn HPACK für die Neukodierung verwendet wird, MUSS die niemals indizierte literale Darstellung (siehe Abschnitt 6.2.3 von [RFC7541]) verwendet werden.
Die Wahl, zu markieren, dass ein Feldwert niemals indiziert werden sollte, hängt von mehreren Faktoren ab. Da QPACK nicht vor dem Erraten eines gesamten Feldwerts schützt, werden kurze oder Werte mit niedriger Entropie leichter von einem Gegner wiederhergestellt. Daher könnte ein Encoder wählen, Werte mit niedriger Entropie nicht zu indizieren.
Ein Encoder könnte auch wählen, Werte für Felder nicht zu indizieren, die als sehr wertvoll oder empfindlich für die Wiederherstellung gelten, wie die Cookie- oder Authorization-Header-Felder.
Im Gegenteil könnte ein Encoder bevorzugen, Werte für Felder zu indizieren, die wenig oder keinen Wert haben, wenn sie offengelegt würden. Beispielsweise variiert ein User-Agent-Header-Feld üblicherweise nicht zwischen Anfragen und wird an jeden Server gesendet. In diesem Fall bietet die Bestätigung, dass ein bestimmter User-Agent-Wert verwendet wurde, wenig Wert.
Beachten Sie, dass diese Kriterien für die Entscheidung, eine niemals indizierte literale Darstellung zu verwenden, sich im Laufe der Zeit weiterentwickeln werden, wenn neue Angriffe entdeckt werden.
7.2 Statische Huffman-Kodierung (Static Huffman Encoding)
Es gibt derzeit keinen bekannten Angriff gegen eine statische Huffman-Kodierung. Eine Studie hat gezeigt, dass die Verwendung einer statischen Huffman-Kodierungstabelle ein Informationsleck erzeugte; diese Studie kam jedoch zu dem Schluss, dass ein Angreifer dieses Informationsleck nicht nutzen konnte, um eine bedeutende Menge an Informationen wiederzugewinnen (siehe [PETAL]).
7.3 Speicherverbrauch (Memory Consumption)
Ein Angreifer kann versuchen, einen Endpunkt dazu zu bringen, seinen Speicher zu erschöpfen. QPACK ist so konzipiert, dass es sowohl die Spitzen- als auch die stabilen Mengen an Speicher begrenzt, die von einem Endpunkt zugewiesen werden.
QPACK verwendet die Definition der maximalen Größe der dynamischen Tabelle und der maximalen Anzahl blockierter Streams, um die Menge an Speicher zu begrenzen, die der Encoder den Decoder verbrauchen lassen kann. In HTTP/3 werden diese Werte vom Decoder über die Parameter SETTINGS_QPACK_MAX_TABLE_CAPACITY bzw. SETTINGS_QPACK_BLOCKED_STREAMS gesteuert (siehe Abschnitt 3.2.3 und Abschnitt 2.1.2). Die Begrenzung der Größe der dynamischen Tabelle berücksichtigt die Größe der in der dynamischen Tabelle gespeicherten Daten plus eine kleine Zulage für Overhead. Die Begrenzung der Anzahl blockierter Streams ist nur ein Proxy für die maximale Speichermenge, die vom Decoder benötigt wird. Die tatsächliche maximale Speichermenge hängt davon ab, wie viel Speicher der Decoder verwendet, um jeden blockierten Stream zu verfolgen.
Ein Decoder kann die Menge an Zustandsspeicher begrenzen, die für die dynamische Tabelle verwendet wird, indem er einen geeigneten Wert für die maximale Größe der dynamischen Tabelle festlegt. In HTTP/3 wird dies durch Festlegen eines geeigneten Werts für den SETTINGS_QPACK_MAX_TABLE_CAPACITY-Parameter erreicht. Ein Encoder kann die Menge an Zustandsspeicher begrenzen, die er verwendet, indem er eine kleinere dynamische Tabellengröße wählt, als der Decoder zulässt, und dies dem Decoder signalisiert (siehe Abschnitt 4.3.1).
Ein Decoder kann die Menge an Zustandsspeicher begrenzen, die für blockierte Streams verwendet wird, indem er einen geeigneten Wert für die maximale Anzahl blockierter Streams festlegt. In HTTP/3 wird dies durch Festlegen eines geeigneten Werts für den SETTINGS_QPACK_BLOCKED_STREAMS-Parameter erreicht. Streams, die blockiert werden könnten, verbrauchen keinen zusätzlichen Zustandsspeicher beim Encoder.
Ein Encoder weist Speicher zu, um alle dynamischen Tabellenreferenzen in nicht bestätigten Feldabschnitten zu verfolgen. Eine Implementierung kann die Menge an Zustandsspeicher direkt begrenzen, indem sie nur so viele Verweise auf die dynamische Tabelle verwendet, wie sie verfolgen möchte; keine Signalisierung zum Decoder ist erforderlich. Das Begrenzen von Verweisen auf die dynamische Tabelle verringert jedoch die Komprimierungseffektivität.
Die Menge an temporärem Speicher, die von einem Encoder oder Decoder verbraucht wird, kann durch sequenzielle Verarbeitung von Feldzeilen begrenzt werden. Eine Decoder-Implementierung muss keine vollständige Liste von Feldzeilen beibehalten, während ein Feldabschnitt dekodiert wird. Eine Encoder-Implementierung muss keine vollständige Liste von Feldzeilen beibehalten, während ein Feldabschnitt kodiert wird, wenn sie einen Single-Pass-Algorithmus verwendet. Beachten Sie, dass es für eine Anwendung aus anderen Gründen notwendig sein könnte, eine vollständige Liste von Feldzeilen beizubehalten; selbst wenn QPACK dies nicht erzwingt, können Anwendungseinschränkungen dies notwendig machen.
Während die ausgehandelte Grenze für die Größe der dynamischen Tabelle einen Großteil des Speichers ausmacht, der von einer QPACK-Implementierung verbraucht werden kann, sind Daten, die aufgrund der Flusskontrolle nicht sofort gesendet werden können, von dieser Grenze nicht betroffen. Implementierungen sollten die Größe nicht gesendeter Daten begrenzen, insbesondere auf dem Decoder-Stream, wo die Flexibilität zur Auswahl dessen, was gesendet werden soll, begrenzt ist. Mögliche Reaktionen auf einen Überschuss an nicht gesendeten Daten könnten die Begrenzung der Fähigkeit des Peers, neue Streams zu öffnen, das ausschließliche Lesen vom Encoder-Stream oder das Schließen der Verbindung umfassen.
7.4 Implementierungsgrenzen (Implementation Limits)
Eine QPACK-Implementierung muss sicherstellen, dass große Werte für Ganzzahlen, lange Kodierung für Ganzzahlen oder lange Zeichenfolgenliterale keine Sicherheitsschwächen erzeugen.
Eine Implementierung muss eine Grenze für die Werte festlegen, die sie für Ganzzahlen akzeptiert, sowie für die kodierte Länge; siehe Abschnitt 4.1.1. Ebenso muss sie eine Grenze für die Länge festlegen, die sie für Zeichenfolgenliterale akzeptiert; siehe Abschnitt 4.1.2. Diese Grenzen SOLLTEN groß genug sein, um das größte einzelne Feld zu verarbeiten, das die HTTP-Implementierung akzeptieren kann.
Wenn eine Implementierung auf einen Wert trifft, der größer ist, als sie dekodieren kann, MUSS dies als Stream-Fehler vom Typ QPACK_DECOMPRESSION_FAILED behandelt werden, wenn es sich auf einem Anfrage-Stream befindet, oder als Verbindungsfehler des entsprechenden Typs, wenn es sich auf dem Encoder- oder Decoder-Stream befindet.