Sådan beskytter du dit offentlige websted med ESNI

Hej Habr, mit navn er Ilya, jeg arbejder i platformsteamet hos Exness. Vi udvikler og implementerer de kerneinfrastrukturkomponenter, som vores produktudviklingsteams bruger.

I denne artikel vil jeg gerne dele min erfaring med at implementere krypteret SNI (ESNI) teknologi i infrastrukturen på offentlige hjemmesider.

Sådan beskytter du dit offentlige websted med ESNI

Brugen af ​​denne teknologi vil øge sikkerhedsniveauet, når du arbejder med et offentligt websted og overholde interne sikkerhedsstandarder vedtaget af virksomheden.

Først og fremmest vil jeg gerne påpege, at teknologien ikke er standardiseret og stadig er under udkast, men CloudFlare og Mozilla understøtter det allerede (i udkast 01). Dette motiverede os til et sådant eksperiment.

Lidt teori

ESNI er en udvidelse til TLS 1.3-protokollen, der tillader SNI-kryptering i TLS-håndtrykket "Client Hello"-meddelelsen. Her er, hvordan Client Hello ser ud med ESNI-support (i stedet for den sædvanlige SNI ser vi ESNI):

Sådan beskytter du dit offentlige websted med ESNI

 For at bruge ESNI skal du bruge tre komponenter:

  • DNS; 
  • Kundesupport;
  • Support på serversiden.

DNS

Du skal tilføje to DNS-poster – AOg TXT (TXT-posten indeholder den offentlige nøgle, som klienten kan kryptere SNI med) - se nedenfor. Derudover skal der være opbakning DoH (DNS over HTTPS), fordi tilgængelige klienter (se nedenfor) ikke aktiverer ESNI-understøttelse uden DoH. Dette er logisk, da ESNI indebærer kryptering af navnet på den ressource, vi har adgang til, det vil sige, det giver ingen mening at få adgang til DNS over UDP. Desuden brugen DNSSEC giver dig mulighed for at beskytte mod cache-forgiftningsangreb i dette scenarie.

Tilgængelig i øjeblikket flere DoH-udbydere, blandt dem:

CloudFlare stater (Tjek Min browser → Krypteret SNI → Lær mere), at deres servere allerede understøtter ESNI, det vil sige, for CloudFlare-servere i DNS har vi mindst to poster - A og TXT. I eksemplet nedenfor forespørger vi Google DNS (over HTTPS): 

А indgang:

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 record, anmodning genereres i henhold til en skabelon _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 bør vi bruge DoH (helst med DNSSEC) og tilføje to poster. 

Kunde support

Hvis vi taler om browsere, så pt support er kun implementeret i FireFox. Her Her er instruktioner om, hvordan du aktiverer ESNI og DoH support i FireFox. Efter at browseren er konfigureret, skulle vi se noget som dette:

Sådan beskytter du dit offentlige websted med ESNI

Link for at tjekke browseren.

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

Med det formål at teste backend med ESNI support implementerede vi klienten på go, Men mere om det senere.

Support på serversiden

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

Derfor besluttede vi at oprette vores egen front-end-komponent (ESNI reverse proxy), som ville understøtte TLS 1.3-terminering med ESNI og proxy HTTP(S)-trafik til upstream, som ikke understøtter ESNI. Dette gør det muligt at bruge teknologien i en allerede eksisterende infrastruktur uden at ændre på hovedkomponenterne – altså ved at bruge nuværende webservere, der ikke understøtter ESNI. 

For klarhedens skyld er her et diagram:

Sådan beskytter du dit offentlige websted med ESNI

Jeg bemærker, at proxyen er designet med mulighed for at afslutte en TLS-forbindelse uden ESNI, for at understøtte klienter uden ESNI. Kommunikationsprotokollen med upstream kan også være enten HTTP eller HTTPS med en TLS-version lavere end 1.3 (hvis upstream ikke understøtter 1.3). Denne ordning giver maksimal fleksibilitet.

Implementering af ESNI-støtte vedr go vi lånte fra CloudFlare. Jeg vil gerne bemærke med det samme, at selve implementeringen er ret ikke-triviel, da den involverer ændringer i standardbiblioteket krypto/tls og kræver derfor "patching" GOROOT før montering.

Til at generere ESNI-nøgler brugte vi esnitool (også udtænkt af CloudFlare). Disse nøgler bruges til SNI-kryptering/dekryptering.
Vi testede bygningen med go 1.13 på Linux (Debian, Alpine) og MacOS. 

Et par ord om operationelle funktioner

ESNI omvendt proxy giver metrics i Prometheus-format, såsom rps, upstream latency & svarkoder, mislykkede/vellykkede TLS-håndtryk og TLS-håndtryk varighed. Ved første øjekast virkede dette tilstrækkeligt til at evaluere, hvordan proxyen håndterer trafik. 

Vi udførte også belastningstest før brug. Resultater nedenfor:

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 

Vi udførte rent kvalitativ belastningstest for at sammenligne ordningen ved hjælp af ESNI omvendt proxy og uden. Vi "hældte" trafik lokalt for at eliminere "interferens" i mellemkomponenter.

Så med ESNI-understøttelse og proxying til upstream med HTTP, fik vi omkring ~550 rps fra én instans med det gennemsnitlige CPU/RAM-forbrug af ESNI reverse proxy:

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

Sådan beskytter du dit offentlige websted med ESNI

Til sammenligning er RPS for den samme nginx opstrøms uden TLS (HTTP-protokol)-terminering ~ 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 

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

Afslutningsvis bemærker jeg at ESNI-teknologien ser ret lovende ud. Der er stadig mange åbne spørgsmål, for eksempel spørgsmålene om lagring af en offentlig ESNI-nøgle i DNS og roterende ESNI-nøgler - disse spørgsmål diskuteres aktivt, og den seneste version af ESNI-udkastet (i skrivende stund) er allerede 7.

Kilde: www.habr.com

Tilføj en kommentar