// Engineering Log

HTTP, HTTPS y TLS: Parte 8 — ¿Qué son JA3 y JA4? Huellas del cliente TLS

Publicado el 12.10.2026

// Ruta rapida

Este articulo pertenece al tema Seguridad y proteccion.

JA3 y JA4: maneras de obtener una huella corta (fingerprint) de un cliente TLS a partir de su primer mensaje ClientHello. Diferentes programas — Chrome, Firefox, curl, la biblioteca Python requests, el cliente Go, un programa malicioso — forman el ClientHello de manera distinta: ofrecen distintos conjuntos de cifrados, extensiones, grupos de intercambio de claves en distinto orden. De esos campos se compone una cadena, la cadena se hashifica y se obtiene un identificador idéntico para todas las copias de un mismo programa y distinto para distintos programas. La huella se calcula antes de descifrar el tráfico y sin la participación del cliente, por eso se usa para protección contra bots, búsqueda de malware en la red y en sistemas DPI.

La principal diferencia con el encabezado User-Agent: User-Agent lo escribe el propio cliente, y un script puede hacerse pasar fácilmente por el navegador Chrome. La huella TLS la determina la biblioteca que establece la conexión, y si un script en Python se presenta como Chrome pero su ClientHello proviene de OpenSSL, esa discrepancia se ve de inmediato.

Qué entra en el ClientHello

ClientHello se envía en texto claro (si no se usa ECH) y contiene:

  • la versión del protocolo y la lista de versiones soportadas;
  • la lista de conjuntos de cifrado en orden de preferencia;
  • la lista de extensiones: SNI, ALPN, supported_groups, signature_algorithms, key_share, session_ticket y una decena más;
  • los grupos de intercambio de claves (curvas elípticas): x25519, secp256r1, X25519MLKEM768;
  • los algoritmos de firma;
  • los protocolos ALPN: h2, http/1.1.

Todo esto lo fija la biblioteca TLS (BoringSSL en Chrome, NSS en Firefox, OpenSSL en curl y Python, crypto/tls en Go) y sus ajustes en la aplicación.

JA3

JA3 fue propuesto en 2017 por investigadores de Salesforce (John Althouse, Jeff Atkinson, Josh Atkins — por las iniciales). La cadena JA3 consta de cinco campos del ClientHello, escritos como números decimales separados por comas, y los valores dentro de cada campo separados por guiones:

Versión,Cifrados,Extensiones,Grupos,Formatos_de_puntos
771,4865-4866-4867-49195-49199-...,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-21,29-23-24,0

La huella es el MD5 de esa cadena: 32 caracteres hexadecimales, por ejemplo 375c6162a492dfbf2795909110ce8424. Los valores GREASE (especiales “rellenos” que los navegadores insertan para que los servidores no rompan al ver valores desconocidos) se descartan al calcularla.

Para la respuesta del servidor existe JA3S — a partir de los campos del ServerHello. El par JA3 + JA3S destaca bien programas maliciosos concretos y sus servidores de control: un mismo programa que se conecta al mismo software servidor siempre da el mismo par.

Por qué JA3 dejó de funcionar para navegadores. En JA3 las extensiones aparecen en el orden en que las envía el cliente. Desde Chrome 110 (febrero de 2023) el navegador mezcla el orden de las extensiones en cada nueva conexión — se hizo para que los servidores no dependan de un orden fijo y no obstaculicen la evolución de TLS. Como resultado, un mismo Chrome da un JA3 nuevo casi en cada conexión, y las bases de huellas de navegadores perdieron sentido. Además, MD5 de toda la cadena no permite entender en qué se parecen dos huellas: el cambio de un solo cifrado da un hash completamente diferente.

JA4

JA4 fue propuesto en 2023 por John Althouse, ya en la compañía FoxIO. La huella es legible por humanos, resistente al reordenamiento de extensiones y tiene en cuenta QUIC.

Ejemplo para Chrome:

t13d1516h2_8daaf6152771_e5627efa2ab1

Tres partes separadas por guiones bajos.

Parte a — descripción, legible sin descifrado:

SímbolosSignificadoEjemplo
1transporte: t — TLS sobre TCP, q — QUIC, d — DTLSt
2–3versión TLS: la máxima de supported_versions13 — TLS 1.3
4d — hay SNI (conexión por nombre), i — no hay SNI (por IP)d
5–6número de cifrados sin GREASE15
7–8número de extensiones sin GREASE16
9–10primera y última letra del primer protocolo ALPN, 00 — no hay ALPNh2

Parte b — los primeros 12 caracteres SHA-256 de la lista de cifrados, ordenada por valor. No importa el orden en que el cliente los envió.

Parte c — los primeros 12 caracteres SHA-256 de la lista ordenada de extensiones (sin SNI ni ALPN — ya están contadas en la parte a) y de la lista de algoritmos de firma en el orden original.

