Hej Habr, jag heter Ilya och jag arbetar i plattformsteamet pÄ företaget Exness. Vi utvecklar och implementerar grundlÀggande infrastrukturella komponenter som vÄra produktutvecklingsteam anvÀnder.
I den hÀr artikeln skulle jag vilja dela med mig av erfarenheten av att implementera teknologin encrypted SNI (ESNI) i infrastrukturen för publika webbplatser.

AnvÀndningen av denna teknologi kommer att öka sÀkerhetsnivÄn vid arbete med publika webbplatser och uppfylla interna sÀkerhetsstandarder som antagits av företaget.
Först och frÀmst vill jag pÄpeka att teknologin inte Àr standardiserad och fortfarande Àr i utkast, men CloudFlare och Mozilla stöder den redan (i ). Det Àr vad som motiverade oss till detta experiment.
Lite teori
ESNI Àr en utvidgning av TLS 1.3-protokollet som möjliggör kryptering av SNI i meddelandet 'Client Hello' under TLS-handshake. SÄ hÀr ser 'Client Hello' ut med ESNI-stöd (istÀllet för det vanliga SNI ser vi ESNI):

 För att anvÀnda ESNI behövs tre komponenter:
- DNS;Â
- Klientstöd;
- Serverstöd.
DNS
TvĂ„ DNS-poster mĂ„ste lĂ€ggas till â A, och TXT (TXT-posten innehĂ„ller den offentliga nyckeln som klienten kan anvĂ€nda för att kryptera SNI) â se nedan. Dessutom mĂ„ste stöd för DoH (DNS over HTTPS) finnas, eftersom tillgĂ€ngliga klienter (se nedan) inte aktiverar ESNI-stöd utan DoH. Detta Ă€r logiskt, eftersom ESNI innebĂ€r kryptering av resursnamnet vi anropar, det vill sĂ€ga det Ă€r meningslöst att anropa DNS via UDP. Dessutom möjliggör anvĂ€ndningen av att skydda sig mot 'cache poisoning'-attacker i detta scenario.
För nÀrvarande finns det , bland dem:
CloudFlare (Check My Browser â Encrypted SNI â Learn More), att deras servrar redan nu stöder ESNI, det vill sĂ€ga för CloudFlare-servrar har vi minst tvĂ„ poster i DNS â A och TXT. I exemplet nedan anropar vi Google DNS (över HTTPS):Â
A post:
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, begÀran formuleras enligt mallen _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Ă„ ur ett DNS-perspektiv bör vi anvĂ€nda DoH (helst med DNSSEC) och lĂ€gga till tvĂ„ poster.Â
Support frÄn kunden
Om vi talar om webblÀsare, sÄ Àr det för nÀrvarande . hÀr Àr en instruktion för hur man aktiverar stöd för ESNI och DoH i FireFox. NÀr webblÀsaren Àr konfigurerad, bör vi se nÄgot i stil med:

för att kontrollera webblÀsaren.
SjÀlvklart mÄste TLS 1.3 anvÀndas för att stödja ESNI, eftersom ESNI Àr en tillÀgg till TLS 1.3.
För testÀndamÄl av backend med stöd för ESNI har vi implementerat en klient pÄ go, men mer om det senare.
Support frÄn servern
För nÀrvarande stöds inte ESNI av webbservrar som nginx/apache m.fl., eftersom de arbetar med TLS via OpenSSL/BoringSSL, dÀr ESNI inte officiellt stöds.
DĂ€rför har vi beslutat att skapa vĂ„r egen front-end-komponent (ESNI reverse proxy) som skulle stödja TLS 1.3-terminering med ESNI och proxy HTTP(S)-trafik till en upstream som inte stöder ESNI. Detta möjliggör anvĂ€ndning av teknologin i en redan etablerad infrastruktur, utan att förĂ€ndra grundkomponenterna â det vill sĂ€ga att anvĂ€nda nuvarande webbservrar som inte stöder ESNI.Â
För tydlighetens skull, hÀr Àr ett diagram:

Jag vill pÄpeka att proxyn designades för att kunna terminera TLS-anslutningar utan ESNI, för att stödja klienter som inte har ESNI. Dessutom kan protokollet för kommunikation med upstream vara bÄde HTTP och HTTPS med en TLS-version under 1.3 (om upstream inte stöder 1.3). Detta schema ger maximal flexibilitet.
Implementeringen av ESNI-support pÄ go har vi lÄnat frÄn . Jag vill genast pÄpeka att sjÀlva implementeringen Àr ganska icke-trivialiskt, eftersom den krÀver Àndringar i standardbiblioteket crypto/tls och dÀrför krÀver "patchning" GOROOT innan byggnation.
För att generera ESNI-nycklar anvÀnde vi (ocksÄ ett projekt frÄn CloudFlare). Dessa nycklar anvÀnds för kryptering/avkryptering av SNI.
Vi testade bygget med go 1.13 pĂ„ Linux (Debian, Alpine) och MacOS.Â
NÄgra ord om driftsÀkerhetsaspekter
ESNI reverse proxy erbjuder metrics i Prometheus-format, sĂ„som rps, upstream latens & responskoder, misslyckade/lyckade TLS-handshakes & TLS-handshake varaktighet. Vid första anblick sĂ„g detta tillrĂ€ckligt ut för att bedöma hur proxy klarar av trafiken.Â
Innan vi anvÀnde den genomförde vi Àven belastningstestning. Resultaten nedan:
wrk -t50 -c1000 -d360s 'https://esni-rev-proxy.npw:443' --timeout 15s
Kör 6m test @ https://esni-rev-proxy.npw:443
50 trÄdar och 1000 anslutningar
TrĂ„dstatistik Genomsnitt Stdev Max +/â Stdev
Latens 1.77s 1.21s 7.20s 65.43%
BegÀrningar/Sek 13.78 8.84 140.00 83.70%
206357 begÀrningar pÄ 6.00m, 6.08GB lÀsta
BegÀrningar/s: 573.07
Ăverföring/s: 17.28MB Vi genomförde belastningstestningen av rent kvalitativa skĂ€l, för att jĂ€mföra scheman med och utan ESNI reverse proxy. Vi "matade" trafiken lokalt för att utesluta "störningar" i mellanliggande komponenter.
SÄ, med stöd för ESNI och proxytjÀnst till upstream med HTTP, fick vi cirka ~ 550 rps frÄn en instans, medan den genomsnittliga CPU/RAM-anvÀndningen för ESNI reverse proxy:
- 80% CPU-anvÀndning (4 vCPU, 4 GB RAM-vÀrdar, Linux)
- 130 MB Mem RSS

I jÀmförelse, RPS för samma upstream nginx utan TLS-terminering (HTTP-protokoll) ~ 1100:
wrk -t50 -c1000 -d360s 'http://lb.npw:80' â-timeout 15s
Kör 6m test @ http://lb.npw:80
50 trÄdar och 1000 anslutningar
TrĂ„dstatistik Genomsnitt Stdev Max +/â Stdev
Latens 1.11s 2.30s 15.00s 90.94%
BegÀrningar/Sek 23.25 13.55 282.00 79.25%
393093 begÀrningar pÄ 6.00m, 11.35GB lÀsta
Socket-fel: anslut 0, lÀs 0, skriv 0, timeout 9555
Icke-2xx eller 3xx svar: 8111
BegÀrningar/s: 1091.62
Ăverföring/s: 32.27MB NĂ€rvaron av timeouts tyder pĂ„ att det finns brist pĂ„ resurser (vi anvĂ€nde 4 vCPU, 4 GB RAM-vĂ€rdar, Linux), och faktiska potentiella RPS Ă€r högre (vi fick siffror upp till 2700 RPS pĂ„ kraftfullare resurser).
Avslutningsvis vill jag nĂ€mna att teknologin ESNI ser ganska lovande ut. Det finns fortfarande mĂ„nga öppna frĂ„gor, sĂ„som lagring av den offentliga ESNI-nyckeln i DNS och rotation av ESNI-nycklar â dessa frĂ„gor diskuteras aktivt, och den senaste versionen av utkastet (vid tidpunkten för skrivandet) ESNI redan .
KĂ€lla: habr.com
