Zum Hauptinhalt springen

8. 0-RTT und Anti-Replay (0-RTT and Anti-Replay)

Wie in Abschnitt 2.3 und Anhang E.5 erwähnt, bietet TLS keinen inhärenten Replay-Schutz für 0-RTT-Daten. Es gibt zwei potenzielle Bedrohungen:

  • Netzwerkangreifer, die einen Replay-Angriff durchführen, indem sie einfach einen Flug von 0-RTT-Daten duplizieren.

  • Netzwerkangreifer, die das Wiederholungsverhalten des Clients ausnutzen, um zu veranlassen, dass der Server mehrere Kopien einer Anwendungsnachricht erhält. Diese Bedrohung existiert bereits bis zu einem gewissen Grad, da Clients, die Robustheit schätzen, auf Netzwerkfehler reagieren, indem sie versuchen, Anfragen erneut zu senden. 0-RTT fügt jedoch eine zusätzliche Dimension für jedes Serversystem hinzu, das keinen global konsistenten Serverstatus verwaltet. Insbesondere wenn ein Serversystem mehrere Zonen hat, in denen Tickets aus Zone A in Zone B nicht akzeptiert werden, kann ein Angreifer ein ClientHello und frühe Daten, die für A bestimmt sind, sowohl an A als auch an B duplizieren. Bei A werden die Daten in 0-RTT akzeptiert, aber bei B lehnt der Server 0-RTT-Daten ab und erzwingt stattdessen einen vollständigen Handshake. Wenn der Angreifer das ServerHello von A blockiert, wird der Client den Handshake mit B abschließen und wahrscheinlich die Anfrage wiederholen, was zu einer Duplizierung im gesamten Serversystem führt.

Die erste Klasse von Angriffen kann verhindert werden, indem ein Status geteilt wird, um zu gewährleisten, dass die 0-RTT-Daten höchstens einmal akzeptiert werden. Server SOLLTEN (SHOULD) dieses Maß an Replay-Schutz bieten, indem sie eine der in diesem Abschnitt beschriebenen Methoden oder eine gleichwertige Methode implementieren. Es wird jedoch verstanden, dass aufgrund betrieblicher Bedenken nicht alle Bereitstellungen den Status auf dieser Ebene verwalten werden. Daher wissen Clients im normalen Betrieb nicht, welche dieser Mechanismen Server tatsächlich implementieren, und MÜSSEN (MUST) daher nur frühe Daten senden, die sie als sicher für ein Replay erachten.

Zusätzlich zu den direkten Auswirkungen von Replays gibt es eine Klasse von Angriffen, bei denen selbst Operationen, die normalerweise als idempotent gelten, durch eine große Anzahl von Replays ausgenutzt werden könnten (Timing-Angriffe, Erschöpfung von Ressourcenlimits und andere, wie in Anhang E.5 beschrieben). Diese können gemildert werden, indem sichergestellt wird, dass jede 0-RTT-Nutzlast nur eine begrenzte Anzahl von Malen wiedergegeben werden kann. Der Server MUSS (MUST) sicherstellen, dass jede Instanz davon (sei es eine Maschine, ein Thread oder eine andere Entität innerhalb der relevanten Serving-Infrastruktur) 0-RTT für denselben 0-RTT-Handshake höchstens einmal akzeptiert; dies begrenzt die Anzahl der Replays auf die Anzahl der Serverinstanzen in der Bereitstellung. Eine solche Garantie kann durch lokales Aufzeichnen von Daten aus kürzlich empfangenen ClientHellos und Ablehnen von Wiederholungen oder durch jede andere Methode erreicht werden, die dieselbe oder eine stärkere Garantie bietet. Die Garantie "höchstens einmal pro Serverinstanz" ist eine Mindestanforderung; Server SOLLTEN (SHOULD) 0-RTT-Replays weiter einschränken, wenn möglich.

Die zweite Klasse von Angriffen kann nicht auf der TLS-Ebene verhindert werden und MUSS (MUST) von jeder Anwendung behandelt werden. Beachten Sie, dass jede Anwendung, deren Clients eine Art von Wiederholungsverhalten implementieren, bereits eine Art Anti-Replay-Verteidigung implementieren muss.

8.1. Einmalige Tickets (Single-Use Tickets)

Die einfachste Form der Anti-Replay-Verteidigung besteht darin, dass der Server jedes Sitzungsticket nur einmal verwenden lässt. Beispielsweise kann der Server eine Datenbank aller ausstehenden gültigen Tickets verwalten und jedes Ticket aus der Datenbank löschen, sobald es verwendet wird. Wenn ein unbekanntes Ticket bereitgestellt wird, würde der Server dann auf einen vollständigen Handshake zurückfallen.

