Hei Habr, jeg heter Ilya, jeg jobber i plattformteamet hos Exness. Vi utvikler og implementerer kjerneinfrastrukturkomponentene som produktutviklingsteamene våre bruker.
I denne artikkelen vil jeg dele min erfaring med å implementere kryptert SNI (ESNI) teknologi i infrastrukturen til offentlige nettsteder.
Bruken av denne teknologien vil øke sikkerhetsnivået når du arbeider med et offentlig nettsted og overholde interne sikkerhetsstandarder vedtatt av selskapet.
Først av alt vil jeg påpeke at teknologien ikke er standardisert og fortsatt er i utkastet, men CloudFlare og Mozilla støtter den allerede (i
Litt teori
ESNI er en utvidelse til TLS 1.3-protokollen som tillater SNI-kryptering i TLS-håndtrykket "Client Hello"-meldingen. Slik ser Client Hello ut med ESNI-støtte (i stedet for den vanlige SNI ser vi ESNI):
For å bruke ESNI trenger du tre komponenter:
- DNS;
- Kundestøtte;
- Støtte på serversiden.
DNS
Du må legge til to DNS-poster – AOg TXT (TXT-posten inneholder den offentlige nøkkelen som klienten kan kryptere SNI med) - se nedenfor. I tillegg må det være støtte Doh (DNS over HTTPS) fordi tilgjengelige klienter (se nedenfor) ikke aktiverer ESNI-støtte uten DoH. Dette er logisk, siden ESNI innebærer kryptering av navnet på ressursen vi har tilgang til, det vil si at det ikke gir noen mening å få tilgang til DNS over UDP. Dessuten bruken
Tilgjengelig for øyeblikket
CloudFlare
А inngang:
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, forespørsel genereres i henhold til en mal _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å fra et DNS-perspektiv bør vi bruke DoH (helst med DNSSEC) og legge til to oppføringer.
Kundeservice
Hvis vi snakker om nettlesere, så for øyeblikket
Selvfølgelig må TLS 1.3 brukes for å støtte ESNI, siden ESNI er en utvidelse til TLS 1.3.
For det formål å teste backend med ESNI-støtte, implementerte vi klienten på go, Men mer om det senere.
Støtte på serversiden
Foreløpig støttes ikke ESNI av webservere som nginx/apache, etc., siden de jobber med TLS via OpenSSL/BoringSSL, som ikke offisielt støtter ESNI.
Derfor bestemte vi oss for å lage vår egen front-end-komponent (ESNI omvendt proxy), som ville støtte TLS 1.3-terminering med ESNI og proxy HTTP(S)-trafikk til oppstrøms, som ikke støtter ESNI. Dette gjør at teknologien kan brukes i en allerede eksisterende infrastruktur, uten å endre hovedkomponentene – det vil si å bruke nåværende webservere som ikke støtter ESNI.
For klarhet, her er et diagram:
Jeg legger merke til at proxyen ble designet med muligheten til å avslutte en TLS-tilkobling uten ESNI, for å støtte klienter uten ESNI. Kommunikasjonsprotokollen med oppstrøm kan også være enten HTTP eller HTTPS med en TLS-versjon lavere enn 1.3 (hvis oppstrøms ikke støtter 1.3). Denne ordningen gir maksimal fleksibilitet.
Implementering av ESNI-støtte på go vi lånte fra
For å generere ESNI-nøkler brukte vi
Vi testet bygget med go 1.13 på Linux (Debian, Alpine) og MacOS.
Noen få ord om operasjonelle funksjoner
ESNI omvendt proxy gir beregninger i Prometheus-format, for eksempel rps, oppstrøms latens og svarkoder, mislykkede/vellykkede TLS-håndtrykk og TLS-håndtrykkvarighet. Ved første øyekast virket dette tilstrekkelig til å evaluere hvordan proxyen håndterer trafikk.
Vi utførte også lasttesting før bruk. Resultater nedenfor:
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
Vi utførte rent kvalitativ lasttesting for å sammenligne ordningen med ESNI omvendt proxy og uten. Vi "hellte" trafikk lokalt for å eliminere "interferens" i mellomkomponenter.
Så, med ESNI-støtte og proxying til oppstrøms fra HTTP, fikk vi rundt ~550 rps fra en forekomst, med gjennomsnittlig CPU/RAM-forbruk av ESNI reverse proxy:
- 80 % CPU-bruk (4 vCPU, 4 GB RAM-verter, Linux)
- 130 MB Mem RSS
Til sammenligning er RPS for samme nginx oppstrøms uten TLS (HTTP-protokoll)-terminering ~ 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
Tilstedeværelsen av tidsavbrudd indikerer at det er mangel på ressurser (vi brukte 4 vCPUer, 4 GB RAM-verter, Linux), og faktisk er potensialet RPS høyere (vi mottok tall på opptil 2700 RPS på kraftigere ressurser).
Avslutningsvis bemerker jeg at ESNI-teknologien ser ganske lovende ut. Det er fortsatt mange åpne spørsmål, for eksempel spørsmålene om lagring av den offentlige ESNI-nøkkelen i DNS og roterende ESNI-nøkler - disse spørsmålene diskuteres aktivt, og den siste versjonen av ESNI-utkastet (i skrivende stund) er allerede
Kilde: www.habr.com