Cómo resolver el fingerprinting TLS en n8n con CapSolver

Adélia Cruz
Neural Network Developer
18-Mar-2026

Si alguna vez has intentado extraer datos de un sitio web protegido por detección de bots de nivel empresarial, probablemente hayas encontrado un muro invisible: tus solicitudes se bloquean incluso aunque tus encabezados, cookies y User-Agent sean perfectos. La razón: fingerprinting TLS — y ocurre antes de que se envíe la solicitud HTTP.
Servicios anti-bot como Cloudflare, Akamai, DataDome y otros inspeccionan el handshake TLS para determinar si el cliente es un navegador real o una herramienta de automatización. Los clientes HTTP estándar — Go's net/http, Python's requests, curl, Node.js axios — tienen huellas dactilares TLS distintas que se detectan inmediatamente.
En esta guía, construirás un servidor Go ligero usando httpcloak que imita una huella dactilar TLS de Chrome real, y lo conectarás a tus flujos de trabajo de n8n para que cada solicitud HTTP parezca tráfico de navegador Chrome genuino a nivel de red.
¿Qué es el fingerprinting TLS?
Cada vez que un cliente se conecta a un sitio web mediante HTTPS, inicia un handshake TLS enviando un mensaje ClientHello. Este mensaje contiene:
- Conjuntos de cifrado — los algoritmos de cifrado que el cliente admite, y su orden
- Extensiones TLS — características como SNI, ALPN, grupos compatibles, algoritmos de firma
- Curvas elípticas y formatos de puntos — parámetros criptográficos
- Versión TLS — la máxima versión TLS admitida
Los servicios anti-bot extraen estos valores y calculan un fingerprint — llamado JA3 o JA4 — que identifica de forma única el software del cliente. Cada navegador, biblioteca HTTP y entorno de lenguaje de programación produce un fingerprint diferente.
| Cliente | Fingerprint JA3 | Detectado como |
|---|---|---|
| Chrome 145 | Hash único que coincide con el orden de los conjuntos de cifrado de Chrome | Navegador real |
| Firefox 130 | Hash diferente — Firefox utiliza preferencias de cifrado diferentes | Navegador real |
Go net/http |
Hash completamente diferente — la pila TLS de Go es obvia | Bot / herramienta de automatización |
Python requests |
Otro hash distinto — el TLS de urllib3 de Python es identificable |
Bot / herramienta de automatización |
| curl | Otro hash — el fingerprint TLS de curl es bien conocido | Bot / herramienta de automatización |
Node.js axios |
Fingerprint TLS de Node.js — se detecta fácilmente | Bot / herramienta de automatización |
La clave es: el fingerprinting TLS ocurre durante el handshake, antes de enviar cualquier encabezado HTTP. Ningún tipo de manipulación de encabezados puede corregir un fingerprint TLS no navegador.
¿Por qué los clientes HTTP estándar fallan?
Cuando un navegador se conecta a un sitio web mediante HTTPS, envía un ClientHello TLS que incluye detalles sobre sus conjuntos de cifrado, extensiones y configuraciones admitidos. Los servicios anti-bot registran este fingerprint (llamado fingerprint JA3 o JA4) y lo comparan con perfiles de navegadores conocidos.
Go's net/http, Python's requests, curl y la mayoría de las bibliotecas HTTP tienen huellas dactilares TLS distintas. Incluso con cookies y encabezados correctos, los sistemas anti-bot bloquearán la solicitud si detectan un fingerprint TLS no navegador.
Esto es lo que ocurre paso a paso:
- Tu flujo de trabajo de n8n envía una solicitud HTTP a un sitio protegido
- Comienza el handshake TLS — tu cliente envía su
ClientHello - El servicio anti-bot registra el fingerprint JA3/JA4 del handshake
- El fingerprint coincide con Go/Python/Node.js — no con Chrome o Firefox
- La solicitud se bloquea, se desafía o se muestra una página de engaño — antes de que se evalúen tus encabezados
Por eso establecer User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) ... no ayuda. El User-Agent es un encabezado de nivel HTTP. El fingerprinting TLS opera en una capa inferior. Si tu User-Agent dice Chrome pero tu fingerprint TLS dice Go, la solicitud se detecta inmediatamente.
¿Quién usa el fingerprinting TLS?
El fingerprinting TLS se ha convertido en una práctica estándar en la protección contra bots empresarial. Estos son los principales servicios que verifican los fingerprints TLS:
| Servicio anti-bot | Verificación TLS | Notas |
|---|---|---|
| Cloudflare Bot Management | Sí | Desafío de "Verificando tu navegador..." en toda la página. Verifica JA3/JA4 en cada solicitud |
| Akamai Bot Manager | Sí | Usa el fingerprint TLS como una de las señales en la puntuación de bots |
| DataDome | Sí | Analiza el fingerprint TLS junto con señales de comportamiento |
| Muchos otros | Varía | El fingerprinting TLS se está convirtiendo en estándar en la protección contra bots empresarial |
CapSolver admite resolver desafíos de muchos de estos servicios. El servidor TLS de esta guía está diseñado para funcionar junto con cualquier flujo de trabajo de resolución de captchas donde la última solicitud HTTP necesite parecer tráfico de navegador real — ya sea que estés evadiendo el desafío de Cloudflare, Akamai, DataDome u otro sistema anti-bot.
Requisitos previos
| Requisito | Notas |
|---|---|
| n8n autohospedado | Requerido — el servidor TLS debe ejecutarse en la misma máquina que n8n. n8n Cloud no es adecuado. |
| Go 1.21+ | Debe estar instalado en el servidor. Verificar con go version. |
| Gestor de procesos (recomendado) | Cualquier gestor de procesos (systemd, supervisor, Docker, PM2) para mantener el servidor TLS en ejecución tras reinicios |
Paso 1 — Crear el servidor TLS
El servidor TLS es un servidor HTTP ligero de Go que acepta solicitudes en el puerto 7878 y las reenvía usando el conjunto de configuración de Chrome-145 de httpcloak.
Crear el archivo de código
bash
mkdir -p ~/tls-server && cd ~/tls-server
Crea un archivo llamado main.go con el siguiente contenido:
go
package main
import (
"context"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"strings"
"time"
"github.com/sardanioss/httpcloak/client"
)
type FetchRequest struct {
URL string `json:"url"`
Method string `json:"method"`
Headers map[string]string `json:"headers"`
Proxy string `json:"proxy"`
Body string `json:"body"`
}
type FetchResponse struct {
Status int `json:"status"`
Body string `json:"body"`
Headers map[string][]string `json:"headers"`
}
type ErrorResponse struct {
Error string `json:"error"`
}
func writeError(w http.ResponseWriter, status int, msg string) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(ErrorResponse{Error: msg})
}
func fetchHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
writeError(w, http.StatusMethodNotAllowed, "solo se permite POST")
return
}
var req FetchRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeError(w, http.StatusBadRequest, "JSON inválido: "+err.Error())
return
}
if req.URL == "" {
writeError(w, http.StatusBadRequest, "url es requerido")
return
}
if req.Method == "" {
req.Method = "GET"
}
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
c := client.NewClient("chrome-145", client.WithTimeout(60*time.Second))
defer c.Close()
if req.Proxy != "" {
c.SetProxy(req.Proxy)
}
headers := make(map[string][]string, len(req.Headers))
var userAgent string
for k, v := range req.Headers {
lower := strings.ToLower(k)
if lower == "user-agent" {
userAgent = v
} else {
headers[k] = []string{v}
}
}
var bodyReader io.Reader
if req.Body != "" {
bodyReader = strings.NewReader(req.Body)
}
hcReq := &client.Request{
Method: strings.ToUpper(req.Method),
URL: req.URL,
Headers: headers,
Body: bodyReader,
UserAgent: userAgent,
FetchMode: client.FetchModeNavigate,
}
resp, err := c.Do(ctx, hcReq)
if err != nil {
writeError(w, http.StatusBadGateway, "falló la búsqueda: "+err.Error())
return
}
body, err := resp.Text()
if err != nil {
writeError(w, http.StatusInternalServerError, "falló la lectura del cuerpo: "+err.Error())
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(FetchResponse{
Status: resp.StatusCode,
Body: body,
Headers: resp.Headers,
})
}
func main() {
const port = "7878"
mux := http.NewServeMux()
mux.HandleFunc("/fetch", fetchHandler)
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
fmt.Fprint(w, `{"status":"ok"}`)
})
log.Printf("Servidor TLS (httpcloak chrome-145) escuchando en :%s", port)
log.Fatal(http.ListenAndServe(":"+port, mux))
}
Inicializar y compilar
bash
go mod init tls-server
go get github.com/sardanioss/httpcloak/client
go build -o main main.go
Ejecutar el servidor
bash
./main
El servidor se ejecuta en primer plano. Para mantenerlo en ejecución en segundo plano, use cualquier gestor de procesos (systemd, supervisor, Docker, etc.) o ejecútelo en una sesión screen/tmux.
Verificar que funciona (en una nueva terminal)
bash
curl http://localhost:7878/health
Esperado: {"status":"ok"}
Nota: El servidor TLS debe ejecutarse en la misma máquina que tu instancia de n8n. El flujo de trabajo de n8n lo llama en
http://localhost:7878/fetch.
Paso 2 — Permitir que n8n llame a localhost
De forma predeterminada, n8n bloquea los nodos de solicitud HTTP que intentan llamar a direcciones localhost (protección contra SSRF). Debes deshabilitar esto para que tus flujos puedan acceder al servidor TLS en localhost:7878.
Agrega la variable de entorno N8N_BLOCK_ACCESS_TO_LOCALHOST=false y reinicia tu instancia de n8n. Cómo lo haces depende de cómo ejecutes n8n:
Si ejecutas n8n directamente:
bash
export N8N_BLOCK_ACCESS_TO_LOCALHOST=false
n8n start
Si usas Docker:
Agrega -e N8N_BLOCK_ACCESS_TO_LOCALHOST=false a tu comando docker run, o agrégalo a la sección environment en tu docker-compose.yml.
Paso 3 — Usar el servidor TLS desde n8n
El servidor TLS expone un único endpoint que acepta cualquier solicitud HTTP y la reenvía con un fingerprint TLS de Chrome.
Referencia de API
Endpoint: POST http://localhost:7878/fetch
Cuerpo de la solicitud (JSON):
json
{
"url": "https://example.com",
"method": "GET",
"headers": {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36",
"cookie": "cf_clearance=abc123; session=xyz"
},
"proxy": "http://user:pass@host:port",
"body": ""
}
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
url |
string | Sí | La URL objetivo a consultar |
method |
string | No | Método HTTP — predeterminado a GET |
headers |
objeto | No | Pares clave-valor de encabezados HTTP a enviar |
proxy |
string | No | URL del proxy en formato http://user:pass@host:port |
body |
string | No | Cuerpo de la solicitud (para solicitudes POST/PUT) |
Respuesta (JSON):
json
{
"status": 200,
"body": "<html>...</html>",
"headers": { "content-type": ["text/html"], "..." : ["..."] }
}
Configurar el nodo de solicitud HTTP de n8n
Para llamar al servidor TLS desde un flujo de trabajo de n8n, usa un nodo de solicitud HTTP con estas configuraciones:
| Parámetro | Valor | Descripción |
|---|---|---|
| Método | POST |
Siempre POST al servidor TLS |
| URL | http://localhost:7878/fetch |
Endpoint del servidor TLS local |
| Tipo de contenido | Bruto |
No uses JSON — el modo JSON de n8n serializa incorrectamente |
| Tipo de contenido bruto | application/json |
Indica al servidor TLS que el cuerpo es JSON |
| Cuerpo | ={{ JSON.stringify({ url: "...", method: "GET", headers: {...}, proxy: "..." }) }} |
La solicitud real a reenviar |
Importante: Usar
contentType: "json"conJSON.stringify()en el cuerpo hace que n8n duplique la serialización, enviando{"": ""}en lugar de tus datos. Siempre usacontentType: "bruto"conrawContentType: "application/json".
Ejemplo: Consultar una página protegida
En la expresión del cuerpo del nodo de solicitud HTTP:
javascript
={{ JSON.stringify({
url: "https://protected-site.com/data",
method: "GET",
headers: {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36",
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"accept-language": "en-US,en;q=0.9"
},
proxy: "http://user:pass@proxy-host:8080"
}) }}
El servidor TLS reenviará esta solicitud con un fingerprint TLS de Chrome-145, y el sitio objetivo verá una conexión de navegador Chrome genuino.
Pruebalo
Prueba directamente el servidor TLS desde la línea de comandos:
bash
curl -X POST http://localhost:7878/fetch \
-H "Content-Type: application/json" \
-d '{
"url": "https://tls-check.example.com",
"method": "GET",
"headers": {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36"
}
}'
Puedes verificar tu fingerprint TLS apuntando el servidor a un verificador de fingerprints JA3/JA4 — el resultado debe coincidir con un navegador Chrome real, no con un cliente de biblioteca Go.
Importar este flujo de trabajo
Este flujo de trabajo crea un punto de entrada de webhook que reenvía cualquier solicitud a través del servidor TLS con un fingerprint TLS de Chrome. Envía un POST con url, method, headers y proxy opcional — el flujo lo pasa a localhost:7878/fetch y devuelve el resultado.
Webhook (POST /tls-fetch) → Consulta a través del servidor TLS → Responder al webhook
Copia el JSON a continuación y cópialo en n8n mediante Menú → Importar desde JSON.
Haga clic para expandir el JSON del flujo de trabajo
json
{
"name": "TLS Fetch — Proxy con Fingerprint de Chrome",
"nodes": [
{
"parameters": {
"content": "## TLS Fetch — Proxy con Fingerprint de Chrome\n\n**¿Para quién es?** Desarrolladores que necesitan solicitudes HTTP con huellas dactilares TLS de navegador auténticas.\n\n**¿Qué hace?** Proxy de solicitudes HTTP a través de un servidor TLS de Go (httpcloak) que imita el fingerprint TLS de Chrome, evadiendo la detección de bots.\n\n**¿Cómo funciona?**\n1. El webhook recibe la URL objetivo y los detalles de la solicitud\n2. La solicitud se reenvía al servidor TLS local con el fingerprint de Chrome\n3. La respuesta se devuelve al llamador\n\n**Configuración:**\n1. Asegúrate de que el servidor TLS (httpcloak) esté ejecutándose en el puerto 7878\n2. Activa el flujo de trabajo\n3. Envía un POST a la URL del webhook con tus detalles de solicitud",
"height": 494,
"width": 460,
"color": 1
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-720,
-300
],
"id": "sticky-blog-main-1773678228122-1",
"name": "Nota Pegajosa"
},
{
"parameters": {
"httpMethod": "POST",
"path": "tls-fetch",
"responseMode": "responseNode",
"options": {}
},
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [
-200,
0
],
"id": "tls00001-0001-0001-0001-000000000001",
"name": "Recibir Solicitud del Solucionador",
"webhookId": "tls00001-aaaa-bbbb-cccc-000000000001"
},
{
"parameters": {
"method": "POST",
"url": "http://localhost:7878/fetch",
"sendBody": true,
"contentType": "raw",
"rawContentType": "application/json",
"body": "={{ JSON.stringify(json.body) }}",
"options": {
"timeout": 60000
}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.3,
"position": [
100,
0
],
"id": "tls00001-0001-0001-0001-000000000002",
"name": "Fetch via TLS Server"
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ JSON.stringify(json) }}",
"options": {}
},
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.5,
"position": [
400,
0
],
"id": "tls00001-0001-0001-0001-000000000003",
"name": "Respond to Webhook"
}
],
"connections": {
"Receive Solver Request": {
"main": [
[
{
"node": "Fetch via TLS Server",
"type": "main",
"index": 0
}
]
]
},
"Fetch via TLS Server": {
"main": [
[
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
}
}
``
Conclusión
Has configurado un servidor de suplantación de huella dactilar TLS que hace que las solicitudes HTTP de n8n parezcan tráfico de navegador Chrome auténtico a nivel de red. Esto es esencial para capturar sitios web protegidos por servicios anti-bot que inspeccionan las huellas dactilares TLS.
Este servidor TLS es útil para evitar:
- Cloudflare Bot Management — desafíos de página completa que verifican las huellas dactilares TLS
- Akamai Bot Manager — detección de bots empresarial mediante análisis TLS
- DataDome — análisis de comportamiento + huella dactilar TLS
- PerimeterX / HUMAN — fingerprinting de dispositivo + TLS
- Muchos otros servicios anti-bot que soporta CapSolver
La biblioteca httpcloak con su configuración predeterminada de Chrome-145 maneja la suplantación de huellas JA3/JA4, los marcos SETTINGS de HTTP/2, la negociación ALPN y el orden de los encabezados, haciendo que tus solicitudes sean indistinguibles de un navegador Chrome real a nivel TLS.
¿Necesitas resolver CAPTCHAs junto con la suplantación TLS? Consulta CapSolver — se integra directamente con n8n como un nodo oficial y soporta Cloudflare Challenge, Turnstile, reCAPTCHA y muchos más. Usa el código de bonificación n8n para obtener un 8% adicional en tu primer recarga!

Preguntas frecuentes
¿Qué es la fingerprinting TLS?
La fingerprinting TLS es una técnica en la que los servidores analizan las características de tu mensaje ClientHello TLS — incluyendo suites de cifrado, extensiones y su orden — para identificar qué software está realizando la conexión. Cada cliente HTTP (Chrome, Firefox, curl, Go, Python) tiene un patrón de huella dactilar único.
¿Por qué no puedo simplemente establecer el encabezado User-Agent en Chrome?
El encabezado User-Agent es un atributo de nivel HTTP. La fingerprinting TLS ocurre a un nivel inferior — durante el handshake TLS, antes de que se envíen los encabezados HTTP. Los servicios anti-bot comparan ambos niveles: si tu User-Agent dice Chrome pero tu huella dactilar TLS dice Go/Python, la solicitud se marca como un bot.
¿Qué es httpcloak?
httpcloak es una biblioteca de Go que suplanta perfiles TLS reales de navegadores. Maneja la coincidencia de huellas JA3/JA4, los marcos SETTINGS de HTTP/2, la negociación ALPN y el orden de los encabezados. La configuración predeterminada chrome-145 hace que las conexiones sean indistinguibles de un navegador Chrome real 145.
¿Puedo usar una configuración de Chrome diferente?
Sí. httpcloak soporta múltiples configuraciones de navegadores. Consulta la documentación de httpcloak para ver las configuraciones disponibles. Para cambiar la configuración, modifica client.NewClient("chrome-145", ...) en main.go a tu perfil de navegador deseado.
¿Funciona esto con n8n Cloud?
No de forma sencilla. El servidor TLS es un binario de Go local que debe ejecutarse en la misma máquina que n8n para que los flujos de trabajo puedan llamar a http://localhost:7878/fetch. n8n Cloud no permite ejecutar servicios locales junto con los flujos de trabajo. Necesitas una instancia de n8n autohospedada.
¿Puedo ejecutar el servidor TLS en una máquina diferente?
Sí, pero deberás actualizar la URL en tus nodos de solicitud HTTP de n8n de http://localhost:7878/fetch a http://tu-ip-del-servidor:7878/fetch, y asegurarte de que el puerto 7878 esté accesible. También deberás deshabilitar la protección SSRF de n8n o agregar la IP del servidor a la lista blanca.
¿Cómo actualizo la configuración de Chrome cuando se libera una nueva versión?
Actualiza la dependencia httpcloak: go get -u github.com/sardanioss/httpcloak/client, cambia la cadena de configuración en main.go a la nueva versión, reconstruye con go build -o main main.go y reinicia el servidor.
¿Soporta el servidor TLS solicitudes concurrentes?
Sí. El servidor HTTP de Go maneja solicitudes concurrentes nativamente. Cada solicitud crea una nueva instancia de cliente httpcloak con su propia conexión TLS. Para cargas de trabajo de alto volumen, monitorea el uso de memoria ya que cada conexión mantiene su propio estado TLS.
¿Cuál es la sobrecarga de rendimiento?
El servidor TLS añade un retardo mínimo — típicamente 10-50 ms para el salto del proxy local. La mayor parte del tiempo de la solicitud se pasa en la conexión HTTPS real al objetivo. El handshake TLS de Chrome es ligeramente más pesado que el predeterminado de Go, pero esto es despreciable en la práctica.
¿Cómo mantengo el servidor TLS en ejecución después de reiniciar el servidor?
Usa cualquier gestor de procesos — systemd, supervisor, Docker, o similares — para registrar el servidor TLS como un servicio que se inicie al arrancar. Para una configuración rápida, también puedes ejecutarlo dentro de una sesión de screen o tmux.
Aviso de Cumplimiento: La información proporcionada en este blog es solo para fines informativos. CapSolver se compromete a cumplir con todas las leyes y regulaciones aplicables. El uso de la red de CapSolver para actividades ilegales, fraudulentas o abusivas está estrictamente prohibido y será investigado. Nuestras soluciones para la resolución de captcha mejoran la experiencia del usuario mientras garantizan un 100% de cumplimiento al ayudar a resolver las dificultades de captcha durante el rastreo de datos públicos. Fomentamos el uso responsable de nuestros servicios. Para obtener más información, visite nuestros Términos de Servicio y Política de Privacidad.
Máse

Cómo usar CapSolver en n8n: La guía completa para resolver CAPTCHA en tus flujos de trabajo
Aprende cómo integrar CapSolver con n8n para resolver CAPTCHAs y crear flujos de trabajo de automatización confiables con facilidad.

Adélia Cruz
18-Mar-2026

Cómo resolver puzzles visuales en n8n con CapSolver
Resuelve CAPTCHAs visuales con el motor de visión de CapSolver en n8n. Maneja deslizadores, rotación, selección de objetos y OCR de GIF de forma inmediata.

Aloísio Vítor
18-Mar-2026

Cómo resolver el fingerprinting TLS en n8n con CapSolver
Resolver la huella dactilar TLS en n8n con CapSolver. Hacer que las solicitudes parezcan navegadores reales y evitar bloques de detección de bots.

Adélia Cruz
18-Mar-2026

Cómo resolver Cloudflare Turnstile usando CapSolver y n8n
Crea una API de resolución de Cloudflare Turnstile usando CapSolver y n8n. Aprende a automatizar la resolución de tokens, enviarlo a sitios web y extraer datos protegidos sin programación.

Adélia Cruz
10-Mar-2026