Wenn das Ticket eigenständig ist, anstatt ein Datenbankschlüssel zu sein, und der entsprechende PSK bei Verwendung gelöscht wird, genießen Verbindungen, die mit diesem PSK hergestellt wurden, Forward Secrecy. Dies verbessert die Sicherheit aller 0-RTT-Daten und PSK-Verwendung, wenn PSK ohne (EC)DHE verwendet wird.

Da dieser Mechanismus das Teilen der Sitzungsdatenbank zwischen Serverknoten in Umgebungen mit mehreren verteilten Servern erfordert, kann es schwierig sein, hohe Verfügbarkeit und Leistung für PSK-basierte 0-RTT-Verbindungen im Vergleich zu selbstverschlüsselten Tickets zu erreichen. Im Gegensatz zu Sitzungsdatenbanken können Sitzungstickets PSK-basierte Sitzungserstellung auch ohne konsistenten Speicher erfolgreich durchführen, obwohl sie immer noch konsistenten Speicher für Anti-Replay von 0-RTT-Daten benötigen, wie in den folgenden Abschnitten beschrieben.

8.2. ClientHello-Aufzeichnung (Client Hello Recording)

Eine andere Form von Anti-Replay besteht darin, einen eindeutigen Wert aufzuzeichnen, der vom ClientHello abgeleitet ist (im Allgemeinen entweder der Zufallswert oder der PSK-Binder) und Duplikate abzulehnen. Das Aufzeichnen aller ClientHellos führt dazu, dass der Status unbegrenzt wächst, aber ein Server kann stattdessen ClientHellos für ein bestimmtes Zeitfenster aufzeichnen und das obfuscated_ticket_age verwenden, um sicherzustellen, dass Tickets außerhalb dieses Fensters nicht wiederverwendet werden.

Um dies zu implementieren, überprüft der Server zunächst den PSK-Binder wie in Abschnitt 4.2.11 beschrieben, wenn ein ClientHello empfangen wird. Er berechnet dann die expected_arrival_time wie im nächsten Abschnitt beschrieben, und wenn sie außerhalb des Aufzeichnungsfensters liegt, lehnt er 0-RTT ab und fällt auf den 1-RTT-Handshake zurück.

Wenn die expected_arrival_time im Fenster liegt, überprüft der Server, ob er ein passendes ClientHello aufgezeichnet hat. Wenn eines gefunden wird, bricht er entweder den Handshake mit einem illegal_parameter-Alarm ab oder akzeptiert den PSK, lehnt aber 0-RTT ab. Wenn kein passendes ClientHello gefunden wird, akzeptiert er 0-RTT und speichert dann das ClientHello so lange, wie die expected_arrival_time im Fenster liegt. Server KÖNNEN (MAY) auch Datenspeicher mit False Positives wie Bloom-Filter implementieren. In diesem Fall MÜSSEN (MUST) sie auf scheinbare Replays reagieren, indem sie 0-RTT ablehnen, aber den Handshake NICHT abbrechen.

Der Server MUSS (MUST) den Speicherschlüssel nur aus den validierten Abschnitten des ClientHello ableiten. Wenn das ClientHello mehrere PSK-Identitäten enthält, kann ein Angreifer mehrere ClientHellos mit unterschiedlichen Binder-Werten für die weniger bevorzugte Identität erstellen, in der Annahme, dass der Server diese nicht überprüfen wird (wie in Abschnitt 4.2.11 empfohlen). Das heißt, wenn der Client PSKs A und B sendet, der Server aber A bevorzugt, kann der Angreifer den Binder für B ändern, ohne den Binder für A zu beeinflussen. Wenn der Binder für B Teil des Speicherschlüssels ist, wird dieses ClientHello nicht als Duplikat erscheinen, was dazu führt, dass das ClientHello akzeptiert wird und Nebenwirkungen wie Replay-Cache-Verschmutzung verursachen kann, obwohl 0-RTT-Daten nicht entschlüsselt werden, da sie unterschiedliche Schlüssel verwenden. Wenn der validierte Binder oder das ClientHello.random als Speicherschlüssel verwendet wird, ist dieser Angriff nicht möglich.

Da dieser Mechanismus nicht erfordert, alle ausstehenden Tickets zu speichern, kann er in verteilten Systemen mit hoher Wiederaufnahme- und 0-RTT-Rate einfacher zu implementieren sein, auf Kosten eines potenziell schwächeren Anti-Replay-Schutzes aufgrund der Schwierigkeit, die empfangenen ClientHello-Nachrichten zuverlässig zu speichern und abzurufen. In vielen solchen Systemen ist es unpraktisch, alle empfangenen ClientHellos für ein global konsistentes Speichersystem zu speichern. In diesem Fall besteht der beste Anti-Replay-Schutz darin, eine einzelne Speicherzone für ein bestimmtes Ticket als maßgeblich zu haben und 0-RTT für dieses Ticket in jeder anderen Zone abzulehnen. Dieser Ansatz verhindert einfache Replays durch den Angreifer, da nur eine Zone 0-RTT-Daten akzeptiert. Ein schwächeres Design besteht darin, separate Speicher für jede Zone zu implementieren, aber 0-RTT in jeder Zone zuzulassen. Dieser Ansatz begrenzt die Anzahl der Replays auf einmal pro Zone. Duplizierung von Anwendungsnachrichten ist natürlich mit beiden Designs möglich.

