CAPTCHA на сайте под Cloudflare почти никогда не появляется случайно — её включает конкретное правило WAF: по оценке бота, стране, пути запроса, заголовкам или их комбинации.
Коротко:
- Только 3 действия WAF дают решаемую задачу, остальные 4 — блок или чистый проход.
- Managed Challenge — самое частое действие, оно само выбирает тип проверки.
- Жёсткий 403 (действие Block) не решается в принципе — тут не поможет никакой API.
- Триггер вычисляется по HTTP-статусу и телу ответа, без доступа к панели сайта.
Действия WAF, которые заканчиваются CAPTCHA
Правила Cloudflare WAF поддерживают несколько действий. Только три из них ведут к решаемой задаче — остальные либо блокируют запрос, либо пропускают его без проверки:
| Действие WAF | Что происходит | HTTP-статус | Метод CaptchaAI |
|---|---|---|---|
| Managed Challenge | Cloudflare сам выбирает: invisible, Turnstile или JS | 503 | turnstile |
| JS Challenge | 5-секундная JS-страница | 503 | turnstile |
| Interactive Challenge | Классическая CAPTCHA (устаревает) | 403 | turnstile |
| Block | Жёсткий 403 | 403 | — (нерешаемо) |
| Allow | Проходит без проверки | 200 | — |
| Skip | Пропускает остальные правила | 200 | — |
| Log | Только запись в лог | 200 | — |
Managed Challenge — самое частое действие
Managed Challenge — рекомендованное самим Cloudflare действие. Он адаптивно подбирает тип проверки под каждого посетителя:
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
На практике большинство ботов автоматизации попадают в среднюю или верхнюю ветку — invisible-проход достаётся только трафику с очень высокой оценкой бота.
Типичные шаблоны правил WAF
Операторы сайтов пишут правила WAF на языке выражений Cloudflare. Вот шаблоны, которые чаще всего ловят автоматизированный трафик.
Правила по оценке бота
Самый частый триггер для скриптов и headless-браузеров — низкий bot_management.score:
# 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
API-решатели CaptchaAI получают оценки человеческого уровня, потому что задачу решает настоящий браузер, а не эмуляция без рендеринга.
Правила по стране
Геоблок часто мягче, чем кажется, — сначала CAPTCHA, и только отдельно жёсткий бан:
# 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
Правила по пути
Логин и API — самые частые точки, где ставят точечную проверку:
# 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
Правила по частоте запросов
Порог обычно завязан не только на частоту, но и на конкретный путь:
# Challenge after high request rate
(cf.threat_score gt 10 and http.request.uri.path contains "/search")
→ Action: Managed Challenge
Правила по заголовкам
Отсутствие или подозрительный User-Agent ловится не хуже оценки бота:
# 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
Комбинированные правила
Реальные конфигурации почти всегда сочетают несколько условий сразу:
# Multiple conditions
(cf.bot_management.score lt 30
and http.request.uri.path contains "/api/"
and ip.geoip.country ne "US")
→ Action: JS Challenge
Как понять, какое правило сработало
Когда вместо страницы приходит CAPTCHA, триггерное правило можно вычислить по самому ответу — по HTTP-статусу и по телу страницы:
import requests
def check_cloudflare_rule_info(url):
"""Extract WAF rule information from страница Cloudflare-защиты в staging 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
По Cloudflare Ray ID
Каждый ответ Cloudflare несёт заголовок cf-ray. У оператора сайта этот Ray ID виден в панели Cloudflare (Security → Events) — там точно видно, какое правило сработало. У вас как у клиента доступа к этой панели нет, поэтому диагностика идёт от ответа, а не от чужой конфигурации.
Диагностика типичных проблем
- Проверка только на
/login→ правило по пути; решайте задачу на этом маршруте. - Проверка только с IP дата-центров → оценка бота или репутация IP; резидентный прокси или решение задачи.
- Проверка зависит от страны → правило по стране; прокси в разрешённой стране.
- Проверка после N запросов → правило по частоте; снижайте частоту или решайте каждую.
- Проверка всегда JS, не виджет → сработал JS Challenge, не Managed; метод
turnstile. - 403 без проверки → сработал Block (нерешаемо); меняйте IP, заголовки, паттерн запроса.
Совет: сохраняйте
cf-rayрядом со статусом в логах — по этой паре легче сверяться с оператором сайта.
Как решать задачи, вызванные WAF
Стратегия зависит от того, какой тип проверки отрисован — Managed Challenge обычно приходит как Turnstile-виджет, JS Challenge — как отдельная JS-страница:
import requests
import time
API_KEY = "YOUR_API_KEY"
def solve_turnstile(url, challenge_type):
"""Solve страница Cloudflare-защиты в staging 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 = "turnstile"
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
Node.js
const axios = require("axios");
const API_KEY = "YOUR_API_KEY";
async function solveWAFChallenge(url, challengeType) {
const method =
challengeType === "js_challenge" ? "turnstile" : "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;
}
Пример из практики
QA-команда из Алматы поставила на staging-логин cf.bot_management.score lt 30 → Managed Challenge — правило почти всегда рендерит Turnstile-виджет. При решении Turnstile до 10 секунд одного потока хватает на 300+ решений в час: для редких прогонов CI достаточно BASIC ($15/мес, 5 потоков), для постоянного мониторинга — STANDARD ($30/мес, 15 потоков). В логи писали только поля, нужные для самой проверки — дисциплина, актуальная и для 152-ФЗ, и для GDPR.
Что происходит при изменении правил WAF
Операторы сайтов регулярно правят правила WAF, и это напрямую бьёт по автоматизации:
- Правило добавлено — новая проверка на путях, которые раньше работали (503/403 там, где было 200).
- Правило удалено — проверка исчезает (200 там, где был 503).
- Ужесточили (Managed Challenge → Block) — решаемая задача становится жёстким блоком (403 вместо 503).
- Смягчили (Block → Managed Challenge) — блок становится решаемой задачей (503 вместо 403).
- Изменили порог (score 30 → 50) — под проверку попадает больше запросов.
- Изменили область пути — проверки появляются на новых маршрутах.
Стратегия мониторинга
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)
Часто задаваемые вопросы
В чём разница между правилом WAF и Bot Fight Mode Cloudflare?
Bot Fight Mode — грубая защита уровня всего сайта, включается тумблером без условий. Правила WAF точечные: оператор сам решает, для каких путей, стран или оценок бота включать проверку. Сайт нередко использует оба механизма сразу, и внешне эффект неотличим.
Сколько потоков CaptchaAI нужно, чтобы закрыть Managed Challenge при 1000 запросах в час?
Зависит от доли запросов, которая реально получает проверку — обычно заметно меньше 100 %, часть трафика проходит invisible-веткой без виджета. При решении Turnstile до 10 секунд один поток закрывает 300+ решений в час, так что чаще всего хватает BASIC (5 потоков) или STANDARD (15 потоков) — считайте от своих цифр, а не от чужого среднего.
Как долго действует cookie после решения WAF-проверки?
Около 30 минут — после этого последующие запросы с тем же IP и User-Agent проходят без повторной проверки. Точное время зависит от настроек сайта, но полчаса — типичное окно для проверок, выданных через Managed Challenge.
Что делать, если WAF вернул жёсткий 403 без проверки?
Значит, сработало действие Block, а не Challenge — CAPTCHA тут решать нечего, потому что её попросту нет. Единственный выход — поменять то, что триггерит правило: IP-адрес, набор заголовков или сам паттерн запроса (частоту, путь, User-Agent).
Работает ли Managed Challenge на бесплатном тарифе Cloudflare?
Да. В отличие от кастомных правил WAF, которые доступны только на платных тарифах (Pro, Business, Enterprise), Managed Challenge включён на всех тарифах Cloudflare, включая бесплатный.
Итог
- Правила WAF запускают CAPTCHA по оценке бота, стране, пути, заголовкам или частоте запросов.
- Чаще всего срабатывает Managed Challenge — Cloudflare сам выбирает invisible-проверку, Turnstile или JS-задачу.
- Решайте их через CaptchaAI методом
turnstile. - Жёсткий блок (403) нерешаем в принципе — тут помогает только смена паттерна запроса или IP-адреса, а не API.