Hogyan védjük meg nyilvános weboldalunkat ESNI-vel

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.

Hogyan védjük meg nyilvános weboldalunkat ESNI-vel

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 ( draft01). 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):

Hogyan védjük meg nyilvános weboldalunkat ESNI-vel

 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 DNSSEC használata megvédi a "cache poisoning" támadásoktól ebben a forgatókönyvben.

Jelenleg elérhető több DoH szolgáltató, amelyek között vannak:

CDN állítja, (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 a támogatás csak a FireFox-ban valósult meg.. Itt 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:

Hogyan védjük meg nyilvános weboldalunkat ESNI-vel

Link 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:

Hogyan védjük meg nyilvános weboldalunkat ESNI-vel

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 CDNmunká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 esnitool-t használtuk (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

Hogyan védjük meg nyilvános weboldalunkat ESNI-vel

Ö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 7.

Forrás: habr.com

Megbízható hosting vásárlása weboldalak számára, DDoS védelemmel, VPS VDS szerverek. 🔥 Megbízható webtárhely vásárlása DDoS védelemmel, VPS VDS szerverek | ProHoster