Volver al blog

Cómo eludir el fingerprinting TLS/JA4 en 2026: curl_cffi y la suplantación de navegador en la práctica

¿Compraste proxies residenciales y el sitio aún da 403 en la primera solicitud? Te están identificando por el apretón de manos TLS incluso antes de los encabezados HTTP. Analizamos el fingerprinting JA3/JA4 y cómo eludirlo en cinco minutos a través de curl_cffi y la suplantación de navegador — con código, verificación de huella digital y selección de proxy.

📅21 de julio de 2026
Cómo eludir el fingerprinting TLS/JA4 en 2026: curl_cffi y la suplantación de navegador en la práctica
```html

Has comprado proxies residenciales, has configurado un nuevo User-Agent de Chrome, y el sitio aún devuelve 403 en la primera solicitud. ¿Te suena familiar? El problema no está en la IP ni en los encabezados. Te han detectado antes de que el servidor haya leído siquiera un encabezado HTTP, a través del apretón de manos TLS. En 2026, este es el vector de detección número 1, y un simple requests lo falla automáticamente. Vamos a analizar cómo funciona y cómo solucionarlo con unas pocas líneas de código a través de curl_cffi.

Qué está pasando: te detecta el apretón de manos TLS

Cuando un cliente establece una conexión HTTPS, primero envía un paquete ClientHello, incluso antes de cualquier HTTP. En él se enumeran: la versión de TLS, la lista de conjuntos de cifrado soportados (cipher suites), extensiones de TLS (SNI, ALPN, supported_groups), curvas elípticas y formatos de puntos. El orden y la composición de estos campos varían entre diferentes clientes y se pueden identificar antes de que el cliente pronuncie una sola palabra.

De estos campos se calcula una huella digital. JA3 (estándar de 2017) toma una cadena del tipo TLSVersion,Ciphers,Extensions,EllipticCurves,ECPointFormats y la hash MD5, obteniendo una firma de 32 caracteres. El problema de JA3 es que desde enero de 2023, Chrome aleatoriza el orden de las extensiones: 16 extensiones dan 16! (más de 20 billones) de combinaciones, y el mismo navegador produce diferentes JA3.

Por lo tanto, la industria ha pasado a JA4 (FoxIO, implementación masiva 2024–2025). JA4 ordena los códigos de extensión por valor hexadecimal antes de la hash, por lo que la aleatorización de Chrome ya no lo rompe. La hash es un SHA-256 truncado, el formato es legible y de tres partes (a_b_c), e incluye ALPN y soporte para QUIC/HTTP3. Por ejemplo: Chrome 124 produce t13d1516h2 (15 cifrados, 16 extensiones, ALPN h2), mientras que Python puro requests genera t13d1715h2. Para un anti-bot, la segunda firma es un marcador directo de "esto es un script".

Por qué en 2026 no puedes prescindir de esto

La detección JA4 está integrada en todos los grandes proveedores: Cloudflare compara la huella contra listas permitidas, Akamai añade un hash separado para los marcos de configuración HTTP/2, DataDome compara con una base de datos de bots conocidos. La lógica es simple y letal: si envías User-Agent: Chrome 131, pero la huella TLS grita "urllib3/OpenSSL", hay un desincronización, y te bloquean de inmediato. Ningún proxy te salva: una IP residencial perfecta con la huella de Python requests aún pierde.

Por esta razón, la combinación de "proxy + falsificación de huella" se ha convertido en 2026 en una higiene básica del scraping, y no en una opción para avanzados.

Solución: curl_cffi en 5 minutos

curl_cffi es un envoltorio de Python sobre curl-impersonate (curl modificado, construido con BoringSSL de Chrome o NSS de Firefox en lugar de OpenSSL). Reproduce un apretón de manos de navegador auténtico y, además, tiene una API casi idéntica a la familiar requests.

Paso 1. Instalación. Los binarios de curl-impersonate para Windows/macOS/Linux se descargan automáticamente:

pip install curl-cffi

Paso 2. Solicitud básica. Cambias la importación y añades un parámetro:

from curl_cffi import requests

resp = requests.get("https://target.com/", impersonate="chrome")
print(resp.status_code)
print(resp.http_version)  # HTTP/2 — como en un navegador real

Una línea impersonate="chrome" falsifica inmediatamente cuatro capas: la huella TLS (JA3/JA4), la versión HTTP (HTTP/2 en lugar de HTTP/1.1), el orden de los encabezados y las negociaciones ALPN.

Paso 3. Siempre usa el alias genérico, no fijes la versión. Escribe impersonate="chrome" (o "safari", "safari_ios") — el alias se resolverá automáticamente en el perfil más reciente. Un impersonate="chrome124" se volverá obsoleto: Chrome se actualiza cada ~4 semanas, y el perfil antiguo se convertirá en una anomalía. Los objetivos confiables son Chrome, Edge y Safari/iOS (perfiles de chrome99 a chrome131, safari15–18).

Paso 4. Proxies y sesiones. Para un scraping real, mantén el estado en una sesión y conecta proxies. Una IP residencial o móvil es obligatoria aquí: la IP de centro de datos se detecta por ASN, independientemente de TLS:

from curl_cffi import requests

session = requests.Session(impersonate="chrome")

headers = {
    "Accept-Language": "en-US,en;q=0.9",
    "Accept-Encoding": "gzip, deflate, br",
    "Referer": "https://www.google.com/",
}
proxies = {
    "http": "http://user:pass@proxy-host:port",
    "https": "http://user:pass@proxy-host:port",
}

resp = session.get("https://target.com", headers=headers, proxies=proxies)

Paso 5. Asincronía para volumen. A diferencia de requests, curl_cffi tiene async y HTTP/2 de forma nativa:

import asyncio
from curl_cffi.requests import AsyncSession

async def fetch(session, url):
    r = await session.get(url, impersonate="chrome")
    return r.status_code

async def main(urls):
    async with AsyncSession() as session:
        return await asyncio.gather(*[fetch(session, u) for u in urls])

asyncio.run(main(["https://target.com"] * 20))

Verifica tu huella — no adivines

Antes de enviar tráfico real, asegúrate de que la falsificación realmente funcione. Envía una solicitud a verificadores públicos y compara JA4 con el de un navegador de referencia:

  • tls.peet.ws — devuelve JA3, JA4, huella de Akamai y marcos HTTP/2 en JSON. Solicítalo a través de curl_cffi y a través de un Chrome real, y compara los hashes.
  • ja4db.com — base de datos de JA4 conocidos, ayuda a entender a quién te pareces.
  • browserleaks.com/tls y la herramienta JA3/JA4 de Scrapfly — desglose detallado de los campos.

En staging, es conveniente colocar mitmproxy entre el scraper y el objetivo y monitorear el hash JA4 real de cada solicitud.

Diagnóstico: ¿sigues recibiendo 403/429?

Si la huella es correcta y los bloqueos persisten, sigue la lista de verificación de lo más común a lo menos común:

  1. IP de centro de datos. Razón número 1. Cambia a proxies residenciales o móviles — por qué una sola huella no es suficiente se detalla en el artículo sobre detección de proxies residenciales a través de IP Intelligence.
  2. Perfil obsoleto. pip install -U curl-cffi y alias genérico "chrome".
  3. Tasa demasiado alta. Añade pausas aleatorias de 1 a 3 segundos entre solicitudes.
  4. Encabezados desnudos. Asegúrate de enviar Accept-Language, Accept-Encoding, Referer — su ausencia también es una anomalía.
  5. Desincronización entre sesión y IP. Regla: una sesión — una IP durante toda su vida útil.
  6. Estado 200 ≠ éxito. Verifica el cuerpo de la respuesta: bajo el código 200 puede haber una página con CAPTCHA.

Dónde se topa curl_cffi con un muro

curl_cffi cierra la capa de red — y eso es todo. No ejecuta JavaScript. Por lo tanto, es impotente contra desafíos JS: Cloudflare Turnstile, la página "Checking your browser…" (IUAM), la cookie cf_clearance que establece el script después de la verificación, todo esto requiere un entorno de navegador real. Por qué en 2026 los solucionadores de CAPTCHA casi han dejado de funcionar contra tales sistemas preventivos, lo hemos analizado en un análisis separado sobre eludir CAPTCHA.

Qué hacer cuando te topas con un muro de JS:

  • Híbrido. Playwright o Nodriver ejecuta el desafío y obtiene cf_clearance, luego la cookie se pasa a un rápido curl_cffi para la mayoría de las solicitudes — así pagas por un navegador pesado una sola vez.
  • Servicios de solucionadores (CapSolver, 2Captcha) para la emisión automática de tokens.
  • API de scraping gestionado, si no quieres mantener la infraestructura.

Y recuerda sobre la seguridad de los hilos: cada hilo debe tener su propia sesión. Fija la versión de curl-cffi en requirements.txt y revisa los perfiles cada 6 a 12 semanas, cuando los navegadores se actualicen.

Alternativas a curl_cffi

  • tls-client — envoltorio sobre la biblioteca Go basada en uTLS, con perfiles (chrome_124, safari_ios_17) y la bandera random_tls_extension_order=True. Ajuste flexible y fino de la huella.
  • primp — cliente en Rust, permite establecer impersonate_os de forma independiente y ofrece mayor capacidad; desventaja — la API no coincide completamente con requests y la biblioteca es más nueva.

Qué proxy necesitas y por qué

La falsificación de huellas y los proxies resuelven diferentes mitades de una misma tarea: curl_cffi aborda la cuestión de "cómo se ve la conexión", el proxy — "de dónde viene". Un anti-bot verifica ambas señales de forma independiente, por lo que un JA4 perfecto con un ASN de centro de datos negro es inútil. Para objetivos protegidos (marketplaces, redes sociales, agregadores de viajes), utiliza proxies residenciales o móviles: tienen un origen operativo limpio, y los móviles además se ocultan tras el efecto CGNAT "efecto de multitud". Deja el centro de datos para objetivos no sensibles y alto volumen.

Conclusión

En 2026, el scraping es un juego de identidades, no solo de IP. Un requests desnudo se presenta como un script a nivel de apretón de manos TLS y pierde antes de que se envíe el primer encabezado. Cambiar la importación a curl_cffi con impersonate="chrome" elimina esta falla en cinco minutos, pero solo funciona en combinación con una IP residencial o móvil limpia y con la comprensión del límite: la capa de red — sí, desafíos JavaScript — no. Construye tu stack de manera honesta: huella correcta, proxy correcto, híbrido con navegador donde haya un muro de JS — y el 403 en la primera solicitud quedará en el pasado.

```