Jak chránit svůj veřejný web s ESNI

Ahoj Habr, jmenuji se Ilya a pracuji v platformovém týmu společnosti Exness. Vyvíjíme a implementujeme základní infrastrukturní komponenty, které využívají naše produktové týmy.

V tomto článku bych se rád podělil o zkušenosti s implementací technologie encrypted SNI (ESNI) v infrastruktuře veřejných webových stránek.

Jak chránit svůj veřejný web s ESNI

Použití této technologie zvýší úroveň bezpečnosti při práci s veřejným webem a zajistí dodržení interních bezpečnostních standardů společnosti.

Nejdříve bych chtěl upozornit, že technologie není standardizována a stále se nachází v draftu, avšak CloudFlare a Mozilla ji již podporují (v draft01). To nás motivovalo k takovému experimentu.

Trochu teorie

ESNI je rozšíření protokolu TLS 1.3, které umožňuje šifrovat SNI v zprávě „Client Hello“ TLS handshake. Takto vypadá Client Hello s podporou ESNI (místo běžného SNI vidíme ESNI):

Jak chránit svůj veřejný web s ESNI

 K používání ESNI jsou potřeba tři složky:

  • DNS; 
  • Podpora ze strany klienta;
  • Podpora ze strany serveru.

. Vytvořte A-záznam blog a určete pro něj nějakou fiktivní IP (to je oficiální

Je třeba přidat dvě DNS záznamy – A, a TXT (TXT záznam obsahuje veřejný klíč, s jehož pomocí může klient šifrovat SNI) – viz níže. Kromě toho by měla existovat podpora DoH (DNS over HTTPS), protože dostupné klienty (viz níže) neaktualizují podporu ESNI bez DoH. To dává smysl, protože ESNI předpokládá šifrování názvu zdroje, ke kterému se obracíme, tedy je bezpředmětné obracet se na DNS přes UDP. Navíc použití DNSSEC chrání před útoky typu „cache poisoning“ v tomto scénáři.

V současné době je k dispozici několik poskytovatelů DoH,mezi nimi:

CloudFlare tvrdí (Check My Browser → Encrypted SNI → Learn More), že jejich servery již nyní podporují ESNI, což znamená, že pro servery CloudFlare v DNS máme minimálně dva záznamy – A a TXT. V následujícím příkladu dotazujeme Google DNS (over HTTPS): 

A záznam:

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, dotaz se sestavuje podle šablony _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."
}

Z pohledu DNS bychom měli používat DoH (ideálně s DNSSEC) a přidat dvě záznamy. 

Podpora ze strany klienta

Pokud mluvíme o prohlížečích, v současnosti je podpora realizována pouze v prohlížeči FireFox.. Zde Následují pokyny, jak aktivovat podporu ESNI a DoH v prohlížeči FireFox. Po nastavení prohlížeče bychom měli vidět přibližně takový obrazec:

Jak chránit svůj veřejný web s ESNI

Odkaz pro ověření prohlížeče.

Samozřejmě, pro podporu ESNI musí být použit TLS 1.3, protože ESNI je rozšířením TLS 1.3.

Pro účely testování backendu s podporou ESNI jsme implementovali klienta v go, ale o tom později.

Podpora ze strany serveru

V současnosti ESNI nepodporují webové servery jako nginx/apache apod., protože pracují s TLS přes OpenSSL/BoringSSL, ve kterých ESNI není oficiálně podporováno.

Proto jsme se rozhodli vytvořit svůj front-end komponent (ESNI reverse proxy), který by podporoval terminaci TLS 1.3 s ESNI a proxy HTTP(S) provozu na upstream, který ESNI nepodporuje. To umožňuje využívat technologii v již existující infrastruktuře, bez změny hlavních komponent – tedy používat aktuální webové servery, které ESNI nepodporují. 

Pro názornost uvádíme schéma:

Jak chránit svůj veřejný web s ESNI