La ordenación soluciona el problema de Chrome: el reordenamiento de extensiones no cambia la huella. Y las partes separadas permiten buscar coincidencias parciales: por ejemplo, todos los clientes con el mismo conjunto de cifrados (misma parte b) pero con extensiones diferentes.

Para depuración hay variantes “crudas”: JA4_r — mismas listas sin hasheo, JA4_o — en el orden original, sin ordenar.

Familia JA4+. Además de JA4 para clientes TLS, FoxIO describió:

  • JA4S — respuesta del servidor (ServerHello);
  • JA4H — cliente HTTP: método, versión, presencia de cookie y Referer, número de cabeceras, su orden, idioma;
  • JA4X — manera en que se generó el certificado X.509;
  • JA4L — latencia y distancia al cliente;
  • JA4T, JA4TS — parámetros TCP (tamaño de ventana, opciones);
  • JA4SSH — sesiones SSH.

Licencia. El propio JA4 se distribuye bajo la licencia BSD 3-Clause, igual que JA3. Los demás métodos JA4+ están bajo la FoxIO License 1.1: pueden usarse gratuitamente para proteger a la propia compañía y en investigaciones, pero un fabricante que venda un producto que incluya estas huellas necesita una licencia comercial.

Dónde se usan las huellas

Protección contra bots. Cloudflare, Akamai, AWS WAF y otros sistemas de protección comparan la huella con el User-Agent declarado y con una base de clientes conocidos. Un script en Python con User-Agent de navegador recibe captcha o 403. Cloudflare permite usar los campos cf.bot_management.ja3_hash y cf.bot_management.ja4 en reglas WAF en los planes con Bot Management.

Huella HTTP/2. Además de TLS, se distinguen clientes por parámetros de HTTP/2: los valores en el frame SETTINGS, el tamaño de ventana, prioridades y el orden de los pseudocabeceras. Esa huella se llama “huella Akamai” por la compañía que publicó el método.

Detección de malware. Sistemas de detección de intrusiones (Suricata, Zeek) calculan JA3/JA4 para cada conexión, y el analista busca huellas de programas y herramientas conocidas como Cobalt Strike, sin descifrar el tráfico.

DPI y bloqueos. El equipo de filtrado por huella de ClientHello distingue navegador de cliente VPN o proxy, que usan TLS para camuflarse. Por eso las modernas herramientas de evasión de bloqueos (Xray con el protocolo REALITY, sing-box) no forman el ClientHello por sí mismas, sino que copian la huella de un navegador mediante la biblioteca uTLS.

Inventario. En una red corporativa se ve por las huellas qué programas acceden a Internet: bibliotecas TLS obsoletas, clientes inesperados, scripts hechos a medida.

Suplantación de la huella

La huella la determina la biblioteca TLS, por eso sólo puede suplantarse usando otra biblioteca o sus ajustes:

  • uTLS — biblioteca para Go que forma el ClientHello byte a byte como el de un navegador elegido;
  • curl-impersonate — compilación de curl con BoringSSL y ajustes que replican Chrome, y con NSS — que replican Firefox, incluyendo la huella HTTP/2 y el orden de cabeceras;
  • curl_cffi — wrapper sobre curl-impersonate para Python.

Cambiar el User-Agent, las cabeceras o el proxy no cambia la huella. Y a la inversa: una coincidencia total con el navegador a nivel TLS pero discrepancias en HTTP/2, el orden de cabeceras o el comportamiento de JavaScript también se detectan. Las huellas son uno de los indicios, no un veredicto definitivo: detrás de un JA4 hay millones de navegadores idénticos, y no se puede distinguir a un usuario concreto por ello.

Cómo averiguar tu huella

Mediante un servicio. Abra en el navegador o solicite con curl https://tls.peet.ws/api/all — el servicio devolverá JSON con las huellas de su cliente: tls.ja3, tls.ja3_hash, tls.ja4, tls.ja4_r y la huella HTTP/2 http2.akamai_fingerprint_hash.

bash
curl -s https://tls.peet.ws/api/all | python3 -c \
  'import json,sys; d=json.load(sys.stdin); print(d["tls"]["ja3_hash"], d["tls"]["ja4"], d["http_version"])'

Resultados con distintos clientes. Medición en septiembre de 2026, tres solicitudes por cliente:

ClienteJA3JA4Protocolo
curl 8.7.1, macOS (LibreSSL)375c6162…t13d497h2_0d8feac7bc37_7395dae3b2f3h2
curl 8.22, Alpine (OpenSSL 3.5)446fb8bd…t13d3012h2_1d37bd780c83_882d495ac381h2
Python urllib, macOS (OpenSSL 3)4bdac5ab…t13d1713h1_ab0a1bf427ad_89ab6efea773HTTP/1.1
Python requests, Debian (OpenSSL 3)86dab210…t13d1713h1_ab0a1bf427ad_8537cf56674eHTTP/1.1
Node.js 26, fetch98384658…t13d5212h1_b262b3658495_8e6e362c5each2
Go 1.27, net/http03117a8e…t13d1312h2_f57a46bbacb6_f50d94e863ebh2
curl-impersonate, perfil Chrome 116cambia: 0ea31aef…, 97ca64e9…t13d1516h2_8daaf6152771_e5627efa2ab1h2

