Ahoj Habr, jmenuji se Ilya, pracuji v týmu platformy ve společnosti Exness. Vyvíjíme a implementujeme základní součásti infrastruktury, které používají naše týmy pro vývoj produktů.
V tomto článku bych se rád podělil o své zkušenosti s implementací šifrované technologie SNI (ESNI) do infrastruktury veřejných webů.
Použití této technologie zvýší úroveň zabezpečení při práci s veřejnými webovými stránkami a bude v souladu s interními bezpečnostními standardy přijatými Společností.
Nejprve bych rád upozornil, že technologie není standardizovaná a je stále ve fázi návrhu, ale CloudFlare a Mozilla ji již podporují (v
Některé teorie
ESNI je rozšíření protokolu TLS 1.3, které umožňuje šifrování SNI ve zprávě TLS handshake „Client Hello“. Takto vypadá klient Hello s podporou ESNI (místo obvyklého SNI vidíme ESNI):
Chcete-li používat ESNI, potřebujete tři komponenty:
- DNS;
- Zákaznická podpora;
- Podpora na straně serveru.
DNS
Musíte přidat dva záznamy DNS – AA TXT (Záznam TXT obsahuje veřejný klíč, kterým může klient šifrovat SNI) - viz níže. Navíc musí existovat podpora DoH (DNS přes HTTPS), protože dostupní klienti (viz níže) neumožňují podporu ESNI bez DoH. To je logické, protože ESNI předpokládá šifrování názvu zdroje, ke kterému přistupujeme, to znamená, že nemá smysl přistupovat k DNS přes UDP. Navíc použití
Momentálně dostupný
Cloudflare
А vstup:
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 záznam, požadavek je vygenerován podle šablony _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."
}
Z pohledu DNS bychom tedy měli použít DoH (nejlépe s DNSSEC) a přidat dva záznamy.
Zákaznická podpora
Pokud se bavíme o prohlížečích, tak v tuto chvíli
Pro podporu ESNI je samozřejmě nutné použít TLS 1.3, protože ESNI je rozšířením TLS 1.3.
Pro účely testování backendu s podporou ESNI jsme klienta implementovali na go, Ale o tom později.
Podpora na straně serveru
V současné době není ESNI podporováno webovými servery jako nginx/apache atd., protože pracují s TLS přes OpenSSL/BoringSSL, které oficiálně ESNI nepodporují.
Proto jsme se rozhodli vytvořit vlastní front-end komponentu (ESNI reverzní proxy), která by podporovala ukončení TLS 1.3 s ESNI a proxy HTTP(S) provoz na upstream, který ESNI nepodporuje. To umožňuje použití technologie v již existující infrastruktuře, aniž by se měnily hlavní komponenty – tedy s využitím současných webových serverů, které ESNI nepodporují.
Pro přehlednost je zde schéma:
Podotýkám, že proxy byl navržen s možností ukončit připojení TLS bez ESNI, aby podporoval klienty bez ESNI. Komunikační protokol s upstream může být také HTTP nebo HTTPS s verzí TLS nižší než 1.3 (pokud upstream nepodporuje 1.3). Toto schéma poskytuje maximální flexibilitu.
Implementace podpory ESNI na go jsme si půjčili od
Ke generování klíčů ESNI jsme použili
Testovali jsme sestavení pomocí go 1.13 na Linuxu (Debian, Alpine) a MacOS.
Pár slov o provozních vlastnostech
Reverzní proxy ESNI poskytuje metriky ve formátu Prometheus, jako jsou rps, upstream latence a kódy odezvy, neúspěšné/úspěšné TLS handshake a trvání TLS handshake. Na první pohled se to zdálo dostatečné pro vyhodnocení toho, jak proxy nakládá s provozem.
Před použitím jsme také provedli zátěžové testování. Výsledky níže:
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
Provedli jsme čistě kvalitativní zátěžové testování, abychom porovnali schéma pomocí ESNI reverzní proxy a bez. Lokálně jsme „nalévali“ provoz, abychom eliminovali „zásahy“ do mezisložek.
Takže s podporou ESNI a proxy pro upstream s HTTP jsme dostali přibližně ~550 rps z jedné instance, s průměrnou spotřebou CPU/RAM reverzní proxy ESNI:
- 80% využití CPU (4 vCPU, 4 GB RAM hostitelé, Linux)
- 130 MB paměti RSS
Pro srovnání, RPS pro stejný nginx upstream bez ukončení TLS (protokol HTTP) je ~ 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
Přítomnost časových limitů naznačuje, že je nedostatek zdrojů (použili jsme 4 vCPU, 4 GB RAM hostitele, Linux) a ve skutečnosti je potenciální RPS vyšší (obdrželi jsme čísla až 2700 RPS na výkonnějších zdrojích).
Závěrem podotýkám že technologie ESNI vypadá docela slibně. Stále existuje mnoho otevřených otázek, například otázky ukládání veřejného klíče ESNI v DNS a rotace klíčů ESNI - tyto problémy jsou aktivně diskutovány a nejnovější verze návrhu ESNI (v době psaní tohoto článku) je již k dispozici
Zdroj: www.habr.com