Votre script tourne parfaitement en local, puis se met à recevoir des HTTP 503 et une page « Un instant… » au lieu des données attendues. Neuf fois sur dix, le site vient d'activer le mode I'm Under Attack (IUAM) de Cloudflare, sa protection anti-DDoS la plus stricte. L'IUAM n'est pas un simple blocage : il impose à chaque visiteur un défi JavaScript d'environ 5 secondes avant de laisser passer la moindre requête. Un client HTTP standard (requests, axios, curl) ne sait ni exécuter ce JavaScript ni produire le cookie cf_clearance attendu. Voici comment le reconnaître et comment le résoudre avec CaptchaAI.
Reconnaître un défi IUAM
Quand un opérateur active « I'm Under Attack Mode », chaque requête est interceptée à la périphérie du réseau (edge) avant d'atteindre le serveur d'origine :
Every request → Cloudflare edge
↓
JavaScript challenge page served (HTTP 503)
↓
Browser executes JavaScript challenge (~5 seconds)
↓
Challenge answer submitted automatically
↓
cf_clearance cookie set
↓
Original page loaded with cf_clearance cookie
La page servie renvoie un code HTTP 503 et embarque plusieurs champs cachés que le navigateur doit renvoyer :
| Élément | Rôle |
|---|---|
jschl_vc |
Code de vérification du défi |
pass |
Token de temporisation (impose l'attente de 5 secondes) |
jschl_answer |
Réponse calculée par le JavaScript |
cf_chl_opt |
Options du défi |
ray |
Cloudflare Ray ID de la requête |
| « Un instant… » / « Checking your browser… » | Message affiché à l'utilisateur |
Trois signaux ne trompent pas : un statut 503 (et non 403), une attente d'environ 5 secondes, et l'obligation d'exécuter du JavaScript. Le défi couvre tout le domaine ; une fois franchi, le cookie cf_clearance (~30 minutes) autorise les requêtes suivantes.
IUAM, Managed Challenge, Turnstile ou WAF : identifier la bonne protection
Avant de résoudre quoi que ce soit, identifiez la protection en place : elles ne se traitent pas de la même façon. Une requête sans redirection suffit à lever le doute :
import requests
def identify_cloudflare_protection(url):
"""Distinguish IUAM from other Cloudflare protections."""
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, allow_redirects=False)
html = response.text
status = response.status_code
if status == 503 and "jschl" in html:
return "IUAM (I'm Under Attack Mode)"
if status == 503 and "challenge-platform" in html:
return "Managed Challenge"
if status == 403 and "cf-ray" in str(response.headers):
return "Blocked by WAF/Bot Management"
if "cf-turnstile" in html:
return "Turnstile widget"
if "challenges.cloudflare.com" in html:
return "Cloudflare challenge (generic)"
if status == 200:
return "No challenge (passed)"
return f"Unknown (status: {status})"
Comparez ensuite les signaux protection par protection :
| Signal | IUAM | Managed Challenge | Turnstile | Blocage WAF |
|---|---|---|---|---|
| Statut HTTP | 503 | 503 | 200 | 403 |
jschl dans le corps |
✅ | ❌ | ❌ | ❌ |
| Attente de 5 secondes | ✅ | Parfois | ❌ | ❌ |
Cookie cf_clearance posé |
Après résolution | Après résolution | ❌ | ❌ |
| Page de défi | Pleine page | Pleine page | Widget seul | Page d'erreur |
| JavaScript requis | ✅ | ✅ | ✅ | ❌ |
Pourquoi un client HTTP échoue sur le défi JavaScript
Le défi vérifie que vous pilotez un vrai navigateur. Voici son déroulé côté client :
- Cloudflare renvoie une page de défi contenant du JavaScript obfusqué.
- Le JavaScript effectue une série de calculs : opérations mathématiques sur des chaînes de la page, mesures sur le DOM, temporisation imposée (4 à 5 secondes minimum).
- Une réponse numérique est calculée, puis le formulaire est soumis automatiquement avec
jschl_vc,passetjschl_answer. - Cloudflare valide la réponse et le délai, puis renvoie le cookie
cf_clearancequi ouvre l'accès pour ~30 minutes.
Un client HTTP dépourvu de moteur JavaScript ne franchit aucune de ces étapes : il récupère indéfiniment la même page 503.
# This will ALWAYS get the challenge page:
import requests
response = requests.get("https://iuam-protected-site.com")
# response.status_code == 503
# response.text contains "Checking your browser..."
# Plain HTTP clients cannot:
# - Execute JavaScript
# - Compute the challenge answer
# - Meet the timing requirement
# - Generate the required cookies
Résoudre l'IUAM avec CaptchaAI
Un solveur dédié prend le relais. Deux approches se complètent selon votre besoin.
Solveur Cloudflare Challenge (recommandé)
La méthode cloudflare_challenge de CaptchaAI traite directement les défis IUAM : vous envoyez la tâche, puis vous interrogez le résultat jusqu'à obtenir le token.
import requests
import time
API_KEY = "YOUR_API_KEY"
TARGET_URL = "https://iuam-protected-site.com/data"
# Step 1: Submit challenge to CaptchaAI
submit = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "cloudflare_challenge",
"sitekey": "managed",
"pageurl": TARGET_URL,
"json": 1,
})
task_id = submit.json()["request"]
print(f"Task submitted: {task_id}")
# Step 2: Poll for result
for attempt 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:
token = result["request"]
print(f"Challenge solved! Token: {token[:50]}...")
break
elif result.get("request") == "ERROR_CAPTCHA_UNSOLVABLE":
print("Challenge could not be solved")
break
else:
print("Timed out waiting for solution")
# Step 3: Use cf_clearance cookie or token
# The response contains the clearance data needed to access the site
Navigateur headless piloté avec CaptchaAI
Pour les sessions persistantes, associez un navigateur headless à CaptchaAI : le navigateur porte la session, CaptchaAI prend le relais quand la résolution native échoue.
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import requests
import time
API_KEY = "YOUR_API_KEY"
# Launch browser
options = webdriver.ChromeOptions()
options.add_argument("--disable-blink-features=AutomationControlled")
driver = webdriver.Chrome(options=options)
# Navigate to IUAM page
driver.get("https://iuam-protected-site.com")
# Wait for challenge page to load
time.sleep(3)
# Check if IUAM challenge is present
if "Checking your browser" in driver.page_source or driver.title == "Just a moment...":
print("IUAM challenge detected")
# Option A: Wait for browser to solve natively (if not headless)
try:
WebDriverWait(driver, 15).until(
lambda d: "Checking your browser" not in d.page_source
)
print("Challenge passed natively")
except:
print("Native solve failed — using CaptchaAI")
# Submit to CaptchaAI for solving
# Token submission via JavaScript injection
# After challenge is passed, extract cookies for API use
cookies = driver.get_cookies()
cf_clearance = next(
(c["value"] for c in cookies if c["name"] == "cf_clearance"), None
)
if cf_clearance:
print(f"cf_clearance obtained: {cf_clearance[:30]}...")
# Use cookie with requests library
session = requests.Session()
for cookie in cookies:
session.cookies.set(cookie["name"], cookie["value"])
session.headers.update({
"User-Agent": driver.execute_script("return navigator.userAgent"),
})
# Now make requests with the clearance cookie
response = session.get("https://iuam-protected-site.com/api/data")
print(f"Status: {response.status_code}")
driver.quit()
Node.js
Le même flux se transpose côté Node.js avec axios :
const axios = require("axios");
const API_KEY = "YOUR_API_KEY";
const TARGET_URL = "https://iuam-protected-site.com/data";
async function solveIUAM() {
// Submit challenge
const submit = await axios.post("https://ocr.captchaai.com/in.php", null, {
params: {
key: API_KEY,
method: "cloudflare_challenge",
sitekey: "managed",
pageurl: TARGET_URL,
json: 1,
},
});
const taskId = submit.data.request;
console.log(`Task submitted: ${taskId}`);
// Poll for result
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) {
console.log("IUAM challenge solved!");
return result.data.request;
}
}
throw new Error("Timed out");
}
solveIUAM().then((token) => console.log("Token:", token.substring(0, 50)));
Réutiliser le cookie cf_clearance dans la durée
Le cookie cf_clearance est le résultat concret d'un défi IUAM résolu. Bien géré, il vous évite de relancer une résolution à chaque requête :
| Propriété | Valeur |
|---|---|
| Nom du cookie | cf_clearance |
| Durée de vie | ~30 minutes (configurable côté site) |
| Portée | À l'échelle du domaine |
| Lié à | Adresse IP + User-Agent |
| Réutilisable | Oui, pendant toute sa durée de vie |
| Transférable | Uniquement avec la même IP et le même User-Agent |
Encapsulez la logique dans un gestionnaire de session qui ne relance un défi que lorsque le cookie approche de l'expiration :
import requests
import time
class IUAMSessionManager:
"""Manage cf_clearance cookies for IUAM-protected sites."""
def __init__(self, api_key, target_url, user_agent=None):
self.api_key = api_key
self.target_url = target_url
self.user_agent = user_agent or (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 Chrome/120.0.0.0"
)
self.session = requests.Session()
self.session.headers["User-Agent"] = self.user_agent
self.clearance_time = 0
self.clearance_lifetime = 1800 # 30 minutes default
def needs_refresh(self):
"""Check if clearance cookie needs refreshing."""
return time.time() - self.clearance_time > self.clearance_lifetime - 60
def solve_challenge(self):
"""Solve IUAM challenge and update session cookies."""
submit = requests.post("https://ocr.captchaai.com/in.php", data={
"key": self.api_key,
"method": "cloudflare_challenge",
"sitekey": "managed",
"pageurl": self.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": self.api_key,
"action": "get",
"id": task_id,
"json": 1,
}).json()
if result.get("status") == 1:
# Apply clearance to session
self.clearance_time = time.time()
return result["request"]
raise TimeoutError("IUAM solve timed out")
def get(self, url, **kwargs):
"""Make a GET request, solving IUAM if needed."""
if self.needs_refresh():
self.solve_challenge()
return self.session.get(url, **kwargs)
Scénario : superviser votre propre portail derrière l'IUAM
Prenons une équipe QA basée à Lyon qui héberge son application sur OVHcloud et laisse l'IUAM s'activer pendant les pics de trafic. Pour valider le parcours de connexion, elle lance un worker de test depuis une région européenne (par exemple eu-west-3 à Paris) avec une IP de sortie stable. La règle d'or : l'IP et le User-Agent qui résolvent le défi doivent rester identiques à ceux qui consomment le cookie cf_clearance, sans quoi Cloudflare relance un défi. Côté conformité, limitez la collecte aux données nécessaires au test et vérifiez vos obligations RGPD avant de journaliser des identifiants de session.
Dépannage
| Symptôme | Cause | Correctif |
|---|---|---|
| Boucle de défi sans fin | L'IP a changé après l'obtention du cookie | Utilisez une IP cohérente pour la résolution et l'accès |
| cf_clearance rejeté | User-Agent différent entre résolution et requêtes | Réutilisez exactement le même User-Agent |
| 503 persistant après résolution | Cookie expiré (> 30 min) | Rafraîchissez le cookie avant l'expiration |
| Page de défi inattendue | Le site utilise un Managed Challenge, pas l'IUAM | Basculez vers le solveur Turnstile |
| Plusieurs défis enchaînés | Le premier est un IUAM, le second un Turnstile | Résolvez-les séquentiellement |
Questions fréquentes
Pourquoi mon client requests reçoit-il un 503 alors que le navigateur ouvre la page ?
Parce que le navigateur exécute le JavaScript du défi et respecte la temporisation de 5 secondes, ce qu'un client HTTP ne fait pas. Le navigateur obtient donc le cookie cf_clearance et accède au contenu, tandis que votre script reste sur la page 503.
Combien de threads faut-il pour résoudre des défis IUAM à grande échelle ?
CaptchaAI facture au thread concurrent, pas à la résolution : un thread correspond à un défi en cours. L'offre BASIC ($15/mois, 5 threads) traite 5 défis IUAM en parallèle, avec des résolutions illimitées dans le mois. Pour plus de débit, montez en threads avec STANDARD ($30/mois, 15 threads) ou ADVANCE ($90/mois, 50 threads).
Le cookie cf_clearance reste-t-il valide si je change de proxy ?
Non. Le cookie est lié à l'IP et au User-Agent utilisés lors de la résolution. Si vous changez de proxy (donc d'IP de sortie) ou de User-Agent, Cloudflare invalide le cookie et resert le défi. Gardez le même couple IP + User-Agent du début à la fin de la session.
L'IUAM peut-il être suivi d'un défi Turnstile ou d'un CAPTCHA image ?
Oui, certains sites enchaînent les protections : un IUAM d'abord, puis un widget Turnstile ou une image. Résolvez-les dans l'ordre, chacun avec la méthode adaptée. CaptchaAI couvre les deux étapes, puisqu'il prend en charge Cloudflare Challenge comme Cloudflare Turnstile.
En résumé
Le mode Under Attack impose à chaque visiteur un défi JavaScript (HTTP 503, calcul d'environ 5 secondes). Résolvez-le avec le solveur Cloudflare Challenge de CaptchaAI, puis réutilisez le cookie cf_clearance dans la fenêtre de 30 minutes. Point non négociable : conservez la même IP et le même User-Agent entre la résolution et l'usage du cookie.