Come proteggere il proprio sito pubblico con ESNI

Ciao Habr, mi chiamo Ilya e 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 dell'implementazione della tecnologia encrypted SNI (ESNI) nell'infrastruttura dei siti web pubblici.

Come proteggere il proprio sito pubblico con ESNI

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

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

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 (anziché il consueto SNI vediamo ESNI):

Come proteggere il proprio sito pubblico con ESNI

 Per utilizzare ESNI sono necessarie tre componenti:

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

DNS

È necessario aggiungere due record DNS – A, e TXT (il record TXT contiene la chiave pubblica con cui il client può crittografare l'SNI) – vedi sotto. Inoltre, è necessario supportare DoH (DNS over HTTPS), poiché i client disponibili (vedi sotto) non attivano il supporto ESNI senza DoH. Questo è logico, poiché ESNI implica la crittografia del nome della risorsa a cui accediamo, il che rende privo di senso consultare il DNS tramite UDP. Inoltre, l'uso di DNSSEC permette di proteggersi da attacchi di 'cache poisoning' in questo scenario.

Attualmente sono disponibili diversi fornitori DoH, tra cui:

CloudFlare afferma (Controlla il mio browser → SNI crittografato → Scopri di più), i cui server attualmente supportano ESNI, il che significa che per i server CloudFlare nel DNS abbiamo almeno due record – A e TXT. Nell'esempio sottostante richiediamo Google DNS (via HTTPS): 

A record:

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, la richiesta è formulata 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": "Risposta da 2400:cb00:2049:1::a29f:209."
}

Dunque, dal punto di vista del DNS, dobbiamo utilizzare DoH (preferibilmente con DNSSEC) e aggiungere due record. 

Supporto da parte del client

Se parliamo dei browser, attualmente il supporto è realizzato solo in Firefox. Qui qui di seguito è riportata l'istruzione su come attivare il supporto per ESNI e DoH in Firefox. Dopo aver configurato il browser, dovremmo vedere un'immagine simile a questa:

Come proteggere il proprio sito pubblico con ESNI

Link per testare il browser.

Ovviamente, per il supporto di ESNI deve essere utilizzato TLS 1.3, poiché ESNI è un'estensione di TLS 1.3.

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

Supporto da parte del server

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

Pertanto abbiamo deciso di creare un nostro componente front-end (ESNI reverse proxy) che supportasse la terminazione di TLS 1.3 con ESNI e il proxying del traffico HTTP(S) su upstream non supportante ESNI. Ciò consente 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 esemplificativo, presentiamo uno schema:

Come proteggere il proprio sito pubblico con ESNI

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

Abbiamo preso in prestito l'implementazione del supporto per ESNI da go . Vorrei sottolineare che l'implementazione stessa è piuttosto non banale, poiché implica modifiche alla libreria standard CloudFlarecrypto/tls crypto/tls GOROOT GOROOT Per generare le chiavi ESNI, abbiamo utilizzato

esnitool (anche questa è un'invenzione di CloudFlare). Queste chiavi vengono utilizzate per la crittografia/decrittografia SNI. Abbiamo testato la compilazione utilizzando go 1.13 su Linux (Debian, Alpine) e MacOS.
Una parola sulle caratteristiche operative 

Due parole sulle peculiarità operative

Il proxy reverso ESNI fornisce metriche nel formato Prometheus, come ad esempio rps, latenza upstream & codici di risposta, handshake TLS falliti/riusciti & durata dell'handshake TLS. A prima vista, questo sembrava sufficiente per valutare come il proxy gestisse il traffico. 

Prima di utilizzarlo, abbiamo anche condotto test di carico. I risultati sono riportati di seguito:

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

Abbiamo condotto il test di carico puramente qualitativo, per confrontare gli schemi di utilizzo del proxy reverso ESNI e senza. Abbiamo "inserito" traffico localmente per escludere "disturbi" nei componenti intermedi.

Pertanto, con il supporto per ESNI e il proxying upstream con HTTP, abbiamo ottenuto circa ~ 550 rps da un'istanza, con un consumo medio di CPU/RAM del proxy reverso ESNI:

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

Come proteggere il proprio 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
Esecuzione di un test di 6m @ http://lb.npw:80
  50 thread e 1000 connessioni
  Statistiche sui thread   Media      Deviazione    Max   +/- 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 4 vCPU, 4 GB di RAM, Linux), e di fatto il potenziale RPS è più alto (abbiamo ottenuto valori fino a 2700 RPS su risorse più potenti).

In conclusione, vorrei notare che la tecnologia ESNI sembra avere un buon potenziale. Ci sono ancora molte questioni aperte, ad esempio, la questione della memorizzazione della chiave ESNI pubblica nel DNS e il rotazione delle chiavi ESNI – queste questioni sono attivamente discusse, e l'ultima versione del draft (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