Qué se observa en la tabla:

  • cada cliente tiene su propia huella, y el User-Agent no la afecta. Un script en Python que se llame Chrome seguirá mostrando t13d1713h1_…;
  • la parte a se lee sin necesidad de referencia: Python ofrece 17 cifrados y 13 extensiones y pone primero en ALPN http/1.1 (h1), Go — 13 cifrados y 12 extensiones y h2; curl en macOS con LibreSSL ofrece 49 cifrados, incluidos obsoletos;
  • misma parte b para Python urllib y requests (ab0a1bf427ad) — el mismo conjunto de cifrados de OpenSSL; la diferencia en la parte c — extensiones y algoritmos de firma distintos en distintas compilaciones;
  • JA3 del perfil Chrome cambia en cada solicitud, mientras que JA4 permanece como t13d1516h2_8daaf6152771_e5627efa2ab1, que es el ejemplo de huella de Chrome en la especificación JA4. Así se ve el reordenamiento de extensiones;
  • el servicio no lo calcula perfectamente: en curl en macOS en la parte a aparece 497 en lugar de 4907 — el número de extensiones no se rellenó con cero hasta dos dígitos. Al comparar huellas de distintas fuentes, verifique que las calculen de la misma forma.

Abra la misma página en su navegador varias veces seguidas: JA3 cambiará, JA4 no.

En Wireshark. A partir de la versión 4.2, Wireshark calcula las huellas por sí mismo. En el ClientHello analizado hay campos tls.handshake.ja3, tls.handshake.ja3_full y tls.handshake.ja4; puede añadirlos como columna y filtrar:

tls.handshake.ja4 == "t13d1516h2_8daaf6152771_e5627efa2ab1"

Desde la línea de comandos:

bash
tshark -r capture.pcap -Y 'tls.handshake.type == 1' \
  -T fields -e ip.src -e tls.handshake.extensions_server_name -e tls.handshake.ja4

En su propio servidor. Nginx no calcula huellas; para eso hay módulos externos y proxies separados (por ejemplo, fingerproxy — proxy inverso en Go que pasa JA3, JA4 y la huella HTTP/2 a la aplicación en cabeceras). En sitios detrás de Cloudflare las huellas están disponibles en las reglas WAF y en los logs en los planes con Bot Management.

Cuándo usar y cuándo no

Las huellas son útiles:

  • en reglas WAF contra solicitudes automatizadas, cuando el User-Agent declara ser navegador pero la huella indica biblioteca;
  • en investigaciones de incidentes: buscar todas las conexiones de una misma herramienta en la red;
  • para permitir acceso a una API solo a determinados clientes dentro de la compañía (como indicador adicional, no único).

No conviene basarse en ellas:

  • como autenticación — la huella puede falsificarse;
  • para bloquear mediante una “lista negra” de huellas sin verificación: una biblioteca popular tiene un JA4 con millones de clientes legítimos, y junto con el bot bloqueará, por ejemplo, a todos los usuarios de la app móvil que use esa biblioteca;
  • para rastrear a un usuario concreto — la huella describe el programa, no a la persona.

Errores típicos

  • Reglas basadas en JA3 para navegadores después de 2023 — la huella de Chrome y Firefox cambia en cada conexión.
  • Las huellas se calculan en el servidor detrás de una CDN o balanceador que termina TLS — verá la huella del balanceador y no la del cliente.
  • Bloquear por huella tras actualizar la biblioteca cliente de sus propios usuarios — nuevas versiones de OpenSSL y navegadores cambian el conjunto de extensiones (por ejemplo, con la aparición de X25519MLKEM768).

// Tarea parecida

Si estas resolviendo algo parecido

Este articulo pertenece a uno de los temas principales de trabajo. Puedes seguir leyendo sobre el tema, ir a la pagina principal para entender a que me dedico o abrir directamente los servicios.

Tema del articulo

Seguridad y proteccion

SSL, hardening, accesos, proteccion de servicios y configuraciones seguras.

Tareas frecuentes de esta tema

  • Configurar SSL, certificados y conexiones seguras
  • Restringir accesos y cerrar puntos de entrada innecesarios
  • Reforzar la configuracion del servidor y los servicios

// Siguiente paso

Si necesitas ayuda con este tema y no solo otro articulo, es mejor ir directo a la pagina del servicio. La pagina principal y la seleccion de materiales quedan como rutas secundarias.

Abrir servicios

// Contact

¿Necesitas ayuda?

Escríbeme y te ayudaré a resolver el problema

Respondo en un día laborable (03:00-13:00 GMT)

Или оставьте заявку здесь:

Confirme que no es un bot.

Escribir y recibir una respuesta rápida