Hvordan beskytter man sin offentlige hjemmeside med ESNI

Hej Habr, jeg hedder Ilya, og jeg arbejder i platformteamet hos Exness. Vi udvikler og implementerer grundlæggende infrastrukturkomponenter, der anvendes af vores produktudviklingsteams.

I denne artikel vil jeg gerne dele erfaringer med implementeringen af teknologien encrypted SNI (ESNI) i infrastrukturen for offentlige hjemmesider.

Hvordan beskytter man sin offentlige hjemmeside med ESNI

Brugen af denne teknologi vil øge sikkerhedsniveauet ved arbejde med offentlige hjemmesider og overholde de interne sikkerhedsstandarder vedtaget af virksomheden.

Først vil jeg fremhæve, at teknologien ikke er standardiseret og stadig er i udkast, men CloudFlare og Mozilla understøtter allerede den (i draft01). Dette motiverede os til et sådant eksperiment.

Lidt teori

ESNI er en udvidelse af TLS 1.3-protokollen, der gør det muligt at kryptere SNI i "Client Hello" meddelelsen fra TLS handshake. Her er, hvordan Client Hello ser ud med ESNI-understøttelse (i stedet for den sædvanlige SNI ser vi ESNI):

Hvordan beskytter man sin offentlige hjemmeside med ESNI

 For at bruge ESNI er der tre komponenter, der er nødvendige:

  • DNS; 
  • Klientunderstøttelse;
  • Serverunderstøttelse.

DNS

Det er nødvendigt at tilføje to DNS-poster - A, og TXT (TXT-posten indeholder den offentlige nøgle, som klienten kan bruge til at kryptere SNI) - se nedenfor. Derudover bør der være understøttelse af DoH (DNS over HTTPS), da de tilgængelige klienter (se nedenfor) ikke aktiverer understøttelse af ESNI uden DoH. Dette giver mening, da ESNI indebærer kryptering af navnet på den ressource, vi anmoder om, hvilket betyder, at det er meningsløst at henvende sig til DNS via UDP. Endda brugen af DNSSEC giver beskyttelse mod "cache poisoning" angreb i dette scenarie.

I øjeblikket er der tilgængeligt flere DoH-udbydere, blandt dem:

CloudFlare Uanset hvor mange pessimistiske prognoser der er fremsat, har Huawei (Check My Browser → Encrypted SNI → Learn More), hvilket viser, at deres servere allerede nu understøtter ESNI, derfor har vi for CloudFlare-servere i DNS mindst to poster - A og TXT. I eksemplet nedenfor anmoder vi om Google DNS (over HTTPS): 

A post:

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 post, forespørgslen dannes efter skabelonen _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."
}

Så fra et DNS-perspektiv skal vi bruge DoH (helst med DNSSEC) og tilføje to poster. 

Klientens støtte

Når vi taler om browsere, er der i øjeblikket støtte kun implementeret i FireFox.. Her Her er instrukserne til, hvordan man aktiverer ESNI og DoH i FireFox. Når browseren er konfigureret, skal vi se noget som dette:

Hvordan beskytter man sin offentlige hjemmeside med ESNI

Link til browserens kontrol.

Selvfølgelig skal TLS 1.3 bruges til at støtte ESNI, da ESNI er en udvidelse til TLS 1.3.

For backend-testning med ESNI-støtte har vi implementeret en klient i go, men det vender vi tilbage til senere.

Serverens støtte

I øjeblikket understøttes ESNI ikke af webservere som nginx/apache osv., da de arbejder med TLS via OpenSSL/BoringSSL, hvor ESNI ikke officielt understøttes.

Derfor har vi besluttet at skabe vores front-end komponent (ESNI reverse proxy), som understøtter TLS 1.3 terminering med ESNI og HTTP(S) trafik proxying til upstream, der ikke understøtter ESNI. Dette muliggør anvendelse af teknologien i en eksisterende infrastruktur uden at ændre de grundlæggende komponenter - det vil sige, at vi kan bruge nuværende webservere, der ikke understøtter ESNI. 

For klarhedens skyld præsenterer vi en skitse:

Hvordan beskytter man sin offentlige hjemmeside med ESNI

Jeg vil bemærke, at proxyen blev designet med muligheden for at terminere TLS-forbindelsen uden ESNI for at støtte klienter uden ESNI. Derudover kan kommunikationsprotokollen med upstream være både HTTP og HTTPS med en TLS-version lavere end 1.3 (hvis upstream ikke understøtter 1.3). Denne skitse giver maksimal fleksibilitet.

Implementeringen af ESNI-støtte på go har vi lånt fra CloudFlare. Jeg skal straks bemærke, at selve implementeringen er ret ikke-triviel, da den involverer ændringer i standardbiblioteket crypto/tls og kræver derfor "patching" GOROOT før opbygning.

Til generering af ESNI-nøgler brugte vi esnitool (også et produkt fra CloudFlare). Disse nøgler bruges til kryptering/dekryptering af SNI.
Vi har testet opbygningen med go 1.13 på Linux (Debian, Alpine) og MacOS. 

Et par ord om driftsmæssige særheder.

ESNI reverse proxy giver metrics i Prometheus-format, såsom rps, upstream latenstid & svarskoder, fejlede / lykkedes TLS håndtryk & varighed af TLS håndtryk. Ved første øjekast så det ud til at være tilstrækkeligt til at vurdere, hvordan proxyen håndterer trafikken. 

Desuden udførte vi belastningstest inden brug. Resultaterne er nedenfor:

wrk -t50 -c1000 -d360s 'https://esni-rev-proxy.npw:443' --timeout 15s
Kører 6m test @ https://esni-rev-proxy.npw:443
  50 tråde og 1000 forbindelser
  Tråd Statistik   Gennemsnit     Stdev     Max    +/− Stdev
    Latens     1.77s     1.21s    7.20s    65.43%
    Req/Sek    13.78      8.84   140.00     83.70%
  206357 anmodninger i 6.00m, 6.08GB læst
Anmodninger/s:    573.07
Overførsel/s:     17.28MB 

Vi gennemførte belastningstest til ren kvalitetsændring for at sammenligne skemaer med og uden brug af ESNI reverse proxy. Vi "fødte" trafik lokalt for at udelukke "forstyrrelser" i mellemliggende komponenter.

Så med ESNI støtte og proxiering til upstream med HTTP, opnåede vi omkring ~ 550 rps fra én instans, mens den gennemsnitlige CPU/RAM for ESNI reverse proxy var:

  • 80% CPU-brug (4 vCPU, 4 GB RAM værter, Linux)
  • 130 MB Mem RSS

Hvordan beskytter man sin offentlige hjemmeside med ESNI

Til sammenligning, RPS for den samme upstream nginx uden TLS terminering (HTTP-protokol) ~ 1100:

wrk -t50 -c1000 -d360s 'http://lb.npw:80' –-timeout 15s
Kører 6m test @ http://lb.npw:80
  50 tråde og 1000 forbindelser
  Tråd Statistik   Gennemsnit     Stdev     Max    +/− Stdev
    Latens     1.11s     2.30s   15.00s    90.94%
    Req/Sek    23.25     13.55   282.00     79.25%
  393093 anmodninger i 6.00m, 11.35GB læst
  Socket-fejl: connect 0, read 0, write 0, timeout 9555
  Non-2xx eller 3xx svar: 8111
Anmodninger/s:   1091.62
Overførsel/s:     32.27MB 

Tilstedeværelsen af timeouts indikerer, at der er mangel på ressourcer (vi brugte 4 vCPU, 4 GB RAM værter, Linux), og den potentielle RPS er højere (vi fik tal op til 2700 RPS på mere kraftfulde ressourcer).

Afslutningsvis vil jeg bemærke, at teknologien ESNI ser ganske lovende ud. Der er stadig mange åbne spørgsmål, såsom opbevaring af den offentlige ESNI-nøgle i DNS og rotation af ESNI-nøgler – disse spørgsmål er aktivt diskuteret, og den seneste version af udkastet (på tidspunktet for skrivning) ESNI er allerede 7.

Kilde: habr.com

Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere 🔥 Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster