Cómo proteger su sitio web público con ESNI

Hola Habr, me llamo Ilya y trabajo en el equipo de plataforma de la empresa Exness. Estamos desarrollando e implementando componentes de infraestructura básicos que utilizan nuestros equipos de desarrollo de productos.

En este artículo, me gustaría compartir la experiencia de implementar la tecnología de SNI cifrado (ESNI) en la infraestructura de sitios web públicos.

Cómo proteger su sitio web público con ESNI

El uso de esta tecnología permitirá aumentar el nivel de seguridad al trabajar con un sitio web público y cumplir con los estándares internos de seguridad adoptados en la Compañía.

Primero que nada, quiero señalar que la tecnología no está estandarizada y aún se encuentra en borrador, sin embargo, CloudFlare y Mozilla ya la admiten (en draft01). Esto nos motivó a realizar tal experimento.

Un poco de teoría

ESNI es una extensión del protocolo TLS 1.3 que permite cifrar el SNI en el mensaje 'Client Hello' del apretón de manos TLS. Así es como se ve el Client Hello con soporte para ESNI (en lugar del SNI habitual, vemos ESNI):

Cómo proteger su sitio web público con ESNI

 Para utilizar ESNI, se requieren tres componentes:

  • DNS; 
  • Soporte por parte del cliente;
  • Soporte por parte del servidor.

DNS

Es necesario añadir dos registros DNS - Acomo TXT (el registro TXT contiene la clave pública con la que el cliente puede cifrar el SNI) - véase más abajo. Además, debe haber soporte para DoH (DNS sobre HTTPS), ya que los clientes disponibles (véase más abajo) no activan el soporte para ESNI sin DoH. Esto tiene sentido, dado que ESNI implica cifrar el nombre del recurso al que estamos accediendo, es decir, es inútil consultar a DNS por UDP. Además, el uso de DNSSEC ayuda a protegerse contra ataques de 'cache poisoning' en este escenario.

Actualmente hay disponibles varios proveedores de DoH, entre ellos:

CloudFlare declara (Check My Browser → Encrypted SNI → Learn More), que sus servidores ya soportan ESNI, es decir, para los servidores de CloudFlare en DNS tenemos al menos dos registros - A y TXT. En el ejemplo a continuación, solicitamos Google DNS (sobre HTTPS): 

A registro:

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 registro, la consulta se forma según el patrón _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": "Respuesta de 2400:cb00:2049:1::a29f:209."
}

Así que, desde el punto de vista de DNS, debemos utilizar DoH (preferiblemente con DNSSEC) y agregar dos registros. 

Soporte del cliente

Si hablamos de navegadores, en este momento el soporte solo está implementado en Firefox. Aquí se presenta una guía sobre cómo activar el soporte de ESNI y DoH en Firefox. Después de que el navegador esté configurado, deberíamos ver algo como esto:

Cómo proteger su sitio web público con ESNI

Enlace para verificar en el navegador.

Por supuesto, para soportar ESNI se debe utilizar TLS 1.3, ya que ESNI es una extensión de TLS 1.3.

Para fines de prueba del backend con soporte de ESNI, implementamos un cliente en go, pero eso será más adelante.

Soporte del servidor

En este momento, ESNI no es soportado por servidores web como nginx/apache, etc., porque funcionan con TLS a través de OpenSSL/BoringSSL, en los que ESNI no es soportado oficialmente.

Por lo tanto, decidimos crear nuestro propio componente front-end (proxy inverso ESNI) que soporte la terminación de TLS 1.3 con ESNI y el proxy de tráfico HTTP(S) a upstream que no soporte ESNI. Esto permite aplicar la tecnología en una infraestructura ya existente, sin cambiar los componentes principales, es decir, utilizar los servidores web actuales que no soportan ESNI. 

Para mayor claridad, proporcionamos un esquema:

Cómo proteger su sitio web público con ESNI

Cabe mencionar que el proxy fue diseñado con la posibilidad de terminar la conexión TLS sin ESNI, para soportar clientes sin ESNI. Además, el protocolo de comunicación con upstream puede ser tanto HTTP como HTTPS con una versión de TLS inferior a 1.3 (si upstream no soporta 1.3). Este esquema ofrece la máxima flexibilidad.

La implementación del soporte de ESNI en go la tomamos de CloudFlare. Cabe destacar que la implementación en sí es bastante no trivial, ya que implica cambios en la biblioteca estándar crypto/tls y por lo tanto requiere "parcheo" GOROOT antes de la compilación.

Para generar las claves ESNI utilizamos esnitool (también una creación de CloudFlare). Estas claves se utilizan para la encriptación/desencriptación de SNI.
Probamos la compilación utilizando go 1.13 en Linux (Debian, Alpine) y MacOS. 

Unas palabras sobre características operativas

El proxy inverso ESNI proporciona métricas en formato Prometheus, como rps, latencia hacia el upstream y códigos de respuesta, así como los handshakes TLS fallidos/exitosos y la duración del handshake TLS. A primera vista, esto pareció suficiente para evaluar cómo el proxy maneja el tráfico. 

Además, realizamos pruebas de carga antes de usarlo. Los resultados son los siguientes:

wrk -t50 -c1000 -d360s 'https://esni-rev-proxy.npw:443' --timeout 15s
Ejecutando prueba de 6 minutos en https://esni-rev-proxy.npw:443
  50 hilos y 1000 conexiones
  Estadísticas por hilo   Prom.  Desv.  Máx.   +/− Desv.
    Latencia     1.77s     1.21s    7.20s    65.43%
    Req/Sec    13.78      8.84   140.00     83.70%
  206357 solicitudes en 6.00m, 6.08GB leídos
Solicitudes/seg:    573.07
Transferencia/seg:     17.28MB 

Las pruebas de carga que realizamos fueron puramente cualitativas, para comparar el esquema utilizando el proxy inverso ESNI y sin él. Inyectamos tráfico localmente para eliminar ‘interferencias’ en los componentes intermedios.

Entonces, con el soporte de ESNI y el proxy hacia el upstream con HTTP, obtuvimos alrededor de ~ 550 rps desde una instancia, mientras que el consumo promedio de CPU/RAM del proxy inverso ESNI fue:

  • 80% Uso de CPU (4 vCPU, 4 GB RAM en hosts, Linux)
  • 130 MB Mem RSS

Cómo proteger su sitio web público con ESNI

Para comparación, el RPS para el mismo upstream nginx sin terminación TLS (protocolo HTTP) es ~ 1100:

wrk -t50 -c1000 -d360s 'http://lb.npw:80' --timeout 15s
Ejecutando prueba de 6 minutos en http://lb.npw:80
  50 hilos y 1000 conexiones
  Estadísticas por hilo   Prom.  Desv.   Máx.   +/− Desv.
    Latencia     1.11s     2.30s   15.00s    90.94%
    Req/Sec    23.25     13.55   282.00     79.25%
  393093 solicitudes en 6.00m, 11.35GB leídos
  Errores de socket: conectar 0, leer 0, escribir 0, tiempo de espera 9555
  Respuestas no 2xx o 3xx: 8111
Solicitudes/seg:   1091.62
Transferencia/seg:     32.27MB 

La presencia de tiempos de espera indica que hay falta de recursos (utilizamos hosts de 4 vCPU y 4 GB RAM, Linux), y de hecho, el RPS potencial es mayor (obtuvimos cifras de hasta 2700 RPS en recursos más potentes).

En conclusión, debo mencionar que la tecnología ESNI parece bastante prometedora. Aún hay muchas preguntas abiertas, como el almacenamiento de la clave pública ESNI en DNS y la rotación de claves ESNI; estos temas se están discutiendo activamente, y la última versión del borrador (en el momento de la escritura) de ESNI ya Arqueólogos de la era digital 7.

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster