Wie man seine öffentliche Website mit ESNI schützt

Hallo Habr, ich bin Ilja und arbeite im Plattformteam von Exness. Wir entwickeln und implementieren grundlegende Infrastrukturkomponenten, die von unseren Produktentwicklungsteams genutzt werden.

In diesem Artikel möchte ich meine Erfahrungen mit der Implementierung der Technologie encrypted SNI (ESNI) in der Infrastruktur öffentlicher Websites teilen.

Wie man seine öffentliche Website mit ESNI schützt

Die Nutzung dieser Technologie wird das Sicherheitsniveau bei der Arbeit mit öffentlichen Websites erhöhen und den internen Sicherheitsstandards der Firma entsprechen.

Zunächst möchte ich darauf hinweisen, dass die Technologie noch nicht standardisiert ist und sich weiterhin im Entwurf befindet. CloudFlare und Mozilla unterstützen sie jedoch bereits (in draft01). Das hat uns zu diesem Experiment motiviert.

Ein wenig Theorie

ESNI ist eine Erweiterung des TLS 1.3-Protokolls, die es ermöglicht, SNI in der Nachricht "Client Hello" beim TLS-Handshake zu verschlüsseln. So sieht ein Client Hello mit ESNI-Unterstützung aus (anstatt des gewohnten SNI sehen wir ESNI):

Wie man seine öffentliche Website mit ESNI schützt

 Um ESNI zu nutzen, sind drei Komponenten erforderlich:

  • DNS; 
  • Unterstützung durch den Client;
  • Unterstützung durch den Server.

DNS

Zwei DNS-Einträge müssen hinzugefügt werden – A, und TXT (TXT-Eintrag enthält den öffentlichen Schlüssel, mit dem der Client SNI verschlüsseln kann) – siehe unten. Außerdem sollte Unterstützung vorhanden sein DoH (DNS über HTTPS), da verfügbare Clients (siehe unten) die Unterstützung von ESNI ohne DoH nicht aktivieren. Das ist logisch, da ESNI die Verschlüsselung des Ressourcennamens impliziert, auf den wir zugreifen, also macht es keinen Sinn, DNS über UDP anzusprechen. Darüber hinaus schützt die Nutzung DNSSEC vor „Cache Poisoning“-Angriffen in diesem Szenario.

Derzeit sind verfügbar mehrere DoH-Anbieter, darunter:

CloudFlare behauptet (Check My Browser → Verschlüsseltes SNI → Weitere Informationen), was bedeutet, dass ihre Server bereits ESNI unterstützen, das heißt, für CloudFlare-Server im DNS haben wir mindestens zwei Einträge – A und TXT. Im folgenden Beispiel fragen wir Google DNS (über HTTPS) an: 

A Eintrag:

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 Eintrag, die Anfrage wird nach dem Muster gebildet _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": "Antwort von 2400:cb00:2049:1::a29f:209."
}

Aus DNS-Perspektive sollten wir DoH (vorzugsweise mit DNSSEC) verwenden und zwei Einträge hinzufügen. 

Unterstützung vom Client

Wenn wir von Browsern sprechen, dann wird die Unterstützung derzeit nur in Firefox implementiert.. Hier Hier ist eine Anleitung, wie Sie die Unterstützung von ESNI und DoH in Firefox aktivieren können. Nach der Konfiguration des Browsers sollten wir etwa folgendes Bild sehen:

Wie man seine öffentliche Website mit ESNI schützt

Link zur Überprüfung des Browsers.

Natürlich muss für die Unterstützung von ESNI TLS 1.3 verwendet werden, da ESNI eine Erweiterung zu TLS 1.3 ist.

Für Testzwecke mit einem Backend, das ESNI unterstützt, haben wir einen Client implementiert go, aber dazu später mehr.

Unterstützung vom Server

Derzeit wird ESNI von Webservern wie nginx/apache usw. nicht unterstützt, da sie mit TLS über OpenSSL/BoringSSL arbeiten, in denen ESNI offiziell nicht unterstützt wird.

Deshalb haben wir uns entschieden, unsere eigene Front-End-Komponente (ESNI-Reverse-Proxy) zu entwickeln, die die TLS 1.3-Terminierung mit ESNI unterstützt und HTTP(S)-Traffic an ein Upstream weiterleitet, das ESNI nicht unterstützt. Dies ermöglicht die Anwendung der Technologie in bereits bestehenden Infrastrukturen, ohne die Hauptkomponenten zu ändern – das heißt, aktuelle Web-Server, die ESNI nicht unterstützen, können verwendet werden. 

Zur Veranschaulichung präsentieren wir ein Schema:

Wie man seine öffentliche Website mit ESNI schützt

Ich möchte anmerken, dass der Proxy mit der Möglichkeit entworfen wurde, TLS-Verbindungen ohne ESNI zu terminieren, um Clients ohne ESNI zu unterstützen. Zudem kann das Kommunikationsprotokoll mit dem Upstream sowohl HTTP als auch HTTPS mit einer TLS-Version unter 1.3 sein (wenn der Upstream 1.3 nicht unterstützt). Dieses Schema bietet maximale Flexibilität.

Die Implementierung der ESNI-Unterstützung auf go haben wir von CloudFlareentlehnt. Ich möchte gleich anmerken, dass die Implementierung selbst recht komplex ist, da sie Änderungen an der Standardbibliothek erfordert crypto/tls und daher ein "Patching" GOROOT vor der Erstellung benötigt.

Zur Generierung von ESNI-Schlüsseln haben wir esnitool verwendet (ebenfalls ein Produkt von CloudFlare). Diese Schlüssel werden zur Verschlüsselung/Entschlüsselung des SNI verwendet.
Wir haben den Build mit Go 1.13 auf Linux (Debian, Alpine) und MacOS getestet. 

Einige Worte zu den Betriebseigenschaften

Der ESNI-Reverse-Proxy bietet Metriken im Prometheus-Format, wie z.B. rps, upstream latency & response codes, fehlgeschlagene/erfolgreiche TLS-Handshakes & TLS-Handschlagdauer. Auf den ersten Blick schien dies ausreichend zu sein, um zu beurteilen, wie der Proxy mit dem Traffic umgeht. 

Außerdem haben wir vor der Nutzung Lasttests durchgeführt. Die Ergebnisse finden Sie unten:

wrk -t50 -c1000 -d360s 'https://esni-rev-proxy.npw:443' --timeout 15s
6-minütiger Test @ https://esni-rev-proxy.npw:443
  50 Threads und 1000 Verbindungen
  Thread-Stats   Avg      Stdev     Max   +/- Stdev
    Latenz     1.77s     1.21s    7.20s    65.43%
    Req/Sec    13.78      8.84   140.00     83.70%
  206357 Anfragen in 6.00 min, 6.08GB gelesen
Anfragen/Sekunde:    573.07
Übertragung/Sekunde:     17.28MB 

Wir haben die Lasttests rein qualitativ durchgeführt, um die Unterschiede zwischen den Szenarien mit und ohne ESNI-Reverse-Proxy zu vergleichen. Wir haben den Traffic lokal erzeugt, um «Störungen» in den Zwischenkomponenten auszuschließen.

Mit aktivierter ESNI-Unterstützung und HTTP-Proxying im Upstream haben wir etwa ~ 550 rps von einer Instanz erreicht, während der durchschnittliche CPU/RAM-Verbrauch des ESNI-Reverse-Proxys:

  • 80 % CPU-Auslastung (4 vCPU, 4 GB RAM Hosts, Linux)
  • 130 MB Mem RSS

Wie man seine öffentliche Website mit ESNI schützt

Zum Vergleich: RPS für denselben Upstream nginx ohne TLS-Terminierung (HTTP-Protokoll) ~ 1100:

wrk -t50 -c1000 -d360s 'http://lb.npw:80' –-timeout 15s
Führe 6 Minuten Test @ http://lb.npw:80 aus
  50 Threads und 1000 Verbindungen
  Thread-Statistiken   Durchschnitt   Std. Abw.   Max   +/- Std. Abw.
    Latenz     1.11s     2.30s   15.00s    90.94%
    Anfragen/Sekunde    23.25     13.55   282.00     79.25%
  393093 Anfragen in 6.00m, 11.35GB gelesen
  Socket-Fehler: Verbindung 0, Lesen 0, Schreiben 0, Timeout 9555
  Nicht-2xx oder 3xx Antworten: 8111
Anfragen/Sek:   1091.62
Übertragung/Sek:     32.27MB 

Das Vorhandensein von Timeouts deutet darauf hin, dass Ressourcen fehlen (wir haben Hosts mit 4 vCPU und 4 GB RAM verwendet, Linux), und tatsächlich liegt das potenzielle RPS höher (wir hatten Zahlen bis zu 2700 RPS auf leistungsfähigeren Ressourcen).

Zusammenfassend möchte ich festhalten, dass die ESNI-Technologie vielversprechend aussieht. Es gibt noch viele offene Fragen, wie die Speicherung des öffentlichen ESNI-Schlüssels im DNS und die Rotation der ESNI-Schlüssel – diese Fragen werden aktiv diskutiert, und der letzte Entwurf (zum Zeitpunkt des Schreibens) des ESNI ist bereits 7.

Quelle: habr.com

Zuverlässiges Webhosting mit DDoS-Schutz, VPS- und VDS-Server kaufen 🔥 Zuverlässiges Webhosting mit DDoS-Schutz, VPS- und VDS-Server kaufen | ProHoster