Quando a Cloudflare apresenta uma página de desafio, um fluxo de token complexo começa - desde os parâmetros iniciais da página, passando pela execução do JavaScript até o cookie cookie_qa_validacao final. Compreender esses parâmetros ajuda a diagnosticar falhas de resolução, depurar fluxos de automação e escolher a abordagem de solução correta.
Anatomia da página de desafio
Uma página de desafio da Cloudflare (HTTP 503) contém vários elementos principais:
<!DOCTYPE html>
<html>
<head>
<title>Just a moment...</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<div id="challenge-stage">
<div id="challenge-body-text">
Checking if the site connection is secure
</div>
<div id="challenge-spinner">
<!-- Loading spinner -->
</div>
</div>
<div id="challenge-form" style="display:none">
<form id="challenge-form" action="/..." method="POST">
<!-- Hidden parameters -->
<input type="hidden" name="md" value="...">
<input type="hidden" name="r" value="...">
</form>
</div>
<script src="/cdn-cgi/challenge-platform/h/g/orchestrate/chl_page/v1?ray=...">
</script>
</body>
</html>
Parâmetros principais
Na página do desafio
| Parâmetro | Nome | Objetivo |
|---|---|---|
ray |
ID de raio da Cloudflare | Identificador de solicitação exclusivo, vincula o desafio à solicitação original |
md |
Metadados do desafio | Estado de desafio criptografado |
r |
Token de resposta | Resposta computada (preenchida por JavaScript) |
chl_opt |
Opções de desafio | Configuração para o script de desafio |
cRay |
Raio de desafio | Raio secundário para rastreamento de desafios |
cZone |
Zona de desafio | ID da zona Cloudflare |
cUPMDTk |
Carimbo de data e hora | Hora de emissão do desafio |
cHash |
Hash de desafio | Validação de integridade |
No URL do script de desafio
/cdn-cgi/challenge-platform/h/g/orchestrate/chl_page/v1?ray=ABC123
| Componente | Significado |
|---|---|
/cdn-cgi/challenge-platform/ |
Infraestrutura de desafio da Cloudflare |
h/g/ |
Versão de desafio/variant |
orchestrate/ |
Endpoint de orquestração de desafio |
chl_page/v1 |
Versão da página do desafio |
ray=ABC123 |
Solicitar vinculação de Ray ID |
Na carga JavaScript
O script de desafio carrega parâmetros adicionais:
// Extracted from obfuscated challenge script
window._cf_chl_opt = {
cvId: '2', // Challenge version
cType: 'managed', // Challenge type
cNounce: '...', // Cryptographic nonce
cRay: '...', // Challenge Ray ID
cHash: '...', // Challenge hash
cUPMDTk: '...', // Timestamp
cFPWv: 'g', // sinal de navegador version
cTTimeMs: '4000', // Minimum wait time (ms)
cTplV: 5, // Template version
cLt: '...', // Challenge lifetime
cRq: {}, // Challenge request data
};
Fluxo de token do desafio à liberação
Fluxo passo a passo
1. CLIENT → CLOUDFLARE EDGE
GET /protected-page
↓
2. CLOUDFLARE → CLIENT
HTTP 503 + Challenge page HTML
Sets: __cf_bm cookie (bot management tracking)
Contains: ray ID, challenge script URL
↓
3. CLIENT (browser)
Loads challenge script from /cdn-cgi/challenge-platform/...
↓
4. CHALLENGE SCRIPT EXECUTES:
a. Collects browser sinal de navegador:
- Canvas hash
- WebGL renderer
- Screen dimensions
- Installed fonts
- Timezone
- Language
b. Runs proof-of-work:
- Iterates hash computations
- Must find answer matching difficulty
c. Computes timing:
- Enforces minimum wait (cTTimeMs)
- Records actual timing
d. Generates response token:
- Combines sinal de navegador + PoW answer + timing
- Encrypts with challenge nonce
↓
5. CLIENT → CLOUDFLARE
POST /cdn-cgi/challenge-platform/h/g/flow/ov1/...
Body: { r: "encrypted_response", md: "metadata", ... }
↓
6. CLOUDFLARE validates:
- Proof-of-work answer correct?
- Timing within acceptable range?
- sinal de navegador consistent with real browser?
- No replay (nonce check)?
↓
7. CLOUDFLARE → CLIENT
HTTP 200 + Set-Cookie: cookie_qa_validacao=...; path=/; expires=...
+ HTTP redirect to original URL
↓
8. CLIENT → CLOUDFLARE
GET /protected-page
Cookie: cookie_qa_validacao=...
↓
9. CLOUDFLARE → CLIENT
HTTP 200 + Protected content
Linha do tempo dos cookies
Request 1: No cookies
→ Challenge page (503)
→ __cf_bm cookie set
Challenge solve:
→ cookie_qa_validacao cookie set
Request 2+: cookie_qa_validacao + __cf_bm
→ Content served (200)
After ~30 mins: cookie_qa_validacao expires
→ Next request triggers new challenge
Biscoitos de desafio
| Biscoito | Objetivo | Vitalício | Escopo |
|---|---|---|---|
__cf_bm |
Acompanhamento de sessão de gerenciamento de bot | 30 minutos | Domínio |
cookie_qa_validacao |
Prova de autorização de desafio | 15 min – 24 horas (configurável) | Domínio |
__cflb |
Afinidade do balanceador de carga | Sessão | Domínio |
_cfuvid |
ID de visitante exclusivo | Sessão | Domínio |
restrições de cookies cookie_qa_validacao
O cookie cookie_qa_validacao está vinculado a:
- Endereço IP — Deve vir do mesmo IP que resolveu o desafio
- User-Agent — Deve corresponder ao UA usado durante o desafio
- Domínio — Válido apenas para o domínio que o emitiu
# ❌ FAILS — IP mismatch
# Solve challenge from IP A, then use cookie_qa_validacao from IP B
# ❌ FAILS — UA mismatch
# Solve with Chrome UA, then send requests with Firefox UA
# ✅ WORKS — Same IP + Same UA
session = requests.Session()
session.headers["User-Agent"] = "Mozilla/5.0 ... Chrome/120.0.0.0"
# Use same session for solving and subsequent requests
Extraindo parâmetros de desafio
Pitão
import re
import requests
def extract_challenge_params(url):
"""Extract Cloudflare Turnstile em staging page parameters."""
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)
html = response.text
params = {
"status_code": response.status_code,
"cf_ray": response.headers.get("cf-ray", ""),
"is_challenge": response.status_code == 503,
}
if not params["is_challenge"]:
return params
# Extract Ray ID from page
ray_match = re.search(r"ray['\"]?\s*[:=]\s*['\"]([a-f0-9]+)['\"]", html, re.I)
if ray_match:
params["ray_id"] = ray_match.group(1)
# Extract challenge script URL
script_match = re.search(
r'src=["\'](/cdn-cgi/challenge-platform/[^"\']+)["\']', html
)
if script_match:
params["challenge_script"] = script_match.group(1)
# Extract challenge options
opt_match = re.search(r"_cf_chl_opt\s*=\s*\{([^}]+)\}", html)
if opt_match:
opt_text = opt_match.group(1)
# Parse individual options
for key in ["cType", "cRay", "cHash", "cTTimeMs", "cvId", "cFPWv"]:
val_match = re.search(
rf"{key}\s*:\s*['\"]?([^'\"', }}]+)", opt_text
)
if val_match:
params[key] = val_match.group(1)
# Extract form parameters
md_match = re.search(r'name=["\']md["\']\s+value=["\']([^"\']+)["\']', html)
if md_match:
params["md"] = md_match.group(1)
# Extract cookies from response
params["cookies"] = {
name: value
for name, value in response.cookies.items()
}
return params
# Usage
params = extract_challenge_params("https://protected-site.com")
if params["is_challenge"]:
print(f"Challenge type: {params.get('cType', 'unknown')}")
print(f"Ray ID: {params.get('ray_id', params['cf_ray'])}")
print(f"Min wait: {params.get('cTTimeMs', '?')}ms")
print(f"Script: {params.get('challenge_script', 'not found')}")
Node.js
const axios = require("axios");
async function extractChallengeParams(url) {
const response = await axios.get(url, {
headers: {
"User-Agent": "Mozilla/5.0 Chrome/120.0.0.0",
Accept: "text/html,*/*;q=0.8",
},
validateStatus: () => true,
maxRedirects: 0,
});
const html = response.data;
const params = {
statusCode: response.status,
cfRay: response.headers["cf-ray"] || "",
isChallenge: response.status === 503,
};
if (!params.isChallenge) return params;
// Extract challenge script URL
const scriptMatch = html.match(
/src=["'](\/cdn-cgi\/challenge-platform\/[^"']+)["']/
);
if (scriptMatch) params.challengeScript = scriptMatch[1];
// Extract challenge type
const typeMatch = html.match(/cType\s*:\s*['"]?(\w+)/);
if (typeMatch) params.challengeType = typeMatch[1];
// Extract timing
const timeMatch = html.match(/cTTimeMs\s*:\s*['"]?(\d+)/);
if (timeMatch) params.minWaitMs = parseInt(timeMatch[1]);
return params;
}
extractChallengeParams("https://protected-site.com").then(console.log);
Resolvendo com CaptchaAI
CaptchaAI lida com todo o fluxo de token internamente – você não precisa extrair os parâmetros de desafio manualmente:
import requests
import time
API_KEY = "YOUR_API_KEY"
def solve_turnstile_staging(target_url):
"""Solve Cloudflare Turnstile em staging page — CaptchaAI handles token flow."""
submit = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "turnstile_staging",
"sitekey": "managed",
"pageurl": target_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")
# CaptchaAI handles the full flow:
# 1. Loads the challenge page
# 2. Executes JavaScript
# 3. Solves proof-of-work
# 4. Returns clearance token/cookies
token = solve_turnstile_staging("https://protected-site.com/login")
Depurando falhas de desafio
Pontos de falha comuns
| Ponto de falha | Sintoma | Causa raiz |
|---|---|---|
| A página do desafio não carrega | Tempo limite ou resposta vazia | Problema de rede/proxy |
| O script não é executado | Ciclos de desafio | APIs JavaScript ausentes |
| A prova de trabalho falha | Girador infinito | Tempo limite computacional |
| Resposta rejeitada | Redirecionar de volta ao desafio | Violação de tempo ou incompatibilidade de sinal de navegador |
| cookie_qa_validacao não definido | Cookie ausente após resolução | Erro de análise de resposta |
| cookie_qa_validacao rejeitado | 403 em solicitação subsequente | Incompatibilidade de IP ou UA |
Lista de verificação de depuração
def debug_challenge_flow(url, cookie_qa_validacao_cookie=None, user_agent=None):
"""Debug the challenge solve flow step by step."""
ua = user_agent or (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 Chrome/120.0.0.0"
)
steps = []
# Step 1: Initial request
response = requests.get(
url,
headers={"User-Agent": ua, "Accept": "text/html,*/*;q=0.8"},
timeout=15,
allow_redirects=False,
)
steps.append({
"step": "initial_request",
"status": response.status_code,
"is_challenge": response.status_code == 503,
"cf_ray": response.headers.get("cf-ray", ""),
})
# Step 2: Test with cookie_qa_validacao
if cookie_qa_validacao_cookie:
session = requests.Session()
session.cookies.set("cookie_qa_validacao", cookie_qa_validacao_cookie)
session.headers["User-Agent"] = ua
response2 = session.get(url, timeout=15, allow_redirects=False)
steps.append({
"step": "with_clearance",
"status": response2.status_code,
"passed": response2.status_code == 200,
})
if response2.status_code != 200:
steps.append({
"step": "diagnosis",
"issue": "cookie_qa_validacao rejected",
"possible_causes": [
"Cookie expired",
"IP address changed",
"User-Agent mismatch",
"Cookie from different domain",
],
})
return steps
Solução de problemas
| Sintoma | Causa | Correção |
|---|---|---|
| O tipo de desafio é "gerenciado", mas a solução falha | O desafio requer catraca, não desafio JS | Experimente o método turnstile em vez de turnstile_staging |
| cookie_qa_validacao funciona uma vez e depois rejeitado | A rotação de IP mudou seu IP | Pin IP para a vida útil da folga |
| A página "Só um momento..." nunca resolve | JavaScript bloqueado ou malformado | Use a CaptchaAI em vez de resolução manual |
| O desafio reaparece após cada solicitação | cookie_qa_validacao não sendo enviado | Certifique-se de que os cookies persistam na sessão |
| Desafio diferente em caminhos diferentes | Regras WAF por caminho | Resolva para cada caminho separadamente |
Perguntas frequentes
O que há dentro do cookie cookie_qa_validacao?
É um token criptografado contendo prova de resolução, hash de IP, hash de UA e tempo de expiração. Você não pode decodificá-lo ou forjá-lo – apenas a vantagem da Cloudflare pode validá-lo.
Quanto tempo dura cookie_qa_validacao?
Os operadores do site configuram o tempo de vida. O padrão é 30 minutos. O intervalo é de 15 minutos a 24 horas. Os clientes empresariais podem definir valores personalizados.
Posso resolver o desafio sem a execução de JavaScript?
Não. O desafio requer JavaScript para calcular a prova de trabalho e a sinal de navegador do navegador. CaptchaAI lida com isso internamente usando navegadores reais.
O que acontece se o Ray ID mudar?
Cada solicitação recebe um novo Ray ID. O desafio está vinculado ao Ray ID no momento da página do desafio. Depois que cookie_qa_validacao for emitido, o Ray ID não será mais relevante.
Posso reutilizar cookie_qa_validacao em domínios diferentes?
Não. cookie_qa_validacao tem escopo de domínio. Cada domínio requer seu próprio cookie de resolução e liberação de desafios.
Resumo
As páginas de desafio da Cloudflare contêm Ray IDs, scripts de desafio, objetos de opções e parâmetros de formulário que orientam um fluxo de token de prova de trabalho. O fluxo produz um cookie cookie_qa_validacao vinculado ao IP e ao User-Agent, válido por 15 minutos a 24 horas. ComCaptchaAI, você não precisa analisar esses parâmetros manualmente - o solucionador lida com todo o fluxo. Para depuração, compreender os parâmetros ajuda a identificar onde o fluxo é interrompido.
Artigos relacionados
- Cloudflare Turnstile em staging vs detecção de catraca
- Desafio gerenciado versus interativo da Cloudflare
- Cloudflare Turnstile 403 Após correção do token