Ciao Habr, mi chiamo Ilya, lavoro nel team della piattaforma di Exness. Sviluppiamo e implementiamo i componenti principali dell'infrastruttura utilizzati dai nostri team di sviluppo prodotto.
In questo articolo vorrei condividere la mia esperienza nell'implementazione della tecnologia SNI crittografata (ESNI) nell'infrastruttura dei siti Web pubblici.
L'uso di questa tecnologia aumenterà il livello di sicurezza quando si lavora con un sito Web pubblico e sarà conforme agli standard di sicurezza interni adottati dalla Società.
Innanzitutto vorrei sottolineare che la tecnologia non è standardizzata ed è ancora in bozza, ma CloudFlare e Mozilla già la supportano (in
Un po 'di teoria
ESNI è un'estensione del protocollo TLS 1.3 che consente la crittografia SNI nel messaggio "Client Hello" dell'handshake TLS. Ecco come appare Client Hello con il supporto ESNI (al posto del solito SNI vediamo ESNI):
Per utilizzare ESNI sono necessari tre componenti:
- DNS;
- Supporto al cliente;
- Supporto lato server.
DNS
Devi aggiungere due record DNS: AE TXT (Il record TXT contiene la chiave pubblica con cui il client può crittografare SNI) - vedere di seguito. Inoltre, deve esserci supporto DoH (DNS su HTTPS) perché i client disponibili (vedi sotto) non abilitano il supporto ESNI senza DoH. Questo è logico, poiché ESNI implica la crittografia del nome della risorsa a cui accediamo, ovvero non ha senso accedere al DNS tramite UDP. Inoltre, l'uso
Attualmente disponibile
CloudFlare
А 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 viene generata secondo un 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, dal punto di vista DNS, dovremmo utilizzare DoH (preferibilmente con DNSSEC) e aggiungere due voci.
Servizio Clienti
Se stiamo parlando di browser, al momento
Naturalmente, TLS 1.3 deve essere utilizzato per supportare ESNI, poiché ESNI è un'estensione di TLS 1.3.
Allo scopo di testare il backend con il supporto ESNI, abbiamo implementato il client su go, Ma ne parleremo più avanti.
Supporto lato server
Attualmente, ESNI non è supportato da server web come nginx/apache, ecc., poiché funzionano con TLS tramite OpenSSL/BoringSSL, che non supportano ufficialmente ESNI.
Pertanto, abbiamo deciso di creare il nostro componente front-end (proxy inverso ESNI), che supporterebbe la terminazione TLS 1.3 con ESNI e il traffico proxy HTTP(S) verso l'upstream, che non supporta ESNI. Ciò consente di utilizzare la tecnologia in un'infrastruttura già esistente, senza modificare i componenti principali, ovvero utilizzando gli attuali server Web che non supportano ESNI.
Per chiarezza ecco uno schema:
Prendo atto che il proxy è stato progettato con la possibilità di terminare una connessione TLS senza ESNI, per supportare i client senza ESNI. Inoltre, il protocollo di comunicazione con upstream può essere HTTP o HTTPS con una versione TLS inferiore a 1.3 (se upstream non supporta 1.3). Questo schema offre la massima flessibilità.
Attuazione del supporto ESNI su go abbiamo preso in prestito da
Per generare le chiavi ESNI abbiamo utilizzato
Abbiamo testato la build utilizzando go 1.13 su Linux (Debian, Alpine) e MacOS.
Qualche parola sulle caratteristiche operative
Il proxy inverso ESNI fornisce metriche in formato Prometheus, come rps, latenza upstream e codici di risposta, handshake TLS non riusciti/riusciti e durata dell'handshake TLS. A prima vista, questo sembrava sufficiente per valutare come il proxy gestisce il traffico.
Abbiamo anche eseguito test di carico prima dell'uso. Risultati di seguito:
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
Abbiamo effettuato test di carico puramente qualitativi per confrontare lo schema utilizzando il proxy inverso ESNI e senza. Abbiamo "versato" il traffico localmente per eliminare le "interferenze" nei componenti intermedi.
Quindi, con il supporto ESNI e il proxy upstream da HTTP, abbiamo ottenuto circa 550 rps da un'istanza, con il consumo medio di CPU/RAM del proxy inverso ESNI:
- Utilizzo della CPU all'80% (4 vCPU, host RAM da 4 GB, Linux)
- RSS di memoria da 130 MB
Per fare un confronto, l'RPS per lo stesso nginx upstream senza terminazione TLS (protocollo HTTP) è ~ 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
La presenza di timeout indica che mancano risorse (abbiamo utilizzato 4 vCPU, host 4 GB RAM, Linux), ed infatti il potenziale RPS è più alto (abbiamo ricevuto cifre fino a 2700 RPS su risorse più potenti).
In conclusione, prendo atto che la tecnologia ESNI sembra piuttosto promettente. Ci sono ancora molte domande aperte, ad esempio le questioni relative alla memorizzazione della chiave ESNI pubblica nel DNS e alla rotazione delle chiavi ESNI: queste questioni vengono discusse attivamente e l'ultima versione della bozza ESNI (al momento in cui scrivo) è già
Fonte: habr.com