TLS 1.3 0-RTT: miért nem elég csak a GET-et engedni?

A TLS 1.3 0-RTT gyorsíthatja a visszatérő látogató első kérését, de cserébe megismételhetővé teszi. Ezért önmagában az sem elég, ha csak GET kéréseket engedünk át.

A TLS 1.3 0-RTT módja egy hálózati kört takaríthat meg a visszatérő látogatóknál. A kliens már a kézfogás befejezése előtt elküldheti az első HTTP-kérést, így távoli régióból vagy mobilhálózaton hamarabb érkezhet meg a válasz.

A gyorsításnak azonban ára van: a korán elküldött kérés megismételhető. Nem elég tehát annyit mondani, hogy 0-RTT-ben csak GET kéréseket engedünk át. A döntést endpointonként kell meghozni, mert nem minden GET mellékhatásmentes, és nem minden ismétlés olcsó.

TLS 1.3 0-RTT kapcsolat: a kliens korai HTTP-kérése két edge szerver felé ismétlődhet

Mitől lesz gyorsabb?

Egy új TLS-kapcsolatnál a kliens először elküldi a ClientHello üzenetet, majd megvárja a szerver válaszát. Alkalmazási adatot csak ezután küld. A TLS 1.3 early data egy korábbi kapcsolat során kapott session ticketre támaszkodik: a kliens az első HTTP-kérést már a ClientHello mellé oda tudja tenni.

Ezért a 0-RTT nem az első látogatást gyorsítja. Csak akkor használható, ha a kliens korábban már járt a szervernél, és még van érvényes ticketje. A névben szereplő nulla sem a kézfogás hiányát jelenti. Arra utal, hogy az első alkalmazási adat elküldéséhez nem kell megvárni egy teljes hálózati fordulót.

A szerver ettől még elutasíthatja az early datát. Ilyenkor a kliens a rendes kézfogás után újraküldi a kérést. Már ez a szabályos működés is megmutatja, hogy a 0-RTT-hez csak olyan művelet illik, amely biztonságosan ismételhető.

A titkosítás megmarad, az egyszeriség nem

Az early data kulcsa egy korábbi kapcsolatból származó titokra épül. Mivel a kliens még nem kapott friss, kapcsolatspecifikus adatot a szervertől, a TLS 1.3 nem ad kapcsolatközi replay-garanciát. Egy támadó rögzítheti a titkosított korai adatot, majd egy másik kapcsolaton újra elküldheti.

A kérés tartalma ettől nem válik olvashatóvá, és észrevétlenül sem írható át. A veszély más: a szerver ugyanazt a műveletet többször hajthatja végre.

Elosztott rendszerben nehéz teljesen kizárni ezt. Két edge szervernek közösen kellene, erősen konzisztens módon nyilvántartania, hogy melyik korai adatot látta már. Ez lehetséges, de állapotot, koordinációt és késleltetést visz abba az útvonalba, amelyet éppen gyorsítani próbálunk. A TLS-specifikáció ezért a kliens és az alkalmazási protokoll felelősségévé is teszi, hogy csak replaytűrő adat kerüljön 0-RTT-be.

Miért nem elég csak a GET-et engedni?

Az HTTP early data szabályai alapértelmezésként megengedik a safe metódusokat, az unsafe vagy ismeretlen biztonságú metódusokat viszont tiltják. Ez jó kiindulópont, de nem helyettesíti az endpoint ismeretét.

  • Egy GET /unsubscribe?token=… rosszul tervezett, mégis létező útvonal. Megismételve újra állapotot módosít.
  • Egy GET /download/report nem feltétlenül ír adatot, de minden hívás elindíthat egy drága lekérdezést vagy exportot.
  • Az olvasottsági, audit- vagy rate-limit-számlálót növelő GET üzleti értelemben szintén mellékhatással jár.

A safe és az idempotens ráadásul nem ugyanazt jelenti. A safe metódus olvasási szándékot fejez ki. Az idempotens művelet többszöri végrehajtása ugyanarra a kívánt állapotra vezet. Egy drága, egyébként idempotens lekérdezés ismétlése még mindig alkalmas lehet erőforrás-kimerítésre.

Az Early-Data fejléc és a 425 válasz

Az origin gyakran nem látja a kliens TLS-kézfogását, mert CDN vagy reverse proxy terminálja előtte a kapcsolatot. Az Early-Data: 1 fejléc ezért továbbadja, hogy a kérés egy korábbi hopon early dataként érkezett.

Ha az origin nem vállalja az ismétlés kockázatát, 425 Too Early választ küldhet. A kliens ezután a befejezett TLS-kapcsolaton próbálkozik újra; a megismételt kérés már nem mehet early dataként. A 425-ös válasz alapértelmezés szerint nem cache-elhető.

NGINX-ben az ssl_early_data direktíva és a $ssl_early_data változó ad ehhez építőelemet. A proxy azonban csak azt tudja megmondani, hogy korán érkezett-e a kérés. Azt már az alkalmazás ismeri, hogy egy adott üzleti művelet ismétlése elfogadható-e.

Hol engedném át?

Jó jelölt lehet egy publikus, cache-elhető HTML-oldal, egy statikus konfiguráció vagy egy valóban mellékhatásmentes keresés. Ehhez is szükséges, hogy a CDN és az origin következetesen kezelje az early data jelzését.

Írási API-k, hitelesített állapotváltások, fizetés, jelszó-visszaállítás és költséges lekérdezések előtt nem engedném át. Éles rendszerben alapértelmezésként kikapcsolva hagynám, majd csak mért késleltetési nyereség és konkrét endpointlista alapján nyitnám meg.

A 0-RTT akkor jó optimalizálás, ha a kiválasztott útvonalak már eleve elviselik az ismétlést. Nem teljesítménykapcsoló, hanem a HTTP-műveletekről szóló biztonsági döntés.

Források

Leave a Reply

Az e-mail címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük