Hogyan védheti meg nyilvános webhelyét az ESNI segítségével

Hello Habr, a nevem Ilya, az Exness platform csapatában dolgozom. Fejlesztjük és megvalósítjuk azokat az alapvető infrastruktúra-összetevőket, amelyeket termékfejlesztő csapataink használnak.

Ebben a cikkben szeretném megosztani tapasztalataimat a titkosított SNI (ESNI) technológia nyilvános webhelyek infrastruktúrájában való megvalósításáról.

Hogyan védheti meg nyilvános webhelyét az ESNI segítségével

Ennek a technológiának a használata növeli a biztonsági szintet a nyilvános weboldallal végzett munka során, és megfelel a Társaság által elfogadott belső biztonsági szabványoknak.

Először is szeretném felhívni a figyelmet arra, hogy a technológia nincs szabványosítva, és még tervezetben van, de a CloudFlare és a Mozilla már támogatja ( tervezet01). Ez motivált minket egy ilyen kísérletre.

Egy kis elmélet

ESNI a TLS 1.3 protokoll kiterjesztése, amely lehetővé teszi az SNI-titkosítást a TLS kézfogás „Client Hello” üzenetben. Így néz ki a Client Hello ESNI támogatással (a szokásos SNI helyett ESNI-t látunk):

Hogyan védheti meg nyilvános webhelyét az ESNI segítségével

 Az ESNI használatához három összetevőre van szüksége:

  • DNS; 
  • Ügyfélszolgálat;
  • Szerver oldali támogatás.

DNS

Két DNS-rekordot kell hozzáadnia - AÉs TXT (A TXT rekord tartalmazza azt a nyilvános kulcsot, amellyel a kliens titkosíthatja az SNI-t) - lásd alább. Ezen kívül támogatásra is szükség van DoH (DNS HTTPS-en keresztül), mert az elérhető kliensek (lásd alább) nem engedélyezik az ESNI-támogatást DoH nélkül. Ez logikus, mivel az ESNI magában foglalja az elért erőforrás nevének titkosítását, vagyis nincs értelme a DNS-hez UDP-n keresztül hozzáférni. Ráadásul a felhasználás DNSSEC lehetővé teszi a gyorsítótár-mérgezés elleni védelmet ebben a forgatókönyvben.

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

CloudFlare államok (Ellenőrizze a Böngészőt → Titkosított SNI → További információ), hogy a szervereik már támogatják az ESNI-t, vagyis a DNS-ben lévő CloudFlare szerverekhez legalább két rekord van - A és TXT. Az alábbi példában lekérdezzük a Google DNS-t (HTTPS-en keresztül): 

А belépé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 rekord, kérés egy sablon szerint generálódik _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 DNS szempontból a DoH-t kell használnunk (lehetőleg DNSSEC-vel), és adjunk hozzá két bejegyzést. 

Vevőszolgálat

Ha már a böngészőkről beszélünk, akkor jelenleg a támogatás csak FireFoxban van megvalósítva. Itt Íme az ESNI és a DoH támogatás FireFoxban történő aktiválásához szükséges utasítások. A böngésző konfigurálása után valami ilyesmit kell látnunk:

Hogyan védheti meg nyilvános webhelyét az ESNI segítségével

Link hogy ellenőrizze a böngészőt.

Természetesen az ESNI támogatásához a TLS 1.3-at kell használni, mivel az ESNI a TLS 1.3 kiterjesztése.

A backend ESNI-támogatással történő tesztelése céljából a klienst a következőn implementáltuk go, De erről később.

Szerver oldali támogatás

Jelenleg az ESNI-t nem támogatják az olyan webszerverek, mint az nginx/apache stb., mivel ezek OpenSSL/BoringSSL-en keresztül működnek a TLS-szel, amelyek hivatalosan nem támogatják az ESNI-t.

Ezért úgy döntöttünk, hogy létrehozzuk a saját front-end komponensünket (ESNI fordított proxy), amely támogatná a TLS 1.3-as lezárást ESNI-vel és proxy HTTP(S) forgalmat az upstream felé, amely nem támogatja az ESNI-t. Ez lehetővé teszi, hogy a technológiát egy már meglévő infrastruktúrában használják anélkül, hogy megváltoztatnák a fő összetevőket - vagyis olyan jelenlegi webszervereket használnának, amelyek nem támogatják az ESNI-t. 