Poznamenávám, že proxy byla navržena s možností terminovat TLS spojení bez ESNI, aby podpořila klienty bez ESNI. Také může být protokol komunikace s upstreamem buď HTTP, nebo HTTPS s verzí TLS nižší než 1.3 (pokud upstream nepodporuje 1.3). Tento model poskytuje maximální flexibilitu.

Implementaci podpory ESNI na go jsme převzali od CloudFlare. Hned poznamenávám, že samotná implementace je dost netriviální, protože předpokládá změny v standardní knihovně crypto/tls a proto vyžaduje "patchování" GOROOT před sestavením.

Pro generování ESNI klíčů jsme použili esnitool (také dílo CloudFlare). Tyto klíče se používají pro šifrování/dešifrování SNI.
Otestovali jsme sestavení s použitím go 1.13 na Linuxu (Debian, Alpine) a MacOS. 

Pár slov o provozních vlastnostech

ESNI reverse proxy poskytuje metriky ve formátu Prometheus, například rps, latence upstreamu a kódy odpovědí, neúspěšné/úspěšné TLS handshake a délku TLS handshake. Na první pohled se to zdálo být dostatečné pro posouzení, jak si proxy poradí s provozem. 

Před použitím jsme také provedli zátěžové testování. Výsledky jsou níže:

wrk -t50 -c1000 -d360s 'https://esni-rev-proxy.npw:443' --timeout 15s
Běží test 6 minut @ https://esni-rev-proxy.npw:443
  50 vláken a 1000 připojení
  Statistiky vláken   Průměr   Stdev   Max   +/− Stdev
    Latence     1.77s     1.21s    7.20s    65.43%
    Požadavků/sec    13.78     8.84   140.00     83.70%
  206357 požadavků za 6.00 minut, 6.08GB přečteno
Požadavky/sec:    573.07
Přenos/sec:     17.28MB 

Zátěžové testování jsme provedli čistě kvalitativně, aby bylo možné porovnat schéma s použitím ESNI reverse proxy a bez ní. Provoz jsme „nalévali“ lokálně, abychom vyloučili „rušení“ ve středních komponentách.

S podporou ESNI a proxy na upstreamu s HTTP jsme získali přibližně ~ 550 rps z jednoho instance, přičemž průměrná spotřeba CPU/RAM ESNI reverse proxy:

  • 80% využití CPU (4 vCPU, 4 GB RAM hosty, Linux)
  • 130 MB Mem RSS

Jak chránit svůj veřejný web s ESNI

Pro srovnání, RPS pro stejný upstream nginx bez terminace TLS (HTTP protokol) je ~ 1100:

wrk -t50 -c1000 -d360s 'http://lb.npw:80' --timeout 15s
Běží test 6 minut @ http://lb.npw:80
  50 vláken a 1000 připojení
  Statistiky vláken   Průměr   Stdev   Max   +/− Stdev
    Latence     1.11s     2.30s   15.00s    90.94%
    Požadavků/sec    23.25     13.55   282.00     79.25%
  393093 požadavků za 6.00 minut, 11.35GB přečteno
  Chyby soketu: připojení 0, čtení 0, zápis 0, vypršení 9555
  Odpovědi, které nejsou 2xx nebo 3xx: 8111
Požadavky/sec:   1091.62
Přenos/sec:     32.27MB 

Přítomnost time-outů naznačuje nedostatek zdrojů (používali jsme 4 vCPU, 4 GB RAM hosty, Linux), a ve skutečnosti by potenciální RPS mohl být vyšší (získávali jsme čísla až 2700 RPS na výkonnějších zdrojích).

Na závěr poznamenám, že technologie ESNI vypadá dost perspektivně. Existuje ještě mnoho otevřených otázek, například otázka ukládání veřejného ESNI klíče do DNS a rotace ESNI klíčů – tyto otázky se aktivně diskutují, a poslední verze návrhu (v době psaní) ESNI již 7.

Zdroj: habr.com

Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster