Bună Habr, mă numesc Ilya, lucrez în echipa platformei de la Exness. Dezvoltăm și implementăm componentele de bază ale infrastructurii pe care le folosesc echipele noastre de dezvoltare a produselor.
În acest articol, aș dori să împărtășesc experiența mea de implementare a tehnologiei SNI criptate (ESNI) în infrastructura site-urilor web publice.
Utilizarea acestei tehnologii va crește nivelul de securitate atunci când lucrați cu un site web public și va respecta standardele de securitate internă adoptate de Companie.
În primul rând, aș dori să subliniez că tehnologia nu este standardizată și este încă în proiect, dar CloudFlare și Mozilla o susțin deja (în
Un pic de teorie
ESNI este o extensie a protocolului TLS 1.3 care permite criptarea SNI în mesajul de strângere de mână TLS „Client Hello”. Iată cum arată Client Hello cu suport ESNI (în loc de SNI obișnuit vedem ESNI):
Pentru a utiliza ESNI, aveți nevoie de trei componente:
- DNS;
- Suport pentru clienți;
- Suport pe partea serverului.
DNS
Trebuie să adăugați două înregistrări DNS - Ași TXT (Înregistrarea TXT conține cheia publică cu care clientul poate cripta SNI) - vezi mai jos. În plus, trebuie să existe sprijin DOH (DNS prin HTTPS) deoarece clienții disponibili (vezi mai jos) nu activează suportul ESNI fără DoH. Acest lucru este logic, deoarece ESNI implică criptarea numelui resursei pe care o accesăm, adică nu are sens să accesăm DNS prin UDP. Mai mult, utilizarea
Disponibil acum
Cloudflare
А intrare:
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 înregistrare, cererea este generată conform unui șablon _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."
}
Deci, din perspectiva DNS, ar trebui să folosim DoH (de preferință cu DNSSEC) și să adăugăm două intrări.
Relații Clienți
Dacă vorbim despre browsere, atunci în acest moment
Desigur, TLS 1.3 trebuie utilizat pentru a susține ESNI, deoarece ESNI este o extensie a TLS 1.3.
În scopul testării backend-ului cu suport ESNI, am implementat clientul pe go, Dar mai multe despre asta mai târziu.
Suport pe partea serverului
În prezent, ESNI nu este acceptat de servere web precum nginx/apache etc., deoarece funcționează cu TLS prin OpenSSL/BoringSSL, care nu acceptă oficial ESNI.
Prin urmare, am decis să creăm propria noastră componentă front-end (ESNI reverse proxy), care ar suporta terminarea TLS 1.3 cu ESNI și trafic HTTP(S) proxy către upstream, care nu acceptă ESNI. Acest lucru permite ca tehnologia să fie utilizată într-o infrastructură deja existentă, fără a modifica componentele principale - adică folosind servere web actuale care nu acceptă ESNI.
Pentru claritate, iată o diagramă:
Observ că proxy-ul a fost conceput cu capacitatea de a termina o conexiune TLS fără ESNI, pentru a sprijini clienții fără ESNI. De asemenea, protocolul de comunicare cu upstream poate fi fie HTTP, fie HTTPS cu o versiune TLS mai mică decât 1.3 (dacă upstream nu acceptă 1.3). Această schemă oferă flexibilitate maximă.
Implementarea sprijinului ESNI pe go am împrumutat de la
Pentru a genera cheile ESNI am folosit
Am testat construcția folosind go 1.13 pe Linux (Debian, Alpine) și MacOS.
Câteva cuvinte despre caracteristicile operaționale
Proxy-ul invers ESNI oferă valori în format Prometheus, cum ar fi rps, coduri de latență și răspuns în amonte, strângeri de mână TLS nereușite/reușite și durata strângerii de mână TLS. La prima vedere, acest lucru părea suficient pentru a evalua modul în care proxy-ul gestionează traficul.
De asemenea, am efectuat teste de sarcină înainte de utilizare. Rezultate mai jos:
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
Am efectuat teste de încărcare pur calitative pentru a compara schema folosind proxy invers ESNI și fără. Am „turnat” trafic local pentru a elimina „interferența” în componentele intermediare.
Deci, cu suport ESNI și proxy upstream de la HTTP, am primit aproximativ 550 rps dintr-o singură instanță, cu consumul mediu CPU/RAM al proxy-ului invers ESNI:
- 80% utilizare CPU (4 vCPU, 4 GB RAM gazde, Linux)
- 130 MB Mem RSS
Pentru comparație, RPS pentru același nginx în amonte fără terminarea TLS (protocol HTTP) este de ~ 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
Prezența timeout-urilor indică lipsa resurselor (am folosit 4 vCPU, 4 GB RAM gazde, Linux), iar de fapt potențialul RPS este mai mare (am primit cifre de până la 2700 RPS pe resurse mai puternice).
In concluzie, notez că tehnologia ESNI pare destul de promițătoare. Există încă multe întrebări deschise, de exemplu, problemele stocării cheii ESNI publice în DNS și rotația cheilor ESNI - aceste probleme sunt discutate activ, iar cea mai recentă versiune a proiectului ESNI (la momentul scrierii) este deja
Sursa: www.habr.com