So schützen Sie Ihre öffentliche Website mit ESNI

Hallo Habr, mein Name ist Ilya, ich arbeite im Plattformteam bei Exness. Wir entwickeln und implementieren die zentralen Infrastrukturkomponenten, die unsere Produktentwicklungsteams verwenden.

In diesem Artikel möchte ich meine Erfahrungen mit der Implementierung der verschlüsselten SNI-Technologie (ESNI) in die Infrastruktur öffentlicher Websites teilen.

So schützen Sie Ihre öffentliche Website mit ESNI

Durch den Einsatz dieser Technologie wird das Sicherheitsniveau bei der Arbeit mit einer öffentlichen Website erhöht und die internen Sicherheitsstandards des Unternehmens eingehalten.

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

Ein bisschen Theorie

ESNI ist eine Erweiterung des TLS 1.3-Protokolls, die eine SNI-Verschlüsselung in der TLS-Handshake-Nachricht „Client Hello“ ermöglicht. So sieht Client Hello mit ESNI-Unterstützung aus (anstelle des üblichen SNI sehen wir ESNI):

So schützen Sie Ihre öffentliche Website mit ESNI

 Um ESNI nutzen zu können, benötigen Sie drei Komponenten:

  • DNS; 
  • Kundendienst;
  • Serverseitige Unterstützung.

DNS

Sie müssen zwei DNS-Einträge hinzufügen – AUnd TXT (Der TXT-Eintrag enthält den öffentlichen Schlüssel, mit dem der Client SNI verschlüsseln kann) – siehe unten. Darüber hinaus muss es Unterstützung geben DoH (DNS über HTTPS), da verfügbare Clients (siehe unten) die ESNI-Unterstützung ohne DoH nicht aktivieren. Dies ist logisch, da ESNI eine Verschlüsselung des Namens der Ressource impliziert, auf die wir zugreifen. Das heißt, es macht keinen Sinn, über UDP auf DNS zuzugreifen. Darüber hinaus ist die Verwendung DNSSEC ermöglicht Ihnen, sich in diesem Szenario vor Cache-Poisoning-Angriffen zu schützen.

Derzeit verfügbar mehrere DoH-Anbieter, unter ihnen:

CloudFlare Zitat (Überprüfen Sie meinen Browser → Verschlüsseltes SNI → Weitere Informationen), dass ihre Server bereits ESNI unterstützen, d. h. für CloudFlare-Server im DNS haben wir mindestens zwei Einträge – A und TXT. Im folgenden Beispiel fragen wir Google DNS ab (über HTTPS): 

А Rekord:

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 Datensatz, Anfrage wird nach einer Vorlage generiert _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."
}

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

Kundendienst

Wenn wir über Browser sprechen, dann im Moment Die Unterstützung ist nur in Firefox implementiert. Hier Hier finden Sie Anweisungen zum Aktivieren der ESNI- und DoH-Unterstützung in FireFox. Nachdem der Browser konfiguriert ist, sollten wir etwa Folgendes sehen:

So schützen Sie Ihre öffentliche Website mit ESNI

Link um den Browser zu überprüfen.

Zur Unterstützung von ESNI muss natürlich TLS 1.3 verwendet werden, da ESNI eine Erweiterung von TLS 1.3 ist.

Um das Backend mit ESNI-Unterstützung zu testen, haben wir den Client implementiert go, Aber dazu später mehr.

Serverseitige Unterstützung

Derzeit wird ESNI nicht von Webservern wie Nginx/Apache usw. unterstützt, da diese mit TLS über OpenSSL/BoringSSL arbeiten, die ESNI offiziell nicht unterstützen.

Aus diesem Grund haben wir beschlossen, eine eigene Front-End-Komponente (ESNI-Reverse-Proxy) zu erstellen, die die TLS 1.3-Terminierung mit ESNI unterstützt und den HTTP(S)-Verkehr an den Upstream weiterleitet, der ESNI nicht unterstützt. Dies ermöglicht den Einsatz der Technologie in einer bereits bestehenden Infrastruktur, ohne die Hauptkomponenten zu ändern – also unter Verwendung aktueller Webserver, die ESNI nicht unterstützen. 

Zur Verdeutlichung hier ein Diagramm:

So schützen Sie Ihre öffentliche Website mit ESNI

Ich stelle fest, dass der Proxy so konzipiert wurde, dass er eine TLS-Verbindung ohne ESNI beenden kann, um Clients ohne ESNI zu unterstützen. Außerdem kann das Kommunikationsprotokoll mit Upstream entweder HTTP oder HTTPS mit einer TLS-Version niedriger als 1.3 sein (wenn Upstream 1.3 nicht unterstützt). Dieses Schema bietet maximale Flexibilität.

Implementierung der ESNI-Unterstützung auf go wir haben etwas geliehen CloudFlare. Ich möchte sofort darauf hinweisen, dass die Implementierung selbst nicht trivial ist, da sie Änderungen in der Standardbibliothek mit sich bringt Krypto/TLS und erfordert daher „Patchen“ GOROOT vor der Montage.

Zur Generierung von ESNI-Schlüsseln haben wir verwendet esnitool (ebenfalls die Idee von CloudFlare). Diese Schlüssel werden für die SNI-Verschlüsselung/Entschlüsselung verwendet.
Wir haben den Build mit go 1.13 unter Linux (Debian, Alpine) und MacOS getestet. 

Ein paar Worte zu den Betriebsfunktionen

Der ESNI-Reverse-Proxy stellt Metriken im Prometheus-Format bereit, wie z. B. RPS, Upstream-Latenz und Antwortcodes, fehlgeschlagene/erfolgreiche TLS-Handshakes und TLS-Handshake-Dauer. Auf den ersten Blick schien dies ausreichend zu sein, um zu beurteilen, wie der Proxy mit dem Datenverkehr umgeht. 

Wir haben vor der Verwendung auch einen Belastungstest durchgeführt. Ergebnisse unten:

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 

Wir haben rein qualitative Lasttests durchgeführt, um das Schema mit und ohne ESNI-Reverse-Proxy zu vergleichen. Wir haben den Datenverkehr lokal „geschüttet“, um „Störungen“ bei Zwischenkomponenten auszuschließen.

Mit ESNI-Unterstützung und Proxying zum Upstream von HTTP erreichten wir also etwa ~550 rps von einer Instanz, mit dem durchschnittlichen CPU-/RAM-Verbrauch des ESNI-Reverse-Proxys:

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

So schützen Sie Ihre öffentliche Website mit ESNI

Zum Vergleich: RPS für denselben Nginx-Upstream ohne TLS-Terminierung (HTTP-Protokoll) beträgt ~ 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 

Das Vorhandensein von Zeitüberschreitungen weist darauf hin, dass es an Ressourcen mangelt (wir haben 4 vCPUs, 4 GB RAM-Hosts, Linux verwendet), und tatsächlich ist das potenzielle RPS höher (wir haben Werte von bis zu 2700 RPS bei leistungsstärkeren Ressourcen erhalten).

Abschließend stelle ich fest dass die ESNI-Technologie recht vielversprechend aussieht. Es gibt noch viele offene Fragen, zum Beispiel die Fragen der Speicherung des öffentlichen ESNI-Schlüssels im DNS und rotierender ESNI-Schlüssel – diese Fragen werden aktiv diskutiert, und die neueste Version des ESNI-Entwurfs (zum Zeitpunkt des Verfassens dieses Artikels) ist bereits verfügbar 7.

Source: habr.com

Kommentar hinzufügen