Ako chrániť svoju verejnú webovú stránku pomocou ESNI

Ahoj Habr, volám sa Ilya, pracujem v tíme platformy v Exness. Vyvíjame a implementujeme základné komponenty infraštruktúry, ktoré používajú naše tímy pre vývoj produktov.

V tomto článku by som sa rád podelil o svoje skúsenosti s implementáciou šifrovanej technológie SNI (ESNI) do infraštruktúry verejných webových stránok.

Ako chrániť svoju verejnú webovú stránku pomocou ESNI

Použitie tejto technológie zvýši úroveň bezpečnosti pri práci s verejnou webovou stránkou a bude v súlade s internými bezpečnostnými štandardmi prijatými Spoločnosťou.

V prvom rade by som chcel upozorniť, že technológia nie je štandardizovaná a je stále v návrhu, no CloudFlare a Mozilla ju už podporujú (v r. návrh01). To nás motivovalo k takémuto experimentu.

Niektoré teórie

ESNI je rozšírenie protokolu TLS 1.3, ktoré umožňuje šifrovanie SNI v správe TLS handshake „Client Hello“. Takto vyzerá klient Hello s podporou ESNI (namiesto obvyklého SNI vidíme ESNI):

Ako chrániť svoju verejnú webovú stránku pomocou ESNI

 Ak chcete používať ESNI, potrebujete tri komponenty:

  • DNS; 
  • Zákaznícka podpora;
  • Podpora na strane servera.

DNS

Musíte pridať dva záznamy DNS – AA TXT (TXT záznam obsahuje verejný kľúč, ktorým môže klient šifrovať SNI) - viď nižšie. Okrem toho musí existovať podpora Doh (DNS cez HTTPS), pretože dostupní klienti (pozri nižšie) neumožňujú podporu ESNI bez DoH. Je to logické, keďže ESNI predpokladá šifrovanie názvu zdroja, ku ktorému pristupujeme, to znamená, že nemá zmysel pristupovať k DNS cez UDP. Navyše použitie DNSSEC vám v tomto scenári umožňuje chrániť sa pred útokmi na otravu vyrovnávacou pamäťou.

Práve dostupný niekoľko poskytovateľov DoH, medzi nimi:

CloudFlare stavy (Skontrolujte Môj prehliadač → Šifrované SNI → Ďalšie informácie), že ich servery už podporujú ESNI, to znamená, že pre servery CloudFlare v DNS máme aspoň dva záznamy - A a TXT. V nižšie uvedenom príklade dopytujeme Google DNS (cez HTTPS): 

А vstup:

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 záznam, žiadosť sa vygeneruje podľa šablóny _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."
}

Takže z pohľadu DNS by sme mali použiť DoH (najlepšie s DNSSEC) a pridať dva záznamy. 

Zákaznícka podpora

Ak hovoríme o prehliadačoch, tak v súčasnosti podpora je implementovaná iba vo FireFox. Tu Tu je návod, ako aktivovať podporu ESNI a DoH vo FireFox. Po nakonfigurovaní prehliadača by sme mali vidieť niečo takéto:

Ako chrániť svoju verejnú webovú stránku pomocou ESNI

Odkaz na kontrolu prehliadača.

Samozrejme, na podporu ESNI sa musí použiť TLS 1.3, pretože ESNI je rozšírením TLS 1.3.

Pre účely testovania backendu s podporou ESNI sme klienta implementovali na go, Ale o tom neskôr.

Podpora na strane servera

V súčasnosti ESNI nepodporujú webové servery ako nginx/apache atď., pretože pracujú s TLS cez OpenSSL/BoringSSL, ktoré oficiálne nepodporujú ESNI.

Preto sme sa rozhodli vytvoriť vlastný front-end komponent (ESNI reverzný proxy), ktorý by podporoval ukončenie TLS 1.3 s ESNI a proxy HTTP(S) prevádzku na upstream, ktorý ESNI nepodporuje. To umožňuje použiť technológiu v už existujúcej infraštruktúre bez zmeny hlavných komponentov – teda s využitím súčasných webových serverov, ktoré nepodporujú ESNI. 

Pre prehľadnosť uvádzame schému:

Ako chrániť svoju verejnú webovú stránku pomocou ESNI

Všimol som si, že proxy bol navrhnutý so schopnosťou ukončiť pripojenie TLS bez ESNI, aby podporoval klientov bez ESNI. Komunikačný protokol s upstreamom môže byť tiež HTTP alebo HTTPS s verziou TLS nižšou ako 1.3 (ak upstream nepodporuje 1.3). Táto schéma poskytuje maximálnu flexibilitu.

Implementácia podpory ESNI na go požičali sme si od CloudFlare. Hneď by som rád poznamenal, že samotná implementácia je celkom netriviálna, pretože zahŕňa zmeny v štandardnej knižnici krypto/tls a preto vyžaduje „záplatovanie“ GOROOT pred montážou.

Na generovanie kľúčov ESNI sme použili esnitool (tiež duchovné dieťa CloudFlare). Tieto kľúče sa používajú na šifrovanie/dešifrovanie SNI.
Testovali sme zostavu pomocou go 1.13 na Linuxe (Debian, Alpine) a MacOS. 

Niekoľko slov o prevádzkových vlastnostiach

ESNI reverzný proxy poskytuje metriky vo formáte Prometheus, ako sú rps, upstream latencia a kódy odozvy, neúspešné/úspešné TLS handshake a trvanie TLS handshake. Na prvý pohľad sa to zdalo dostatočné na vyhodnotenie toho, ako server proxy zvláda prevádzku. 

Pred použitím sme vykonali aj záťažové testy. Výsledky nižšie:

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 

Uskutočnili sme čisto kvalitatívne testovanie záťaže, aby sme porovnali schému pomocou reverzného proxy servera ESNI a bez neho. Lokálne sme „naliali“ dopravu, aby sme eliminovali „rušenie“ v medzizložkách.

Takže s podporou ESNI a proxy pre upstream z HTTP sme dostali približne ~550 rps z jednej inštancie, s priemernou spotrebou CPU/RAM reverznej proxy ESNI:

  • 80 % využitie CPU (4 vCPU, 4 GB RAM hostitelia, Linux)
  • 130 MB pamäte RSS

Ako chrániť svoju verejnú webovú stránku pomocou ESNI

Pre porovnanie, RPS pre rovnaký nginx upstream bez ukončenia TLS (protokol HTTP) je ~ 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 

Prítomnosť časových limitov naznačuje, že je nedostatok zdrojov (použili sme 4 vCPU, 4 GB RAM hostiteľov, Linux) a v skutočnosti je potenciálna RPS vyššia (dostali sme čísla až 2700 RPS na výkonnejších zdrojoch).

Na záver podotýkam že technológia ESNI vyzerá celkom sľubne. Stále existuje veľa otvorených otázok, napríklad otázky ukladania verejného kľúča ESNI v DNS a rotácie kľúčov ESNI – o týchto problémoch sa aktívne diskutuje a najnovšia verzia návrhu ESNI (v čase písania tohto článku) je už k dispozícii 7.

Zdroj: hab.com

Pridať komentár