Explainers

Comment gérer Cloudflare en mode attaque

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 :

  1. Cloudflare renvoie une page de défi contenant du JavaScript obfusqué.
  2. 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).
  3. Une réponse numérique est calculée, puis le formulaire est soumis automatiquement avec jschl_vc, pass et jschl_answer.
  4. Cloudflare valide la réponse et le délai, puis renvoie le cookie cf_clearance qui 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

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)));

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).

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.

Articles connexes

Les commentaires sont désactivés pour cet article.