Како да ја заштитите вашата јавна веб-страница со ESNI

Здраво Хабр, јас се викам Илја, работам во тимот на платформата во Exness. Ние ги развиваме и имплементираме основните инфраструктурни компоненти што ги користат нашите тимови за развој на производи.

Во оваа статија, би сакал да го споделам моето искуство за имплементирање на шифрирана технологија SNI (ESNI) во инфраструктурата на јавните веб-страници.

Како да ја заштитите вашата јавна веб-страница со ESNI

Употребата на оваа технологија ќе го зголеми нивото на безбедност при работа со јавна веб-страница и ќе биде во согласност со стандардите за внатрешна безбедност усвоени од Компанијата.

Најпрво, би сакал да истакнам дека технологијата не е стандардизирана и сè уште е во нацрт, но CloudFlare и Mozilla веќе ја поддржуваат (во нацрт01). Ова не мотивираше за ваков експеримент.

Малку теорија

ЕСНИ е продолжување на протоколот TLS 1.3 што овозможува шифрирање на SNI во пораката „Клиент Здраво“ за ракување TLS. Еве како изгледа Client Hello со поддршка на ESNI (наместо вообичаениот SNI го гледаме ESNI):

Како да ја заштитите вашата јавна веб-страница со ESNI

 За да користите ESNI, потребни ви се три компоненти:

  • DNS; 
  • Поддршка на клиентите;
  • Поддршка од страна на серверот.

DNS

Треба да додадете два записи DNS - AИ TXT (Записот TXT го содржи јавниот клуч со кој клиентот може да го шифрира SNI) - видете подолу. Покрај тоа, мора да има поддршка Д. (DNS преку HTTPS) бидејќи достапните клиенти (види подолу) не овозможуваат поддршка за ESNI без DoH. Ова е логично, бидејќи ESNI подразбира шифрирање на името на ресурсот до кој пристапуваме, односно нема смисла да се пристапува до DNS преку UDP. Покрај тоа, употребата DNSSEC ви овозможува да се заштитите од напади на труење со кеш во ова сценарио.

Моментално достапни неколку даватели на DoH, меѓу нив:

CloudFlare изјавува (Проверете My Browser → Encrypted SNI → Learn More) дека нивните сервери веќе поддржуваат ESNI, односно за CloudFlare серверите во DNS имаме најмалку два записи - A и TXT. Во примерот подолу бараме Google DNS (преку HTTPS): 

А влез:

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 запис, барањето се генерира според шаблон _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."
}

Значи, од перспектива на DNS, треба да користиме DoH (по можност со DNSSEC) и да додадеме два записи. 

Поддршка за корисници

Ако зборуваме за прелистувачи, тогаш во моментот поддршката се спроведува само во FireFox. Тука Еве инструкции како да ја активирате поддршката за ESNI и DoH во FireFox. Откако ќе се конфигурира прелистувачот, треба да видиме нешто како ова:

Како да ја заштитите вашата јавна веб-страница со ESNI

Линк за да го проверите прелистувачот.

Се разбира, TLS 1.3 мора да се користи за поддршка на ESNI, бидејќи ESNI е продолжение на TLS 1.3.

За да го тестираме задниот дел со поддршка на ESNI, го имплементиравме клиентот на go, Но повеќе за тоа подоцна.

Поддршка од страна на серверот

Во моментов, ESNI не е поддржан од веб-сервери како nginx/apache, итн., бидејќи тие работат со TLS преку OpenSSL/BoringSSL, кои официјално не поддржуваат ESNI.

Затоа, решивме да создадеме наша сопствена предна компонента (ESNI обратен прокси), која ќе поддржува TLS 1.3 завршување со ESNI и прокси HTTP(S) сообраќај до горе, што не поддржува ESNI. Ова овозможува технологијата да се користи во веќе постоечка инфраструктура, без промена на главните компоненти - односно користење на тековни веб-сервери кои не поддржуваат ESNI. 

За јасност, еве дијаграм:

Како да ја заштитите вашата јавна веб-страница со ESNI

Забележувам дека проксито е дизајнирано со можност за прекинување на TLS конекција без ESNI, за поддршка на клиенти без ESNI. Исто така, протоколот за комуникација со upstream може да биде или HTTP или HTTPS со TLS верзија пониска од 1.3 (ако upstream не поддржува 1.3). Оваа шема дава максимална флексибилност.

Имплементација на поддршката ESNI на go позајмивме од CloudFlare. Би сакал веднаш да забележам дека самата имплементација е сосема нетривијална, бидејќи вклучува промени во стандардната библиотека крипто/тлс и затоа бара „крпење“ ГОРОТ пред склопување.

За да генерираме ESNI клучеви што ги користевме esnitool (исто така замисла на CloudFlare). Овие клучеви се користат за шифрирање/декрипција на SNI.
Ја тестиравме конструкцијата користејќи go 1.13 на Linux (Debian, Alpine) и MacOS. 

Неколку зборови за оперативните карактеристики

Обратно прокси ESNI обезбедува метрика во формат Prometheus, како што се rps, шифри за доцнење и одговор нагоре, неуспешни/успешни TLS ракувања и времетраење на TLS ракување. На прв поглед, ова се чинеше доволно за да се оцени како посредникот се справува со сообраќајот. 

Исто така, извршивме тестирање на оптоварување пред употреба. Резултати подолу:

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 

Спроведовме чисто квалитативно тестирање на оптоварување за да ја споредиме шемата користејќи обратен прокси ESNI и без. Локално го „истуривме“ сообраќајот за да ги елиминираме „пречките“ во меѓукомпонентите.

Така, со поддршка на ESNI и прокси до спротиводно од HTTP, добивме околу ~ 550 вртежи во секунда од еден пример, со просечна потрошувачка на CPU/RAM на ESNI обратен прокси:

  • 80% користење на процесорот (4 vCPU, 4 GB RAM хостови, Linux)
  • 130 MB Mem RSS

Како да ја заштитите вашата јавна веб-страница со ESNI

За споредба, RPS за истиот nginx upstream без TLS (HTTP протокол) завршување е ~ 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 

Присуството на тајмаути укажува на недостаток на ресурси (користевме 4 vCPU, 4 GB RAM хостови, Linux), и всушност потенцијалниот RPS е поголем (добивме бројки до 2700 RPS на помоќни ресурси).

Како заклучок, забележувам дека ESNI технологијата изгледа доста ветувачки. Сè уште има многу отворени прашања, на пример, прашањата за складирање на јавниот клуч ESNI во DNS и ротирачките клучеви ESNI - овие прашања активно се дискутираат, а најновата верзија на нацртот на ESNI (во моментот на пишување) е веќе 7.

Извор: www.habr.com

Купете доверлив хостинг за сајтови со DDoS заштита, VPS VDS сервери 🔥 Купете сигурен веб-хостинг со DDoS заштита, VPS VDS сервери | ProHoster