Kako zaštititi svoje javno web mjesto s ESNI

Pozdrav Habru, moje ime je Ilya, radim u timu za platforme u Exnessu. Razvijamo i implementiramo osnovne komponente infrastrukture koje koriste naši timovi za razvoj proizvoda.

U ovom članku želio bih podijeliti svoje iskustvo implementacije kriptirane SNI (ESNI) tehnologije u infrastrukturu javnih web stranica.

Kako zaštititi svoje javno web mjesto s ESNI

Korištenje ove tehnologije povećat će razinu sigurnosti pri radu s javnom web stranicom i uskladiti se s internim sigurnosnim standardima koje je usvojilo Društvo.

Prije svega, želio bih istaknuti da tehnologija nije standardizirana i još uvijek je u nacrtu, ali CloudFlare i Mozilla je već podržavaju (u nacrt01). To nas je motiviralo za takav eksperiment.

Malo teorije

ESNI je proširenje protokola TLS 1.3 koje omogućuje SNI enkripciju u TLS poruci rukovanja "Pozdrav klijentu". Evo kako Client Hello izgleda s ESNI podrškom (umjesto uobičajenog SNI-ja vidimo ESNI):

Kako zaštititi svoje javno web mjesto s ESNI

 Za korištenje ESNI-ja potrebne su vam tri komponente:

  • DNS; 
  • Podrška klijentima;
  • Podrška na strani poslužitelja.

DNS

Morate dodati dva DNS zapisa – AI TXT (TXT zapis sadrži javni ključ s kojim klijent može šifrirati SNI) - vidi dolje. Osim toga, mora postojati podrška DOH (DNS preko HTTPS-a) jer dostupni klijenti (vidi dolje) ne omogućuju ESNI podršku bez DoH-a. To je i logično, jer ESNI podrazumijeva enkripciju naziva resursa kojem pristupamo, odnosno nema smisla pristupati DNS-u preko UDP-a. Štoviše, korištenje DNSSEC omogućuje vam zaštitu od napada trovanja predmemorije u ovom scenariju.

Trenutno dostupan nekoliko DoH pružatelja usluga, među njima:

CloudFlare države (Check My Browser → Encrypted SNI → Learn More) da njihovi poslužitelji već podržavaju ESNI, odnosno za CloudFlare poslužitelje u DNS-u imamo barem dva zapisa - A i TXT. U donjem primjeru postavljamo upit Google DNS-u (preko HTTPS-a): 

А unos:

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 zapis, zahtjev se generira prema predlošku _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."
}

Dakle, iz perspektive DNS-a, trebali bismo koristiti DoH (po mogućnosti s DNSSEC-om) i dodati dva unosa. 

Korisnička podrška

Ako govorimo o preglednicima, onda u ovom trenutku podrška je implementirana samo u FireFoxu. Ovdje Evo uputa kako aktivirati ESNI i DoH podršku u FireFoxu. Nakon što je preglednik konfiguriran, trebali bismo vidjeti nešto poput ovoga:

Kako zaštititi svoje javno web mjesto s ESNI

Link za provjeru preglednika.

Naravno, TLS 1.3 mora se koristiti za podršku ESNI-ju, budući da je ESNI proširenje TLS-a 1.3.

Za potrebe testiranja pozadine s ESNI podrškom implementirali smo klijent na go, Ali o tome kasnije.

Podrška na strani poslužitelja

Trenutno ESNI ne podržavaju web poslužitelji kao što su nginx/apache itd., budući da rade s TLS-om putem OpenSSL/BoringSSL, koji službeno ne podržavaju ESNI.

Stoga smo odlučili stvoriti vlastitu front-end komponentu (ESNI reverse proxy), koja bi podržavala TLS 1.3 završetak s ESNI i proxy HTTP(S) prometom prema uzvodnom, koji ne podržava ESNI. To omogućuje korištenje tehnologije u već postojećoj infrastrukturi, bez mijenjanja glavnih komponenti – odnosno korištenjem trenutnih web poslužitelja koji ne podržavaju ESNI. 

Radi jasnoće, ovdje je dijagram:

Kako zaštititi svoje javno web mjesto s ESNI

Napominjem da je proxy dizajniran s mogućnošću prekidanja TLS veze bez ESNI-ja, za podršku klijentima bez ESNI-ja. Također, komunikacijski protokol uzvodno može biti HTTP ili HTTPS s TLS verzijom nižom od 1.3 (ako uzvodno ne podržava 1.3). Ova shema daje maksimalnu fleksibilnost.

Implementacija ESNI podrške na go posudili smo od CloudFlare. Želio bih odmah napomenuti da je sama implementacija prilično netrivijalna, budući da uključuje promjene u standardnoj biblioteci kripto/tls i stoga zahtijeva "krpanje" GOROOT prije montaže.

Za generiranje ESNI ključeva koristili smo esnitool (također zamisao CloudFlarea). Ovi se ključevi koriste za SNI šifriranje/dešifriranje.
Testirali smo verziju koristeći go 1.13 na Linuxu (Debian, Alpine) i MacOS-u. 

Nekoliko riječi o operativnim značajkama

ESNI obrnuti proxy pruža metriku u Prometheus formatu, kao što su rps, uzvodna latencija i kodovi odgovora, neuspješna/uspješna TLS rukovanja i trajanje TLS rukovanja. Na prvi pogled, ovo se činilo dovoljnim za procjenu kako proxy obrađuje promet. 

Također smo izvršili testiranje opterećenja prije upotrebe. Rezultati ispod:

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 

Proveli smo čisto kvalitativno testiranje opterećenja kako bismo usporedili shemu koja koristi ESNI obrnuti proxy i bez njega. Lokalno smo "točili" promet kako bismo eliminirali "smetnje" u međukomponentama.

Dakle, s podrškom za ESNI i proxyjem za upstream od HTTP-a, dobili smo oko ~550 rps iz jedne instance, s prosječnom potrošnjom CPU/RAM-a ESNI obrnutog proxyja:

  • 80% upotrebe CPU-a (4 vCPU-a, 4 GB RAM-a, Linux)
  • 130 MB Mem RSS

Kako zaštititi svoje javno web mjesto s ESNI

Za usporedbu, RPS za isti nginx uzvodno bez završetka TLS (HTTP protokola) 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 

Prisutnost timeouta ukazuje na nedostatak resursa (koristili smo 4 vCPU-a, hostove od 4 GB RAM-a, Linux), a zapravo je potencijalni RPS veći (dobili smo brojke do 2700 RPS na snažnijim resursima).

Zaključno napominjem da ESNI tehnologija izgleda prilično obećavajuće. Još uvijek ima puno otvorenih pitanja, na primjer, pitanja pohranjivanja javnog ESNI ključa u DNS i rotiranja ESNI ključeva - o tim se pitanjima aktivno raspravlja, a najnovija verzija nacrta ESNI (u vrijeme pisanja) već je 7.

Izvor: www.habr.com

Dodajte komentar