Come proteggere il tuo sito pubblico con ESNI

Ciao Habr, sono Ilya, lavoro nel team di piattaforma di Exness. Sviluppiamo e implementiamo componenti infrastrutturali di base utilizzati dai nostri team di sviluppo prodotto.

In questo articolo vorrei condividere l'esperienza di implementazione della tecnologia SNI crittografato (ESNI) nell'infrastruttura dei siti web pubblici.

Come proteggere il tuo sito pubblico con ESNI

L'uso di questa tecnologia migliorerà il livello di sicurezza nella gestione di un sito web pubblico e consentirà di rispettare gli standard di sicurezza interni adottati dall'azienda.

Innanzitutto, voglio sottolineare che la tecnologia non è standardizzata e si trova ancora in fase di bozza, tuttavia CloudFlare e Mozilla la supportano già (in draft01). Questo ci ha motivato a condurre un esperimento simile.

Un po' di teoria

ESNI è un'estensione del protocollo TLS 1.3 che consente di crittografare l'SNI nel messaggio «Client Hello» del handshake TLS. Ecco come appare il Client Hello con supporto ESNI (invece del tradizionale SNI vediamo ESNI):

Come proteggere il tuo sito pubblico con ESNI

 Per utilizzare ESNI, sono necessari tre elementi:

  • DNS; 
  • Supporto da parte del client;
  • Supporto da parte del server.

DNS

È necessario aggiungere due record DNS – A, e TXT (La registrazione TXT contiene la chiave pubblica che il cliente può utilizzare per crittografare SNI) – vedi sotto. Inoltre, deve esserci supporto DoH (DNS over HTTPS), poiché i client disponibili (vedi sotto) non attivano il supporto ESNI senza DoH. Questo ha senso, poiché ESNI implica la crittografia del nome della risorsa a cui ci stiamo collegando, quindi non ha senso interrogare il DNS tramite UDP. Inoltre, l'uso della DNSSEC permette di proteggersi da attacchi di «cache poisoning» in questo scenario.

Attualmente sono disponibili diversi fornitori di DoH, tra cui:

CloudFlare afferma (Check My Browser → Encrypted SNI → Learn More) che i loro server già supportano ESNI, quindi per i server CloudFlare in DNS abbiamo almeno due registrazioni – A e TXT. Nell'esempio seguente, stiamo interrogando Google DNS (over HTTPS): 

E registrazione:

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 registrazione, la richiesta è formata secondo il modello _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."
}

Quindi, in termini di DNS, dovremmo utilizzare DoH (preferibilmente con DNSSEC) e aggiungere due record. 

Supporto da parte del client

Se parliamo di browser, attualmente il supporto è implementato solo in FireFox.. Qui È fornita una guida su come attivare il supporto per ESNI e DoH in FireFox. Una volta configurato il browser, dovremmo vedere un quadro simile a questo:

Come proteggere il tuo sito pubblico con ESNI

Collegamento per verificare il browser.

Naturalmente, per supportare ESNI deve essere utilizzato TLS 1.3, poiché ESNI è un'estensione di TLS 1.3.

Per testare il backend con supporto ESNI, abbiamo implementato un client in go, ma di questo parleremo più tardi.

Supporto da parte del server

Attualmente, ESNI non è supportato dai server web come nginx/apache, ecc., poiché funzionano con TLS tramite OpenSSL/BoringSSL, nei quali ESNI non è ufficialmente supportato.

Per questo motivo, abbiamo deciso di creare il nostro componente front-end (proxy inverso ESNI) che supporti la terminazione TLS 1.3 con ESNI e il proxying del traffico HTTP(S) verso un upstream che non supporta ESNI. Questo permette di applicare la tecnologia in un'infrastruttura già esistente, senza modificare i componenti principali, ovvero utilizzare i server web attuali che non supportano ESNI. 

A scopo dimostrativo, riportiamo lo schema:

Come proteggere il tuo sito pubblico con ESNI

Va notato che il proxy è stato concepito per terminare la connessione TLS senza ESNI, per supportare i clienti senza ESNI. Inoltre, il protocollo di comunicazione con l'upstream può essere sia HTTP che HTTPS con una versione TLS inferiore alla 1.3 (se l'upstream non supporta la 1.3). Questo schema offre la massima flessibilità.

L'implementazione del supporto ESNI su go l'abbiamo presa da CloudFlare. Sottolineo subito che l'implementazione stessa è piuttosto non banale, in quanto implica modifiche alla libreria standard crypto/tls e quindi richiede un 'patching' del GOROOT prima della compilazione.

Per generare le chiavi ESNI abbiamo utilizzato esnitool (anch'esso creato da CloudFlare). Queste chiavi sono utilizzate per la crittografia/decrittografia del SNI.
Abbiamo testato la compilazione utilizzando go 1.13 su Linux (Debian, Alpine) e MacOS. 

Una parola sulle caratteristiche operative

Il proxy inverso ESNI fornisce metriche nel formato Prometheus, come rps, latenza upstream & codici di risposta, handshake TLS riusciti/falliti & durata dell'handover TLS. A prima vista, ciò sembrava sufficiente per valutare come il proxy gestisce il traffico. 

Abbiamo anche effettuato test di carico prima dell'uso. I risultati sono riportati di seguito:

wrk -t50 -c1000 -d360s 'https://esni-rev-proxy.npw:443' --timeout 15s
Esecuzione del test di 6m @ https://esni-rev-proxy.npw:443
  50 thread e 1000 connessioni
  Statistiche sui thread   Avg      Stdev     Max   +/- Stdev
    Lat.     1.77s     1.21s    7.20s    65.43%
    Req/Sec    13.78      8.84   140.00     83.70%
  206357 richieste in 6.00m, 6.08GB letti
Richieste/sec:    573.07
Trasferimenti/sec:     17.28MB 

Abbiamo condotto i test di carico puramente qualitativi, per confrontare gli schemi usando il proxy inverso ESNI rispetto a senza. Abbiamo "iniettato" traffico localmente per escludere "interferenze" negli elementi intermedi.

Quindi, con il supporto ESNI e il proxying verso l'upstream tramite HTTP, abbiamo ottenuto circa ~ 550 rps da un'istanza, con un consumo medio di CPU/RAM del proxy inverso ESNI:

  • 80% di utilizzo della CPU (4 vCPU, host da 4 GB di RAM, Linux)
  • 130 MB Mem RSS

Come proteggere il tuo sito pubblico con ESNI

A titolo di confronto, RPS per lo stesso upstream nginx senza terminazione TLS (protocollo HTTP) è ~ 1100:

wrk -t50 -c1000 -d360s 'http://lb.npw:80' –-timeout 15s
Running 6m test @ http://lb.npw:80
  50 thread e 1000 connessioni
  Statistiche sui thread   Media      Deviazione   Massimo   +/- Deviazione
    Latenza     1.11s     2.30s   15.00s    90.94%
    Richieste/sec    23.25     13.55   282.00     79.25%
  393093 richieste in 6.00m, 11.35GB letti
  Errori di socket: connessione 0, lettura 0, scrittura 0, timeout 9555
  Risposte non-2xx o 3xx: 8111
Richieste/sec:   1091.62
Trasferimento/sec:     32.27MB 

La presenza di timeout indica una mancanza di risorse (abbiamo utilizzato host con 4 vCPU e 4 GB di RAM, Linux), e di fatto il potenziale RPS è più alto (abbiamo ottenuto cifre fino a 2700 RPS su risorse più potenti).

In conclusione, segnalo che la tecnologia ESNI appare piuttosto promettente. Ci sono ancora molte questioni aperte, come la memorizzazione della chiave ESNI pubblica nel DNS e la rotazione delle chiavi ESNI – queste questioni sono attivamente discusse, e l'ultima versione della bozza (al momento della scrittura) di ESNI è già 7.

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster