Helló Habr, az én nevem Ilja, az Exness platformcsapatában dolgozom. Alapvető infrastruktúraelemeket fejlesztünk és valósítunk meg, amelyeket a termékfejlesztő csapataink használnak.
Ebben a cikkben szeretném megosztani a tapasztalataimat az encrypted SNI (ESNI) technológia bevezetéséről a nyilvános weboldalak infrastruktúrájában.

Ennek a technológiának a használata növelni fogja a nyilvános weboldalunk biztonságát, és megfelel a cég által elfogadott belső biztonsági szabványoknak.
Először is szeretném hangsúlyozni, hogy a technológiát még nem standardizálták, és még mindig tervezet formájában van, azonban a CloudFlare és a Mozilla már támogatja ezt ( ). Ez motivált minket egy ilyen kísérletre.
Egy kis elmélet
ESNI a TLS 1.3 protokollhoz készült kiegészítés, amely lehetővé teszi az SNI titkosítását a TLS handshake "Client Hello" üzenetében. Íme, hogyan néz ki a Client Hello ESNI támogatással (a megszokott SNI helyett ESNI-t látunk):

Az ESNI használatához három összetevő szükséges:
- DNS;
- klientoldali támogatás;
- szerveroldali támogatás.
DNS
Két DNS bejegyzést kell hozzáadni – A, és a TXT (a TXT bejegyzés tartalmazza a nyilvános kulcsot, amellyel a kliens titkosíthatja az SNI-t) – lásd lejjebb. Továbbá szükség van DoH (DNS over HTTPS) támogatásra, mivel a rendelkezésre álló kliensek (lásd lejjebb) nem aktiválják az ESNI támogatását DoH nélkül. Ez logikus, hiszen az ESNI a kérés erőforrásának nevét titkosítja, tehát értelmetlen UDP-n DNS-hez fordulni. Továbbá, a használata megvédi a "cache poisoning" támadásoktól ebben a forgatókönyvben.
Jelenleg elérhető , amelyek között vannak:
CDN (Check My Browser → Encrypted SNI → Learn More), akiknek a szerverei már jelenleg is támogatják az ESNI-t, tehát a CloudFlare szerverei DNS-ében legalább két bejegyzést találunk – A és TXT. Az alábbi példában a Google DNS-t kérdezzük (HTTPS-en keresztül):
A bejegyzés:
curl 'https://dns.google.com/resolve?name=www.cloudflare.com&type=A'
-s -H 'accept: application/dns+json'
{
"Status": 0,
"TC": false,
"RD": true,
"RA": true,
"AD": true,
"CD": false,
"Question": [
{
"name": "www.cloudflare.com.",
"type": 1
}
],
"Answer": [
{
"name": "www.cloudflare.com.",
"type": 1,
"TTL": 257,
"data": "104.17.210.9"
},
{
"name": "www.cloudflare.com.",
"type": 1,
"TTL": 257,
"data": "104.17.209.9"
}
]
}
TXT bejegyzés, a kérés sablonja a következőképpen alakul: _esni.FQDN:
curl 'https://dns.google.com/resolve?name=_esni.www.cloudflare.com&type=TXT'
-s -H 'accept: application/dns+json'
{
"Status": 0,
"TC": false,
"RD": true,
"RA": true,
"AD": true,
"CD": false,
"Question": [
{
"name": "_esni.www.cloudflare.com.",
"type": 16
}
],
"Answer": [
{
"name": "_esni.www.cloudflare.com.",
"type": 16,
"TTL": 1799,
"data": ""/wEUgUKlACQAHQAg9SiAYQ9aUseUZr47HYHvF5jkt3aZ5802eAMJPhRz1QgAAhMBAQQAAAAAXtUmAAAAAABe3Q8AAAA=""
}
],
"Comment": "Response from 2400:cb00:2049:1::a29f:209."
}Tehát a DNS szempontjából a DoH-t (preferáltan DNSSEC-cel) kell használnunk, és két bejegyzést kell hozzáadnunk.
Ügyfél támogatás
Ha a böngészőkről beszélünk, akkor jelenleg . Itt található az útmutató, hogyan aktiválhatjuk az ESNI és a DoH támogatását a FireFox-ban. Miután a böngészőt beállítottuk, körülbelül így kell kinéznie:

a böngésző ellenőrzéséhez.
Természetesen az ESNI támogatásához TLS 1.3-at kell használni, mivel az ESNI a TLS 1.3 kiterjesztése.
Az ESNI-t támogató hátterek tesztelésére egy klienst valósítottunk meg go, de erről később.
Szerver támogatás
Jelenleg az ESNI nem támogatott web szerverektől, mint a nginx/apache stb., mert TLS-t OpenSSL/BoringSSL-lel kezelnek, aminek az ESNI hivatalosan nem támogatott.
Ezért úgy döntöttünk, hogy létrehozunk egy front-end komponenst (ESNI reverse proxy), amely támogatta a TLS 1.3 terminálását ESNI-vel és a HTTP(S) forgalom proxizálását olyan upstream felé, amely nem támogatja az ESNI-t. Ez lehetővé teszi a technológia alkalmazását a már meglévő infrastruktúrában, anélkül, hogy a fő összetevőkön módosítanánk - azaz a jelenlegi, ESNI-t nem támogató web szolgáltatókat tudjuk használni.
A szemléltetés érdekében íme egy ábra:

Megjegyzem, hogy a proxy úgy lett kialakítva, hogy a TLS kapcsolatot ESNI nélkül tudja terminálni, hogy támogassa az ESNI nélküli klienseket. A protokoll az upstreammal lehet HTTP vagy HTTPS TLS 1.3 alatti verzióval (ha az upstream nem támogatja a 1.3-at). Ez a séma maximális rugalmasságot nyújt.
Az ESNI támogatás megvalósítását go a munkájából kölcsönöztük. Azonnal megjegyzem, hogy a megvalósítás meglehetősen összetett, mivel a standard könyvtár módosítását igényli. crypto/tls és ezért "patch-olásra" van szükség GOROOT a fordítás előtt.
Az ESNI kulcsok generálásához a (ez is a CloudFlare terméke). Ezeket a kulcsokat a SNI titkosítására/dekódolására használjuk.
A buildet a go 1.13 használatával teszteltük Linuxon (Debian, Alpine) és MacOS-en.
Néhány szó a működési jellemzőkről.
Az ESNI fordított proxy Prometheus formátumban biztosít metrikákat, például rps, upstream késleltetés és válaszkódok, sikeres és sikertelen TLS-kézfogások és TLS-kézfogás időtartama. Első látásra ez elegendőnek tűnt a proxy forgalomkezelésének értékeléséhez.
Használat előtt terheléses tesztelést végeztünk. Az eredmények lent találhatók:
wrk -t50 -c1000 -d360s 'https://esni-rev-proxy.npw:443' --timeout 15s
6 perces teszt futtatás a https://esni-rev-proxy.npw:443 címen
50 szál és 1000 kapcsolat
Szál statisztikák Átlag Szórás Max +/– Szórás
Késleltetés 1.77s 1.21s 7.20s 65.43%
Kérés/szekundum 13.78 8.84 140.00 83.70%
206357 kérés 6.00 perc alatt, 6.08GB olvasva
Kérések/szekundum: 573.07
Átvitel/szekundum: 17.28MB A terheléses tesztelést teljesen minőségi alapon hajtottuk végre, összehasonlítva az ESNI fordított proxy használatát és anélkül. Lokálisan „töltöttük” a forgalmat, hogy kizárjuk a köztes komponensek „zaját”.
Tehát, ESNI támogatással és upstream HTTP proxyzással, körülbelül ~ 550 rps-t kaptunk egy példánytól, miközben az ESNI fordított proxy átlagos CPU/RAM fogyasztása:
- 80% CPU-használat (4 vCPU, 4 GB RAM-os hosztok, Linux)
- 130 MB Mem RSS

Összehasonlításképpen, az RPS az ugyanazon upstream nginx esetében, TLS termináció nélkül (HTTP protokoll) ~ 1100:
wrk -t50 -c1000 -d360s 'http://lb.npw:80' --timeout 15s
6 perces teszt futtatás a http://lb.npw:80 címen
50 szál és 1000 kapcsolat
Szál statisztikák Átlag Szórás Max +/– Szórás
Késleltetés 1.11s 2.30s 15.00s 90.94%
Kérés/szekundum 23.25 13.55 282.00 79.25%
393093 kérés 6.00 perc alatt, 11.35GB olvasva
Socket hibák: kapcsolódás 0, olvasás 0, írás 0, időtúllépés 9555
Nem 2xx vagy 3xx válaszok: 8111
Kérések/szekundum: 1091.62
Átvitel/szekundum: 32.27MB A timeoutok jelenléte arra utal, hogy erőforrásokból hiány van (4 vCPU, 4 GB RAM-os hosztokat használtunk, Linux), és a potenciális RPS ténylegesen magasabb (2700 RPS-ig is eljutottunk erősebb erőforrásokon).
Összegzésképpen megjegyezném, hogy az ESNI technológia ígéretesnek tűnik. Még sok nyitott kérdés van, például a nyilvános ESNI kulcs DNS-ben való tárolásának és az ESNI kulcsok forgatásának kérdései – ezek a kérdések aktívan vitatottak, és az ESNI legfrissebb tervezet (a cikk írásakor) már .
Forrás: habr.com
