El firewall de aplicaciones web (WAF) de Cloudflare permite a los operadores de sitios crear reglas que activan desafíos CAPTCHA en función de atributos de solicitud específicos: dirección IP, país, ruta URL, puntuación de bot, encabezados o cualquier combinación. Comprender qué reglas desencadenan desafíos le ayuda a diagnosticar por qué está viendo un CAPTCHA y elegir el enfoque correcto para manejarlo.
Acciones de reglas WAF que producen CAPTCHA
Las reglas WAF de Cloudflare admiten varias acciones. Tres de ellos presentan desafíos solucionables:
| Acción WAF | Qué ocurre | Estado HTTP | Método CaptchaAI |
|---|---|---|---|
| Managed Challenge | Cloudflare decide: challenge invisible, Turnstile o JS | 503 | turnstile |
| JS Challenge | Página de challenge de JavaScript de 5 segundos | 503 | cloudflare_challenge |
| Interactive Challenge | CAPTCHA tradicional (heredado, obsoleto) | 403 | turnstile |
| Bloquear | 403 duro, sin challenge | 403 | N/A (no resoluble) |
| Permitir | Pasar, sin control | 200 | N/A |
| Saltar | Saltar las reglas WAF restantes | 200 | N/A |
| Registro | Registrar evento, sin acción | 200 | N/A |
Desafío gestionado (el más común)
Managed Challenge es la acción recomendada por Cloudflare. Decide de forma adaptativa el tipo de desafío por visitante:
WAF rule matches → Managed Challenge triggered
↓
Cloudflare evaluates visitor:
├─ Low risk → Invisible pass (no visible challenge)
├─ Medium risk → Turnstile widget (click to verify)
└─ High risk → JavaScript challenge page
↓
Successful → qa_validation_cookie cookie issued
Patrones de reglas WAF comunes
Los operadores del sitio crean reglas WAF utilizando el lenguaje de expresión de Cloudflare. Estos son los patrones con mayor probabilidad de activar CAPTCHA para tráfico automatizado:
Reglas de puntuación de bots
# Challenge traffic with low bot scores
(cf.bot_management.score lt 30)
→ Action: Managed Challenge
# Challenge non-verified bots
(cf.bot_management.score lt 50 and not cf.bot_management.verified_bot)
→ Action: JS Challenge
Las reglas de puntuación de bots son el desencadenante más común de las herramientas de automatización. Los solucionadores de API de CaptchaAI reciben puntuaciones de nivel humano porque utilizan navegadores reales.
Reglas basadas en países
# Challenge traffic from specific countries
(ip.geoip.country in {"CN" "RU" "VN" "IN"})
→ Action: Managed Challenge
# Block specific regions entirely
(ip.geoip.country eq "XX")
→ Action: Block
Reglas basadas en rutas
# Challenge login page access
(http.request.uri.path eq "/login" or http.request.uri.path eq "/signup")
→ Action: Managed Challenge
# Challenge API endpoints
(http.request.uri.path contains "/api/")
→ Action: JS Challenge
Reglas basadas en tarifas
# Challenge after high request rate
(cf.threat_score gt 10 and http.request.uri.path contains "/search")
→ Action: Managed Challenge
Reglas basadas en encabezados
# Challenge requests with no Accept-Language header
(not http.request.headers["accept-language"])
→ Action: JS Challenge
# Challenge requests with suspicious UA
(http.user_agent contains "python" or http.user_agent contains "curl")
→ Action: Managed Challenge
Reglas compuestas
# Multiple conditions
(cf.bot_management.score lt 30
and http.request.uri.path contains "/api/"
and ip.geoip.country ne "US")
→ Action: JS Challenge
Identificar qué regla se activó
Cuando aparece un desafío CAPTCHA, puede identificar la regla desencadenante a partir de la respuesta:
Desde encabezados HTTP
import requests
def check_cloudflare_rule_info(url):
"""Extract WAF rule information from Cloudflare challenge response."""
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 Chrome/120.0.0.0",
"Accept": "text/html,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
}
response = requests.get(url, headers=headers, timeout=15, allow_redirects=False)
info = {
"status": response.status_code,
"cf_ray": response.headers.get("cf-ray", ""),
"cf_cache_status": response.headers.get("cf-cache-status", ""),
"server": response.headers.get("server", ""),
}
# Challenge-specific info
html = response.text
if response.status_code == 503:
if "jschl" in html:
info["challenge_type"] = "JS Challenge (IUAM or WAF rule)"
elif "challenge-platform" in html:
info["challenge_type"] = "Managed Challenge"
elif "cf-turnstile" in html:
info["challenge_type"] = "Turnstile (Managed Challenge)"
elif response.status_code == 403:
if "cf-ray" in str(response.headers):
info["challenge_type"] = "WAF Block (no challenge)"
else:
info["challenge_type"] = "Origin 403 (not Cloudflare)"
return info
Desde el ID de Cloudflare Ray
Cada respuesta de Cloudflare incluye un encabezado cf-ray. Los operadores del sitio pueden usar este Ray ID en el panel de Cloudflare (Seguridad > Eventos) para ver exactamente qué regla se activó y qué acción se tomó.
Resolviendo desafíos desencadenados por WAF
Estrategia basada en el tipo de desafío.
import requests
import time
API_KEY = "YOUR_API_KEY"
def solve_cloudflare_challenge(url, challenge_type):
"""Solve Cloudflare challenge based on WAF rule action."""
if challenge_type == "managed_challenge":
# Managed Challenge typically renders as Turnstile
method = "turnstile"
sitekey = extract_turnstile_sitekey(url)
elif challenge_type == "js_challenge":
# JavaScript Challenge page
method = "cloudflare_challenge"
sitekey = "managed"
else:
raise ValueError(f"Unknown challenge type: {challenge_type}")
submit = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": method,
"sitekey": sitekey,
"pageurl": url,
"json": 1,
})
task_id = submit.json()["request"]
for _ in range(60):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY,
"action": "get",
"id": task_id,
"json": 1,
}).json()
if result.get("status") == 1:
return result["request"]
raise TimeoutError("Challenge solve timed out")
def extract_turnstile_sitekey(url):
"""Fetch page and extract Turnstile sitekey."""
import re
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 Chrome/120.0.0.0",
}
response = requests.get(url, headers=headers, timeout=15)
match = re.search(r'data-sitekey=["\']([0-9x][A-Za-z0-9_-]+)["\']', response.text)
return match.group(1) if match else None
Nodo.js
const axios = require("axios");
const API_KEY = "YOUR_API_KEY";
async function solveWAFChallenge(url, challengeType) {
const method =
challengeType === "js_challenge" ? "cloudflare_challenge" : "turnstile";
const sitekey =
challengeType === "js_challenge" ? "managed" : await extractSitekey(url);
const submit = await axios.post("https://ocr.captchaai.com/in.php", null, {
params: {
key: API_KEY,
method,
sitekey,
pageurl: url,
json: 1,
},
});
const taskId = submit.data.request;
for (let i = 0; i < 60; i++) {
await new Promise((r) => setTimeout(r, 5000));
const result = await axios.get("https://ocr.captchaai.com/res.php", {
params: { key: API_KEY, action: "get", id: taskId, json: 1 },
});
if (result.data.status === 1) {
return result.data.request;
}
}
throw new Error("Challenge solve timed out");
}
async function extractSitekey(url) {
const response = await axios.get(url, {
headers: {
"User-Agent": "Mozilla/5.0 Chrome/120.0.0.0",
},
});
const match = response.data.match(/data-sitekey=["']([0-9x][A-Za-z0-9_-]+)["']/);
return match ? match[1] : null;
}
Cambios en las reglas WAF y sus efectos
Los operadores del sitio ajustan con frecuencia las reglas WAF. Estos cambios afectan la automatización:
| Cambio | Efecto sobre la automatización | Cómo detectar |
|---|---|---|
| Regla agregada | Aparece un nuevo challenge en rutas que funcionaban | Monitorear cambios de estado 503/403 |
| Regla eliminada | El challenge desaparece | 200 donde antes era 503 |
| Acción escalada (Block → Managed) | El challenge resoluble se convierte en bloque duro | 403 en lugar de 503 |
| Acción relajada (Block → Managed) | El bloque duro se convierte en challenge resoluble | 503 con página de challenge |
| Umbral cambiado (bot score 30 → 50) | Más solicitudes challengeadas | Mayor frecuencia de challenge |
| Alcance de ruta cambiado | Diferentes URLs afectadas | Nuevas rutas devuelven challenges |
Estrategia de seguimiento
import requests
import time
def monitor_cloudflare_protection(urls, interval=3600):
"""Monitor protection changes across URLs."""
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 Chrome/120.0.0.0",
"Accept": "text/html,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
}
last_status = {}
while True:
for url in urls:
try:
response = requests.get(
url, headers=headers, timeout=15, allow_redirects=False
)
status = response.status_code
has_challenge = status == 503 or "cf-turnstile" in response.text
current = {"status": status, "challenge": has_challenge}
previous = last_status.get(url)
if previous and current != previous:
print(f"[CHANGE] {url}")
print(f" Before: {previous}")
print(f" After: {current}")
last_status[url] = current
except requests.RequestException as e:
print(f"[ERROR] {url}: {e}")
time.sleep(interval)
Solución de problemas
| Síntoma | Probable regla WAF | Solución |
|---|---|---|
Challenge solo en /login |
Regla basada en ruta | Resuelve el challenge para esa ruta |
| Challenge solo desde IPs de centros de datos | Bot score o regla de reputación de IP | Usa proxies residenciales o resuelve el challenge |
| Challenge varía según el país | Regla basada en país | Usa proxy en el país permitido o resuelve |
| Challenge tras N solicitudes | Regla basada en tasa | Reduce la tasa de solicitudes o resuelve cada challenge |
| Challenge siempre JS (nunca Turnstile) | Acción JS Challenge (no Managed) | Usa el método cloudflare_challenge |
| 403 sin challenge | Acción Block (no resoluble) | Cambia IP, cabeceras o patrón de solicitud |
Preguntas frecuentes
¿Puedo ver qué reglas WAF utiliza un sitio?
No. Las reglas WAF son privadas para el operador del sitio. Sólo puedes inferir reglas a partir del comportamiento: qué rutas desencadenan desafíos, desde qué IP y qué tipo de desafío aparece.
¿Se aplican las reglas WAF a todos los planes de Cloudflare?
Las reglas WAF personalizadas están disponibles en todos los planes pagos (Pro, Business, Enterprise). Los planes gratuitos tienen reglas WAF limitadas. Sin embargo, Managed Challenge está disponible en todos los planes, incluido el gratuito.
¿Pueden las reglas WAF desencadenar diferentes desafíos para diferentes caminos?
Sí. Cada regla WAF puede tener una acción diferente y coincidir con diferentes rutas. Un sitio puede utilizar Managed Challenge para los puntos finales /login y JS Challenge para los puntos finales /api/.
¿Con qué frecuencia los sitios cambian sus reglas WAF?
Varía. Los sitios de comercio electrónico suelen ajustar las reglas durante los eventos de ventas. Los sitios preocupados por la seguridad pueden actualizar las reglas semanalmente. La mayoría de los sitios rara vez cambian las reglas después de la configuración inicial.
¿La resolución de un desafío WAF afecta las solicitudes futuras?
Sí. Después de resolverlo, la cookie qa_validation_cookie permite que las solicitudes posteriores pasen sin desafíos durante aproximadamente 30 minutos. La cookie está vinculada a su IP y Agente de Usuario.
Resumen
Las reglas WAF de Cloudflare activan challenges CAPTCHA según condiciones configurables: bot score, país, ruta, cabeceras o tasa. La acción más común es Managed Challenge, que Cloudflare presenta de forma adaptativa como challenge invisible, Turnstile o JS. Resúelvelos con CaptchaAI usando el método turnstile o cloudflare_challenge según lo que se renderice. Los bloques duros (403) de las reglas WAF no son resolubles; en su lugar, cambia el patrón de solicitud o la IP.
Artículos relacionados
- Cloudflare Challenge vs Turnstile: cómo detectar
- Cómo funciona Cloudflare Challenge
- Cómo manejar el modo bajo ataque de Cloudflare