Comment protéger votre site Web public avec ESNI

Bonjour Habr, je m'appelle Ilya, je travaille dans l'équipe plateforme chez Exness. Nous développons et mettons en œuvre les composants d’infrastructure de base utilisés par nos équipes de développement de produits.

Dans cet article, j'aimerais partager mon expérience de mise en œuvre de la technologie cryptée SNI (ESNI) dans l'infrastructure des sites Web publics.

Comment protéger votre site Web public avec ESNI

L'utilisation de cette technologie augmentera le niveau de sécurité lors du travail avec un site Web public et se conformera aux normes de sécurité internes adoptées par la Société.

Tout d'abord, je tiens à souligner que la technologie n'est pas standardisée et est encore à l'état de projet, mais CloudFlare et Mozilla la supportent déjà (en brouillon01). Cela nous a motivé pour une telle expérience.

Un peu de théorie

ESNI est une extension du protocole TLS 1.3 qui permet le cryptage SNI dans le message de prise de contact TLS « Client Hello ». Voici à quoi ressemble Client Hello avec le support ESNI (au lieu du SNI habituel, nous voyons ESNI) :

Comment protéger votre site Web public avec ESNI

 Pour utiliser ESNI, vous avez besoin de trois composants :

  • DNS ; 
  • Accompagnement client ;
  • Prise en charge côté serveur.

DNS

Vous devez ajouter deux enregistrements DNS – AEt TXT (L'enregistrement TXT contient la clé publique avec laquelle le client peut chiffrer SNI) - voir ci-dessous. De plus, il doit y avoir un soutien DoH (DNS sur HTTPS) car les clients disponibles (voir ci-dessous) n'activent pas la prise en charge ESNI sans DoH. C'est logique, puisque ESNI implique le cryptage du nom de la ressource à laquelle nous accédons, c'est-à-dire que cela n'a aucun sens d'accéder au DNS via UDP. De plus, l'utilisation DNSSEC vous permet de vous protéger contre les attaques par empoisonnement du cache dans ce scénario.

Actuellement disponible plusieurs fournisseurs du DoH, parmi eux:

CloudFlare déclare (Vérifiez Mon navigateur → SNI crypté → En savoir plus) que leurs serveurs prennent déjà en charge ESNI, c'est-à-dire que pour les serveurs CloudFlare dans le DNS, nous avons au moins deux enregistrements - A et TXT. Dans l'exemple ci-dessous, nous interrogeons Google DNS (via HTTPS) : 

А enregistrement:

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 enregistrement, la demande est générée selon un modèle _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."
}

Donc, du point de vue DNS, nous devrions utiliser DoH (de préférence avec DNSSEC) et ajouter deux entrées. 

Service client

Si nous parlons de navigateurs, alors pour le moment le support est implémenté uniquement dans FireFox. il est Voici les instructions sur la façon d’activer la prise en charge ESNI et DoH dans FireFox. Une fois le navigateur configuré, nous devrions voir quelque chose comme ceci :

Comment protéger votre site Web public avec ESNI

Lien pour vérifier le navigateur.

Bien entendu, TLS 1.3 doit être utilisé pour prendre en charge ESNI, puisque ESNI est une extension de TLS 1.3.

Dans le but de tester le backend avec le support ESNI, nous avons implémenté le client sur go, Mais plus là-dessus plus tard.

Prise en charge côté serveur

Actuellement, ESNI n'est pas pris en charge par les serveurs Web comme nginx/apache, etc., car ils fonctionnent avec TLS via OpenSSL/BoringSSL, qui ne prennent pas officiellement en charge ESNI.

Par conséquent, nous avons décidé de créer notre propre composant frontal (proxy inverse ESNI), qui prendrait en charge la terminaison TLS 1.3 avec ESNI et le trafic proxy HTTP(S) vers l'amont, qui ne prend pas en charge ESNI. Cela permet d'utiliser la technologie dans une infrastructure déjà existante, sans modifier les principaux composants, c'est-à-dire en utilisant des serveurs Web actuels qui ne prennent pas en charge ESNI. 

Pour plus de clarté, voici un schéma :

Comment protéger votre site Web public avec ESNI

Je note que le proxy a été conçu avec la possibilité de mettre fin à une connexion TLS sans ESNI, pour prendre en charge les clients sans ESNI. De plus, le protocole de communication avec l'amont peut être soit HTTP, soit HTTPS avec une version TLS inférieure à 1.3 (si l'amont ne prend pas en charge 1.3). Ce schéma offre une flexibilité maximale.

Mise en œuvre du support ESNI sur go nous avons emprunté à CloudFlare. Je voudrais tout de suite noter que l'implémentation elle-même n'est pas triviale, car elle implique des changements dans la bibliothèque standard. crypto/tls et nécessite donc un « patching » GOROOT avant assemblage.

Pour générer les clés ESNI, nous avons utilisé Esnitool (également une idée originale de CloudFlare). Ces clés sont utilisées pour le cryptage/déchiffrement SNI.
Nous avons testé la version avec go 1.13 sur Linux (Debian, Alpine) et MacOS. 

Quelques mots sur les fonctionnalités opérationnelles

Le proxy inverse ESNI fournit des métriques au format Prometheus, telles que les rps, la latence en amont et les codes de réponse, les négociations TLS échouées/réussies et la durée de la négociation TLS. À première vue, cela semblait suffisant pour évaluer la manière dont le proxy gère le trafic. 

Nous avons également effectué des tests de charge avant utilisation. Résultats ci-dessous :

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 

Nous avons effectué des tests de charge purement qualitatifs pour comparer le schéma avec et sans proxy inverse ESNI. Nous avons « versé » le trafic localement afin d'éliminer les « interférences » dans les composants intermédiaires.

Ainsi, avec la prise en charge d'ESNI et le proxy en amont depuis HTTP, nous avons reçu environ 550 rps d'une instance, avec la consommation moyenne CPU/RAM du proxy inverse ESNI :

  • Utilisation du processeur à 80 % (4 vCPU, 4 Go de RAM hôtes, Linux)
  • 130 Mo de mémoire RSS

Comment protéger votre site Web public avec ESNI

À titre de comparaison, le RPS pour le même nginx en amont sans terminaison TLS (protocole HTTP) est d'environ 1100 XNUMX :

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 

La présence de timeouts indique qu'il y a un manque de ressources (nous avons utilisé 4 vCPU, 4 Go de RAM hôtes, Linux), et en fait le potentiel RPS est plus élevé (nous avons reçu des chiffres allant jusqu'à 2700 RPS sur des ressources plus puissantes).

En conclusion, je note que la technologie ESNI semble très prometteuse. Il reste encore de nombreuses questions ouvertes, par exemple les problèmes de stockage de la clé ESNI publique dans le DNS et de rotation des clés ESNI - ces questions sont activement discutées et la dernière version du projet ESNI (au moment de la rédaction) est déjà 7.

Source: habr.com

Ajouter un commentaire