Wenn Implementierungen neu gestartet werden, SOLLTEN (SHOULD) sie 0-RTT ablehnen, solange ein Teil ihres Aufzeichnungsfensters die Startzeit überlappt. Andernfalls laufen sie Gefahr, Replays zu akzeptieren, die ursprünglich während dieser Zeit gesendet wurden.

Hinweis: Wenn die Uhr des Clients viel schneller läuft als die des Servers, kann ein ClientHello empfangen werden, das in der Zukunft außerhalb des Fensters liegt. In diesem Fall könnte es für 1-RTT akzeptiert werden, was zu einer Client-Wiederholung führt, und dann später für 0-RTT akzeptabel sein. Dies ist eine weitere Variante der zweiten Form des in Abschnitt 8 beschriebenen Angriffs.

8.3. Frischeprüfungen (Freshness Checks)

Da das ClientHello die Zeit angibt, zu der der Client es gesendet hat, ist es möglich, effizient zu bestimmen, ob ein ClientHello kürzlich möglicherweise wiedergegeben wurde, und 0-RTT nur für solche ClientHellos zu akzeptieren, andernfalls auf einen 1-RTT-Handshake zurückzufallen. Dies ist für den in Abschnitt 8.2 beschriebenen ClientHello-Speichermechanismus erforderlich, da der Server sonst eine unbegrenzte Anzahl von ClientHellos speichern müsste, und ist eine nützliche Optimierung für eigenständige Einmaltickets, da sie eine effiziente Ablehnung von ClientHellos ermöglicht, die nicht für 0-RTT verwendet werden können.

Um diesen Mechanismus zu implementieren, muss ein Server die Zeit speichern, zu der ein Sitzungsticket erstellt wurde, zusammen mit einer Schätzung des Round-Trip-Time-Offsets zwischen Client und Server. Das heißt:

adjusted_creation_time = creation_time + estimated_RTT

Dieser Wert kann im Ticket codiert werden, wodurch die Notwendigkeit vermieden wird, den Status für jedes ausstehende Ticket zu verwalten. Der Server kann die Sicht des Clients auf das Alter des Tickets bestimmen, indem er den ticket_age_add-Wert des Tickets vom obfuscated_ticket_age-Parameter in der pre_shared_key-Erweiterung des Clients subtrahiert. Der Server kann die expected_arrival_time des ClientHello wie folgt bestimmen:

expected_arrival_time = adjusted_creation_time + clients_ticket_age

Wenn ein neues ClientHello empfangen wird, wird die expected_arrival_time mit der aktuellen Serverwandzeit verglichen, und wenn sie um mehr als einen bestimmten Betrag abweichen, wird 0-RTT abgelehnt, obwohl der 1-RTT-Handshake abgeschlossen werden kann.

Es gibt mehrere potenzielle Fehlerquellen, die zu Unstimmigkeiten zwischen der expected_arrival_time und der gemessenen Zeit führen können. Variationen in den Client- und Server-Taktraten sind wahrscheinlich minimal, obwohl die absoluten Zeiten möglicherweise um große Werte abweichen. Netzwerk-Übertragungsverzögerungen sind die wahrscheinlichsten Ursachen für eine Nichtübereinstimmung bei legitimen Werten für verstrichene Zeit. Sowohl die NewSessionTicket- als auch die ClientHello-Nachrichten können erneut übertragen und daher verzögert werden, was durch TCP verborgen sein kann. Für Clients im Internet bedeutet dies Fenster in der Größenordnung von zehn Sekunden, um Fehler in Uhren und Variationen in Messungen zu berücksichtigen; andere Bereitstellungsszenarien können andere Anforderungen haben. Taktschiefe-Verteilungen sind nicht symmetrisch, sodass der optimale Kompromiss einen asymmetrischen Bereich zulässiger Nichtübereinstimmungswerte umfassen kann.

Beachten Sie, dass die Frischeprüfung allein nicht ausreicht, um Replays zu verhindern, da sie diese nicht während des Fehlerfensters erkennt, das—abhängig von Bandbreite und Systemkapazität—Milliarden von Replays in realen Einstellungen umfassen könnte. Darüber hinaus wird diese Frischeprüfung nur zum Zeitpunkt des Empfangs des ClientHello durchgeführt und nicht, wenn nachfolgende frühe Anwendungsdatensätze empfangen werden. Nachdem frühe Daten akzeptiert wurden, können Datensätze über einen längeren Zeitraum weiterhin zum Server gestreamt werden.