Slik beskytter du din offentlige nettside med ESNI

Hei Habr, jeg heter Ilya, jeg jobber i plattformteamet hos Exness. Vi utvikler og implementerer kjerneinfrastrukturkomponentene som produktutviklingsteamene våre bruker.

I denne artikkelen vil jeg dele min erfaring med å implementere kryptert SNI (ESNI) teknologi i infrastrukturen til offentlige nettsteder.

Slik beskytter du din offentlige nettside med ESNI

Bruken av denne teknologien vil øke sikkerhetsnivået når du arbeider med et offentlig nettsted og overholde interne sikkerhetsstandarder vedtatt av selskapet.

Først av alt vil jeg påpeke at teknologien ikke er standardisert og fortsatt er i utkastet, men CloudFlare og Mozilla støtter den allerede (i utkast 01). Dette motiverte oss for et slikt eksperiment.

Litt teori

ESNI er en utvidelse til TLS 1.3-protokollen som tillater SNI-kryptering i TLS-håndtrykket "Client Hello"-meldingen. Slik ser Client Hello ut med ESNI-støtte (i stedet for den vanlige SNI ser vi ESNI):

Slik beskytter du din offentlige nettside med ESNI

 For å bruke ESNI trenger du tre komponenter:

  • DNS; 
  • Kundestøtte;
  • Støtte på serversiden.

DNS

Du må legge til to DNS-poster – AOg TXT (TXT-posten inneholder den offentlige nøkkelen som klienten kan kryptere SNI med) - se nedenfor. I tillegg må det være støtte Doh (DNS over HTTPS) fordi tilgjengelige klienter (se nedenfor) ikke aktiverer ESNI-støtte uten DoH. Dette er logisk, siden ESNI innebærer kryptering av navnet på ressursen vi har tilgang til, det vil si at det ikke gir noen mening å få tilgang til DNS over UDP. Dessuten bruken DNSSEC lar deg beskytte mot cache-forgiftningsangrep i dette scenariet.

Tilgjengelig for øyeblikket flere DoH-leverandører, blant dem:

CloudFlare stater (Sjekk Min nettleser → Kryptert SNI → Lær mer) at deres servere allerede støtter ESNI, det vil si at for CloudFlare-servere i DNS har vi minst to poster - A og TXT. I eksemplet nedenfor spør vi Google DNS (over HTTPS): 

А inngang:

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ørsel genereres i henhold til en mal _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 bruke DoH (helst med DNSSEC) og legge til to oppføringer. 

Kundeservice

Hvis vi snakker om nettlesere, så for øyeblikket støtte implementeres kun i FireFox. Her Her er instruksjoner om hvordan du aktiverer ESNI- og DoH-støtte i FireFox. Etter at nettleseren er konfigurert, bør vi se noe slikt:

Slik beskytter du din offentlige nettside med ESNI

Ссылка for å sjekke nettleseren.

Selvfølgelig må TLS 1.3 brukes for å støtte ESNI, siden ESNI er en utvidelse til TLS 1.3.

For det formål å teste backend med ESNI-støtte, implementerte vi klienten på go, Men mer om det senere.

Støtte på serversiden

Foreløpig støttes ikke ESNI av webservere som nginx/apache, etc., siden de jobber med TLS via OpenSSL/BoringSSL, som ikke offisielt støtter ESNI.

Derfor bestemte vi oss for å lage vår egen front-end-komponent (ESNI omvendt proxy), som ville støtte TLS 1.3-terminering med ESNI og proxy HTTP(S)-trafikk til oppstrøms, som ikke støtter ESNI. Dette gjør at teknologien kan brukes i en allerede eksisterende infrastruktur, uten å endre hovedkomponentene – det vil si å bruke nåværende webservere som ikke støtter ESNI. 

For klarhet, her er et diagram:

Slik beskytter du din offentlige nettside med ESNI

Jeg legger merke til at proxyen ble designet med muligheten til å avslutte en TLS-tilkobling uten ESNI, for å støtte klienter uten ESNI. Kommunikasjonsprotokollen med oppstrøm kan også være enten HTTP eller HTTPS med en TLS-versjon lavere enn 1.3 (hvis oppstrøms ikke støtter 1.3). Denne ordningen gir maksimal fleksibilitet.

Implementering av ESNI-støtte på go vi lånte fra CloudFlare. Jeg vil merke med en gang at selve implementeringen er ganske ikke-triviell, siden den innebærer endringer i standardbiblioteket krypto/tls og krever derfor "patching" GOROOT før montering.

For å generere ESNI-nøkler brukte vi esnitool (også ideen til CloudFlare). Disse nøklene brukes til SNI-kryptering/dekryptering.
Vi testet bygget med go 1.13 på Linux (Debian, Alpine) og MacOS. 

Noen få ord om operasjonelle funksjoner

ESNI omvendt proxy gir beregninger i Prometheus-format, for eksempel rps, oppstrøms latens og svarkoder, mislykkede/vellykkede TLS-håndtrykk og TLS-håndtrykkvarighet. Ved første øyekast virket dette tilstrekkelig til å evaluere hvordan proxyen håndterer trafikk. 

Vi utførte også lasttesting før bruk. 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 utførte rent kvalitativ lasttesting for å sammenligne ordningen med ESNI omvendt proxy og uten. Vi "hellte" trafikk lokalt for å eliminere "interferens" i mellomkomponenter.

Så, med ESNI-støtte og proxying til oppstrøms fra HTTP, fikk vi rundt ~550 rps fra en forekomst, med gjennomsnittlig CPU/RAM-forbruk av ESNI reverse proxy:

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

Slik beskytter du din offentlige nettside med ESNI

Til sammenligning er RPS for samme nginx oppstrøms uten TLS (HTTP-protokoll)-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 av tidsavbrudd indikerer at det er mangel på ressurser (vi brukte 4 vCPUer, 4 GB RAM-verter, Linux), og faktisk er potensialet RPS høyere (vi mottok tall på opptil 2700 RPS på kraftigere ressurser).

Avslutningsvis bemerker jeg at ESNI-teknologien ser ganske lovende ut. Det er fortsatt mange åpne spørsmål, for eksempel spørsmålene om lagring av den offentlige ESNI-nøkkelen i DNS og roterende ESNI-nøkler - disse spørsmålene diskuteres aktivt, og den siste versjonen av ESNI-utkastet (i skrivende stund) er allerede 7.

Kilde: www.habr.com

Legg til en kommentar