Az érthetőség kedvéért itt egy diagram:

Hogyan védheti meg nyilvános webhelyét az ESNI segítségével

Megjegyzem, a proxy úgy lett kialakítva, hogy képes legyen megszakítani a TLS-kapcsolatot ESNI nélkül, hogy támogassa az ESNI nélküli ügyfeleket. Ezenkívül az upstream kommunikációs protokoll HTTP vagy HTTPS lehet 1.3-nál alacsonyabb TLS-verzióval (ha az upstream nem támogatja az 1.3-at). Ez a séma maximális rugalmasságot biztosít.

ESNI támogatás megvalósítása a go től kölcsönöztünk CloudFlare. Azonnal szeretném megjegyezni, hogy maga a megvalósítás meglehetősen nem triviális, mivel változásokat tartalmaz a szabványos könyvtárban crypto/tls ezért „foltozást” igényel GOROOT összeszerelés előtt.

Az általunk használt ESNI kulcsok generálásához esnitool (szintén a CloudFlare ötlete). Ezeket a kulcsokat az SNI titkosítására/visszafejtésére használják.
A buildet a go 1.13-as verziójá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átumú mérőszámokat biztosít, például rps, upstream késleltetés és válaszkódok, sikertelen/sikeres TLS-kézfogások és TLS-kézfogás időtartama. Első pillantásra ez elegendőnek tűnt annak értékeléséhez, hogy a proxy hogyan kezeli a forgalmat. 

Használat előtt terhelési vizsgálatot is végeztünk. Eredmények lent:

wrk -t50 -c1000 -d360s 'https://esni-rev-proxy.npw:443' --timeout 15s
Running 6m test @ https://esni-rev-proxy.npw:443
  50 threads and 1000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.77s     1.21s    7.20s    65.43%
    Req/Sec    13.78      8.84   140.00     83.70%
  206357 requests in 6.00m, 6.08GB read
Requests/sec:    573.07
Transfer/sec:     17.28MB 

Pusztán kvalitatív terhelési tesztet végeztünk a séma összehasonlítására ESNI fordított proxy használatával és anélkül. Helyben „öntöttük” a forgalmat, hogy kiküszöböljük a köztes komponensek „interferenciáját”.

Tehát az ESNI támogatással és a HTTP-n keresztüli felfelé irányuló proxyval körülbelül 550 rps-t kaptunk egy példánytól, az ESNI fordított proxy átlagos CPU/RAM fogyasztásával:

  • 80%-os CPU-használat (4 vCPU, 4 GB RAM gazdagép, Linux)
  • 130 MB Mem RSS

Hogyan védheti meg nyilvános webhelyét az ESNI segítségével

Összehasonlításképpen, az RPS ugyanazon nginx esetében a TLS (HTTP-protokoll) lezárása nélkül ~ 1100:

wrk -t50 -c1000 -d360s 'http://lb.npw:80' –-timeout 15s
Running 6m test @ http://lb.npw:80
  50 threads and 1000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.11s     2.30s   15.00s    90.94%
    Req/Sec    23.25     13.55   282.00     79.25%
  393093 requests in 6.00m, 11.35GB read
  Socket errors: connect 0, read 0, write 0, timeout 9555
  Non-2xx or 3xx responses: 8111
Requests/sec:   1091.62
Transfer/sec:     32.27MB 

Az időtúllépések jelenléte erőforráshiányra utal (4 vCPU-t, 4 GB RAM-os gazdagépet, Linuxot használtunk), sőt, a potenciális RPS magasabb (akár 2700 RPS-t is kaptunk erősebb erőforrásokon).

Befejezésül megjegyzem hogy az ESNI technológia meglehetősen ígéretesnek tűnik. Még mindig 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 - ezeket a kérdéseket aktívan vitatják, és az ESNI-tervezet legújabb verziója (a cikk írásakor) már megvan. 7.

Forrás: will.com

Hozzászólás