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

Ahoj Habr, jmenuji se Ilya, pracuji v týmu platformy ve společnosti Exness. Vyvíjíme a implementujeme základní součásti infrastruktury, které používají naše týmy pro vývoj produktů.

V tomto článku bych se rád podělil o své zkušenosti s implementací šifrované technologie SNI (ESNI) do infrastruktury veřejných webů.

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

Použití této technologie zvýší úroveň zabezpečení při práci s veřejnými webovými stránkami a bude v souladu s interními bezpečnostními standardy přijatými Společností.

Nejprve bych rád upozornil, že technologie není standardizovaná a je stále ve fázi návrhu, ale CloudFlare a Mozilla ji již podporují (v koncept01). To nás motivovalo k takovému experimentu.

Některé teorie

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

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

 Chcete-li používat ESNI, potřebujete tři komponenty:

  • DNS; 
  • Zákaznická podpora;
  • Podpora na straně serveru.

DNS

Musíte přidat dva záznamy DNS – AA TXT (Záznam TXT obsahuje veřejný klíč, kterým může klient šifrovat SNI) - viz níže. Navíc musí existovat podpora DoH (DNS přes HTTPS), protože dostupní klienti (viz níže) neumožňují podporu ESNI bez DoH. To je logické, protože ESNI předpokládá šifrování názvu zdroje, ke kterému přistupujeme, to znamená, že nemá smysl přistupovat k DNS přes UDP. Navíc použití DNSSEC vám v tomto scénáři umožňuje chránit se před útoky otravy mezipamětí.

Momentálně dostupný několik poskytovatelů DoH, mezi nimi:

Cloudflare prohlašuje (Zkontrolujte Můj prohlížeč → Šifrované SNI → Další informace), že jejich servery již podporují ESNI, to znamená, že pro servery CloudFlare v DNS máme alespoň dva záznamy - A a TXT. V níže uvedeném příkladu se dotazujeme Google DNS (přes 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, požadavek je vygenerován 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 tedy měli použít DoH (nejlépe s DNSSEC) a přidat dva záznamy. 

Zákaznická podpora

Pokud se bavíme o prohlížečích, tak v tuto chvíli podpora je implementována pouze ve FireFoxu. Zde Zde je návod, jak aktivovat podporu ESNI a DoH ve FireFoxu. Po konfiguraci prohlížeče bychom měli vidět něco takového:

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

Odkaz pro kontrolu prohlížeče.

Pro podporu ESNI je samozřejmě nutné použít TLS 1.3, protože ESNI je rozšířením TLS 1.3.

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

Podpora na straně serveru

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

Proto jsme se rozhodli vytvořit vlastní front-end komponentu (ESNI reverzní proxy), která by podporovala ukončení TLS 1.3 s ESNI a proxy HTTP(S) provoz na upstream, který ESNI nepodporuje. To umožňuje použití technologie v již existující infrastruktuře, aniž by se měnily hlavní komponenty – tedy s využitím současných webových serverů, které ESNI nepodporují. 

Pro přehlednost je zde schéma:

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

Podotýkám, že proxy byl navržen s možností ukončit připojení TLS bez ESNI, aby podporoval klienty bez ESNI. Komunikační protokol s upstream může být také HTTP nebo HTTPS s verzí TLS nižší než 1.3 (pokud upstream nepodporuje 1.3). Toto schéma poskytuje maximální flexibilitu.

Implementace podpory ESNI na go jsme si půjčili od Cloudflare. Rád bych hned poznamenal, že samotná implementace je docela netriviální, protože zahrnuje změny ve standardní knihovně krypto/tls a proto vyžaduje „záplatování“ GOROOT před montáží.

Ke generování klíčů ESNI jsme použili esnitool (také duchovní dítě CloudFlare). Tyto klíče se používají pro šifrování/dešifrování SNI.
Testovali jsme sestavení pomocí go 1.13 na Linuxu (Debian, Alpine) a MacOS. 

Pár slov o provozních vlastnostech

Reverzní proxy ESNI poskytuje metriky ve formátu Prometheus, jako jsou rps, upstream latence a kódy odezvy, neúspěšné/úspěšné TLS handshake a trvání TLS handshake. Na první pohled se to zdálo dostatečné pro vyhodnocení toho, jak proxy nakládá s provozem. 

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

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 

Provedli jsme čistě kvalitativní zátěžové testování, abychom porovnali schéma pomocí ESNI reverzní proxy a bez. Lokálně jsme „nalévali“ provoz, abychom eliminovali „zásahy“ do mezisložek.

Takže s podporou ESNI a proxy pro upstream s HTTP jsme dostali přibližně ~550 rps z jedné instance, s průměrnou spotřebou CPU/RAM reverzní proxy ESNI:

  • 80% využití CPU (4 vCPU, 4 GB RAM hostitelé, Linux)
  • 130 MB paměti RSS

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

Pro srovnání, RPS pro stejný nginx upstream bez ukončení 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 

Přítomnost časových limitů naznačuje, že je nedostatek zdrojů (použili jsme 4 vCPU, 4 GB RAM hostitele, Linux) a ve skutečnosti je potenciální RPS vyšší (obdrželi jsme čísla až 2700 RPS na výkonnějších zdrojích).

Závěrem podotýkám že technologie ESNI vypadá docela slibně. Stále existuje mnoho otevřených otázek, například otázky ukládání veřejného klíče ESNI v DNS a rotace klíčů ESNI - tyto problémy jsou aktivně diskutovány a nejnovější verze návrhu ESNI (v době psaní tohoto článku) je již k dispozici 7.

Zdroj: www.habr.com

Přidat komentář