Hoe u uw openbare website kunt beschermen met ESNI

Hallo Habr, mijn naam is Ilya, ik werk in het platformteam bij Exness. We ontwikkelen en implementeren de kerninfrastructuurcomponenten die onze productontwikkelingsteams gebruiken.

In dit artikel wil ik mijn ervaringen delen met het implementeren van gecodeerde SNI (ESNI)-technologie in de infrastructuur van openbare websites.

Hoe u uw openbare website kunt beschermen met ESNI

Het gebruik van deze technologie zal het beveiligingsniveau verhogen bij het werken met een openbare website en voldoen aan de interne beveiligingsnormen die door het bedrijf zijn aangenomen.

Allereerst wil ik erop wijzen dat de technologie niet gestandaardiseerd is en nog in de conceptfase zit, maar dat CloudFlare en Mozilla deze al ondersteunen (in ontwerp01). Dit motiveerde ons voor een dergelijk experiment.

Een beetje theorie

ESNI is een uitbreiding op het TLS 1.3-protocol dat SNI-codering mogelijk maakt in het TLS-handshakebericht "Client Hallo". Zo ziet Client Hello eruit met ESNI-ondersteuning (in plaats van de gebruikelijke SNI zien we ESNI):

Hoe u uw openbare website kunt beschermen met ESNI

 Om ESNI te gebruiken, heb je drie componenten nodig:

  • DNS; 
  • Klantenondersteuning;
  • Ondersteuning aan serverzijde.

DNS

U moet twee DNS-records toevoegen: AEn TXT (Het TXT-record bevat de openbare sleutel waarmee de client SNI kan coderen) - zie hieronder. Bovendien moet er draagvlak zijn DoH (DNS via HTTPS) omdat beschikbare clients (zie hieronder) ESNI-ondersteuning niet inschakelen zonder DoH. Dit is logisch, aangezien ESNI versleuteling impliceert van de naam van de bron waartoe we toegang hebben, dat wil zeggen dat het geen zin heeft om toegang te krijgen tot DNS via UDP. Bovendien het gebruik DNSSEC stelt u in dit scenario in staat bescherming te bieden tegen cache-vergiftigingsaanvallen.

Nu verkrijgbaar verschillende DoH-aanbieders, onder hen:

CloudFlare staten (Controleer Mijn browser → Gecodeerde SNI → Meer informatie) dat hun servers ESNI al ondersteunen, dat wil zeggen dat we voor CloudFlare-servers in de DNS ten minste twee records hebben: A en TXT. In het onderstaande voorbeeld vragen we Google DNS (via HTTPS): 

А invoer:

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, aanvraag wordt gegenereerd volgens een sjabloon _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."
}

Vanuit DNS-perspectief moeten we dus DoH gebruiken (bij voorkeur met DNSSEC) en twee vermeldingen toevoegen. 

Klantenservice

Als we het over browsers hebben, dan op dit moment ondersteuning is alleen geïmplementeerd in FireFox. Hier Hier vindt u instructies voor het activeren van ESNI- en DoH-ondersteuning in FireFox. Nadat de browser is geconfigureerd, zouden we zoiets als dit moeten zien:

Hoe u uw openbare website kunt beschermen met ESNI

Link om de browser te controleren.

Uiteraard moet TLS 1.3 worden gebruikt om ESNI te ondersteunen, aangezien ESNI een uitbreiding is op TLS 1.3.

Om de backend met ESNI-ondersteuning te testen, hebben we de client geïmplementeerd go, Maar daarover later meer.

Ondersteuning aan serverzijde

Momenteel wordt ESNI niet ondersteund door webservers zoals nginx/apache etc., omdat deze met TLS werken via OpenSSL/BoringSSL, die ESNI officieel niet ondersteunen.

Daarom hebben we besloten om onze eigen front-endcomponent (ESNI reverse proxy) te maken, die TLS 1.3-beëindiging met ESNI en proxy HTTP(S)-verkeer naar de upstream zou ondersteunen, wat ESNI niet ondersteunt. Hierdoor kan de technologie worden gebruikt in een reeds bestaande infrastructuur, zonder de hoofdcomponenten te veranderen – dat wil zeggen met behulp van huidige webservers die ESNI niet ondersteunen. 

Voor de duidelijkheid, hier is een diagram:

Hoe u uw openbare website kunt beschermen met ESNI

Ik merk op dat de proxy is ontworpen met de mogelijkheid om een ​​TLS-verbinding zonder ESNI te beëindigen, om klanten zonder ESNI te ondersteunen. Bovendien kan het communicatieprotocol met upstream HTTP of HTTPS zijn met een TLS-versie lager dan 1.3 (als upstream 1.3 niet ondersteunt). Deze regeling biedt maximale flexibiliteit.

Implementatie van ESNI-ondersteuning op go wij hebben geleend van CloudFlare. Ik wil meteen opmerken dat de implementatie zelf nogal niet triviaal is, omdat het veranderingen in de standaardbibliotheek met zich meebrengt crypto/tls en vereist daarom “patching” GOROOT voor montage.

Om ESNI-sleutels te genereren die we hebben gebruikt esnitool (ook het geesteskind van CloudFlare). Deze sleutels worden gebruikt voor SNI-codering/decodering.
We hebben de build getest met go 1.13 op Linux (Debian, Alpine) en MacOS. 

Een paar woorden over operationele kenmerken

ESNI reverse proxy biedt statistieken in Prometheus-formaat, zoals rps, upstream latentie- en responscodes, mislukte/succesvolle TLS-handshakes en TLS-handshake-duur. Op het eerste gezicht leek dit voldoende om te evalueren hoe de proxy omgaat met verkeer. 

We hebben vóór gebruik ook belastingtests uitgevoerd. Resultaten hieronder:

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 

We hebben puur kwalitatieve belastingtests uitgevoerd om het schema te vergelijken met ESNI reverse proxy en zonder. We hebben het verkeer lokaal "gegoten" om "interferentie" in tussenliggende componenten te elimineren.

Dus met ESNI-ondersteuning en proxying upstream van HTTP haalden we ongeveer ~550 rps uit één exemplaar, met het gemiddelde CPU/RAM-verbruik van ESNI reverse proxy:

  • 80% CPU-gebruik (4 vCPU, 4 GB RAM-hosts, Linux)
  • 130 MB RSS-geheugen

Hoe u uw openbare website kunt beschermen met ESNI

Ter vergelijking: de RPS voor dezelfde nginx upstream zonder TLS-beëindiging (HTTP-protocol) is ~ 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 

De aanwezigheid van time-outs geeft aan dat er een gebrek aan bronnen is (we gebruikten 4 vCPU's, 4 GB RAM-hosts, Linux), en in feite is de potentiële RPS hoger (we ontvingen cijfers tot 2700 RPS op krachtigere bronnen).

Concluderend merk ik op dat de ESNI-technologie er veelbelovend uitziet. Er zijn nog steeds veel open vragen, bijvoorbeeld de kwesties van het opslaan van de openbare ESNI-sleutel in de DNS en het roteren van ESNI-sleutels - deze kwesties worden actief besproken en de nieuwste versie van het ESNI-concept (op het moment van schrijven) is al beschikbaar. 7.

Bron: www.habr.com

Voeg een reactie