Jak chronić swoją publiczną witrynę internetową za pomocą ESNI

Cześć Habr, nazywam się Ilya, pracuję w zespole platformowym w Exness. Opracowujemy i wdrażamy podstawowe komponenty infrastruktury, z których korzystają nasze zespoły ds. rozwoju produktów.

W tym artykule chciałbym podzielić się swoimi doświadczeniami dotyczącymi wdrażania technologii szyfrowanego SNI (ESNI) w infrastrukturze publicznych stron internetowych.

Jak chronić swoją publiczną witrynę internetową za pomocą ESNI

Zastosowanie tej technologii zwiększy poziom bezpieczeństwa podczas pracy z publiczną witryną internetową i będzie zgodne z wewnętrznymi standardami bezpieczeństwa przyjętymi przez Spółkę.

Przede wszystkim chciałbym zaznaczyć, że technologia ta nie jest jeszcze znormalizowana i znajduje się w fazie roboczej, ale CloudFlare i Mozilla już ją obsługują (w szkic01). To właśnie zmotywowało nas do przeprowadzenia takiego eksperymentu.

Trochę teorii

ESNI – jest rozszerzeniem protokołu TLS 1.3, które umożliwia szyfrowanie SNI w wiadomości handshake „Client Hello” TLS. Oto jak wygląda Client Hello z obsługą ESNI (zamiast zwykłego SNI widzimy ESNI):

Jak chronić swoją publiczną witrynę internetową za pomocą ESNI

 Aby korzystać z ESNI, wymagane są trzy komponenty:

  • Serwer DNS; 
  • Obsługa klienta;
  • Wsparcie po stronie serwera.

DNS

Musisz dodać dwa rekordy DNS – Ai TXT (rekord TXT zawiera klucz publiczny, którym klient może zaszyfrować SNI) – patrz poniżej. Ponadto powinno być wsparcie Doh (DNS przez HTTPS), ponieważ dostępni klienci (patrz poniżej) nie aktywują obsługi ESNI bez DoH. Jest to logiczne, ponieważ ESNI oznacza szyfrowanie nazwy zasobu, do którego uzyskujemy dostęp, tj. nie ma sensu uzyskiwać dostępu do DNS przez UDP. Ponadto, używając DNSSEC umożliwia ochronę przed atakami typu cache poisoning w tym scenariuszu.

Obecnie dostępne kilku dostawców DoH, wśród nich:

CloudFlare deklaruje (Sprawdź moją przeglądarkę → Zaszyfrowany SNI → Dowiedz się więcej), że ich serwery już obsługują ESNI, czyli dla serwerów CloudFlare w DNS mamy co najmniej dwa rekordy - A i TXT. W poniższym przykładzie żądamy Google DNS (przez HTTPS): 

А wejście:

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 rekord, żądanie generowane jest według szablonu _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."
}

Zatem z perspektywy DNS powinniśmy użyć DoH (najlepiej z DNSSEC) i dodać dwa rekordy. 

Obsługa klienta

Jeśli mówimy o przeglądarkach, to w tej chwili obsługa jest realizowana tylko w FireFox. Tutaj podano instrukcje dotyczące aktywacji obsługi ESNI i DoH w FireFox. Po skonfigurowaniu przeglądarki powinniśmy zobaczyć coś takiego:

Jak chronić swoją publiczną witrynę internetową za pomocą ESNI

Połączenie aby sprawdzić przeglądarkę.

Oczywiście, aby obsługiwać ESNI, należy użyć protokołu TLS 1.3, ponieważ ESNI jest rozszerzeniem protokołu TLS 1.3.

W celu przetestowania zaplecza ze wsparciem ESNI wdrożyliśmy klienta na go, Ale o tym później.

Wsparcie po stronie serwera

Obecnie ESNI nie jest obsługiwany przez serwery WWW, takie jak nginx/apache itp., ponieważ działają one z protokołem TLS za pośrednictwem OpenSSL/BoringSSL, które oficjalnie nie obsługują ESNI.

Dlatego postanowiliśmy stworzyć własny komponent front-end (ESNI reverse proxy), który obsługiwałby zakończenie TLS 1.3 z ESNI i przekierowywał ruch HTTP(S) do upstream, który nie obsługuje ESNI. Pozwala to na wykorzystanie technologii w już istniejącej infrastrukturze, bez zmiany głównych komponentów - to znaczy, wykorzystując obecne serwery WWW, które nie obsługują ESNI. 

Dla jasności przedstawiam poniższy diagram:

Jak chronić swoją publiczną witrynę internetową za pomocą ESNI

Chciałbym zauważyć, że proxy zostało zaprojektowane z możliwością zakończenia połączenia TLS bez ESNI, aby obsługiwać klientów bez ESNI. Ponadto protokół do komunikacji z nadrzędnym serwerem może być albo HTTP albo HTTPS z wersją TLS niższą niż 1.3 (jeśli nadrzędny serwer nie obsługuje wersji 1.3). Ten schemat zapewnia maksymalną elastyczność.

Wdrożenie wsparcia ESNI w go pożyczyliśmy od CloudFlare. Od razu zauważę, że sama implementacja nie jest wcale trywialna, ponieważ wymaga zmian w bibliotece standardowej. krypto/tls i dlatego wymaga „łatania” GOROOT przed montażem.

Do wygenerowania kluczy ESNI użyliśmy narzędzie esnitool (również dzieło CloudFlare). Te klucze służą do szyfrowania/odszyfrowywania SNI.
Przetestowaliśmy kompilację, używając wersji Go 1.13 Linux (Debian, Alpine) i MacOS. 

Kilka słów o cechach operacyjnych

Odwrotny serwer proxy ESNI dostarcza metryki w formacie Prometheus, takie jak rps, opóźnienia w górę i kody odpowiedzi, nieudane/udane uzgadniania TLS i czas trwania uzgadniania TLS. Na pierwszy rzut oka wydawało się to wystarczające do oceny, jak serwer proxy obsługuje ruch. 

Przeprowadziliśmy również testy obciążeniowe przed użyciem. Wyniki są poniżej:

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 

Przeprowadziliśmy czysto jakościowe testy obciążenia, aby porównać schemat z odwrotnym proxy ESNI i bez niego. „Wylaliśmy” ruch lokalnie, aby wyeliminować „zakłócenia” w komponentach pośrednich.

Dzięki obsłudze ESNI i obsłudze proxy HTTP uzyskaliśmy około 550 obr./s z jednej instancji, biorąc pod uwagę średnie zużycie procesora i pamięci RAM przez odwrotny serwer proxy ESNI:

  • 80% wykorzystania procesora (4 wirtualne procesory, hosty 4 GB RAM, Linux)
  • 130 MB Pamięć RSS

Jak chronić swoją publiczną witrynę internetową za pomocą ESNI

Dla porównania, RPS dla tego samego serwera nginx upstream bez zakończenia TLS (protokół HTTP) wynosi ~ 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 

Obecność przekroczeń limitu czasu wskazuje na brak zasobów (użyliśmy hostów z 4 procesorami wirtualnymi i 4 GB pamięci RAM, Linux), a w rzeczywistości potencjalny RPS jest wyższy (otrzymaliśmy dane do 2700 RPS przy mocniejszych zasobach).

Podsumowując, chciałbym zauważyć, że że technologia ESNI wygląda obiecująco. Nadal pozostaje wiele otwartych kwestii, na przykład kwestie przechowywania klucza publicznego ESNI w DNS i rotacji kluczy ESNI - kwestie te są aktywnie omawiane, a najnowsza wersja projektu (w momencie pisania) ESNI jest już 7.

Źródło: www.habr.com

Kup niezawodny hosting dla stron z ochroną DDoS, serwery VPS VDS 🔥 Kup niezawodny hosting stron internetowych z ochroną DDoS, serwery VPS VDS | ProHoster