دروس API

Cloudflare Challenge معلمات الصفحة وتدفق الرمز المميز

عندما تقدم Cloudflare صفحة تحدي، يبدأ تدفق رمزي معقد - من معلمات الصفحة الأولية من خلال تنفيذ JavaScript إلى ملف تعريف الارتباط cf_clearance النهائي. يساعدك فهم هذه المعلمات على تشخيص حالات الفشل، وتصحيح تدفقات الأتمتة، واختيار نهج الحل الصحيح.


تشريح صفحة التحدي

تحتوي صفحة تحدي Cloudflare (HTTP 503) على عدة عناصر أساسية:

<!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>

المعلمات الرئيسية

في صفحة التحدي

المعلمة الاسم الغرض
ray معرف راي Cloudflare معرف الطلب الفريد، يتحدى الروابط مع الطلب الأصلي
md البيانات الوصفية للتحدي حالة التحدي المشفرة
r رمز الاستجابة الإجابة المحسوبة (مملوءة بJavaScript)
chl_opt خيارات التحدي تكوين البرنامج النصي التحدي
cRay شعاع التحدي شعاع ثانوي لتتبع التحدي
cZone منطقة التحدي معرف منطقة Cloudflare
cUPMDTk الطابع الزمني وقت إصدار التحدي
cHash تجزئة التحدي التحقق من النزاهة

في عنوان URL للبرنامج النصي للتحدي

/cdn-cgi/challenge-platform/h/g/orchestrate/chl_page/v1?ray=ABC123
مكون معنى
/cdn-cgi/challenge-platform/ البنية التحتية لتحدي Cloudflare
h/g/ نسخة التحدي/variant
orchestrate/ نقطة نهاية تنسيق التحدي
chl_page/v1 نسخة صفحة التحدي
ray=ABC123 طلب ربط معرف راي

في حمولة JavaScript

يقوم البرنامج النصي للتحدي بتحميل معلمات إضافية:

// 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',          // Fingerprint version
    cTTimeMs: '4000',    // Minimum wait time (ms)
    cTplV: 5,            // Template version
    cLt: '...',          // Challenge lifetime
    cRq: {},             // Challenge request data
};

تدفق الرمز المميز من التحدي إلى التخليص

التدفق خطوة بخطوة


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 fingerprint:

      - 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 fingerprint + 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?
   - Fingerprint consistent with real browser?
   - No replay (nonce check)?
   ↓

7. CLOUDFLARE → CLIENT
   HTTP 200 + Set-Cookie: cf_clearance=...; path=/; expires=...
   + HTTP redirect to original URL
   ↓

8. CLIENT → CLOUDFLARE
   GET /protected-page
   Cookie: cf_clearance=...
   ↓

9. CLOUDFLARE → CLIENT
   HTTP 200 + Protected content

الجدول الزمني لملفات تعريف الارتباط

Request 1: No cookies
    → Challenge page (503)
    → __cf_bm cookie set

Challenge solve:
    → cf_clearance cookie set

Request 2+: cf_clearance + __cf_bm
    → Content served (200)

After ~30 mins: cf_clearance expires
    → Next request triggers new challenge

ملفات تعريف الارتباط التحدي

ملف تعريف الارتباط الغرض مدى الحياة النطاق
__cf_bm تتبع جلسة إدارة الروبوت 30 دقيقة المجال
cf_clearance إثبات تصريح التحدي 15 دقيقة – 24 ساعة (قابلة للتكوين) المجال
__cflb تقارب موازن التحميل جلسة المجال
_cfuvid معرف الزائر الفريد جلسة المجال

cf_clearance قيود ملفات تعريف الارتباط

يرتبط ملف تعريف الارتباط cf_clearance بما يلي:

  1. عنوان IP — يجب أن يأتي من نفس عنوان IP الذي حل التحدي
  2. وكيل المستخدم — يجب أن يتطابق مع UA المستخدم أثناء التحدي
  3. النطاق - صالح فقط للنطاق الذي أصدره
# ❌ FAILS — IP mismatch
# Solve challenge from IP A, then use cf_clearance 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

استخراج معلمات التحدي

بايثون

import re
import requests

def extract_challenge_params(url):
    """Extract Cloudflare challenge 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);

الحل باستخدام CaptchaAI

يتعامل CaptchaAI مع تدفق الرمز المميز بالكامل داخليًا - ولا تحتاج إلى استخراج معلمات التحدي يدويًا:

import requests
import time

API_KEY = "YOUR_API_KEY"

def solve_cloudflare_challenge(target_url):
    """Solve Cloudflare challenge page — CaptchaAI handles token flow."""
    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"]

    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_cloudflare_challenge("https://protected-site.com/login")

تصحيح فشل التحدي

نقاط الفشل الشائعة

نقطة الفشل أعراض السبب الجذري
لا يتم تحميل صفحة التحدي مهلة أو استجابة فارغة مشكلة Network/proxy
فشل تنفيذ البرنامج النصي حلقات التحدي واجهات برمجة تطبيقات JavaScript مفقودة
فشل إثبات العمل سبينر لانهائي المهلة الحسابية
تم رفض الرد إعادة التوجيه مرة أخرى إلى التحدي انتهاك التوقيت أو عدم تطابق بصمة الإصبع
لم يتم تعيين cf_clearance ملف تعريف الارتباط مفقود بعد الحل خطأ في تحليل الاستجابة
تم رفض cf_clearance 403 بناء على طلب لاحق عدم تطابق IP أو UA

قائمة التحقق من التصحيح

def debug_challenge_flow(url, cf_clearance_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 cf_clearance
    if cf_clearance_cookie:
        session = requests.Session()
        session.cookies.set("cf_clearance", cf_clearance_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": "cf_clearance rejected",
                "possible_causes": [
                    "Cookie expired",
                    "IP address changed",
                    "User-Agent mismatch",
                    "Cookie from different domain",
                ],
            })

    return steps

استكشاف الأخطاء وإصلاحها

أعراض السبب إصلاح
نوع التحدي "مُدار" ولكن فشل الحل التحدي يتطلب Turnstile، وليس تحدي JS جرب طريقة turnstile بدلاً من cloudflare_challenge
يعمل cf_clearance مرة واحدة، ثم يتم رفضه لقد غيّر دوران IP عنوان IP الخاص بك دبوس IP لعمر التخليص
صفحة "لحظة واحدة فقط..." لا يتم حلها أبدًا JavaScript محظور أو مشوه استخدم CaptchaAI بدلاً من الحل اليدوي
يظهر التحدي مرة أخرى بعد كل طلب لم يتم إرسال cf_clearance تأكد من استمرار ملفات تعريف الارتباط في الجلسة
تحدي مختلف على مسارات مختلفة قواعد WAF لكل مسار حل لكل مسار على حدة

الأسئلة المتداولة

ماذا يوجد داخل ملف تعريف الارتباط cf_clearance؟

إنه رمز مميز مشفر يحتوي على إثبات الحل وتجزئة IP وتجزئة UA ووقت انتهاء الصلاحية. لا يمكنك فك تشفيرها أو تزويرها - فقط حافة Cloudflare يمكنها التحقق من صحتها.

كم من الوقت يستمر cf_clearance؟

يقوم مشغلو الموقع بتكوين العمر. الافتراضي هو 30 دقيقة. النطاق من 15 دقيقة إلى 24 ساعة. يمكن لعملاء المؤسسات تعيين قيم مخصصة.

هل يمكنني حل التحدي دون تنفيذ JavaScript؟

لا. يتطلب التحدي استخدام JavaScript لحساب إثبات العمل وبصمة المتصفح. يتعامل CaptchaAI مع هذا الأمر داخليًا باستخدام متصفحات حقيقية.

ماذا يحدث إذا تغير معرف Ray؟

يحصل كل طلب على معرف Ray جديد. يرتبط التحدي بمعرف Ray في وقت صفحة التحدي. بمجرد إصدار cf_clearance، لم يعد معرف Ray ذو صلة.

هل يمكنني إعادة استخدام cf_clearance عبر مجالات مختلفة؟

رقم cf_clearance هو على نطاق المجال. يتطلب كل مجال حل التحدي الخاص به وملف تعريف الارتباط الخاص به.


ملخص

تحتوي صفحات تحدي Cloudflare على معرفات Ray ونصوص التحدي وكائنات الخيارات ومعلمات النموذج التي تقود تدفق الرمز المميز لإثبات العمل. ينتج عن التدفق ملف تعريف ارتباط cf_clearance مرتبط بـ IP وUser-Agent، ويكون صالحًا لمدة 15 دقيقة إلى 24 ساعة. معCaptchaAI، لا تحتاج إلى تحليل هذه المعلمات يدويًا، حيث يعالج الحل التدفق بأكمله. ولتصحيح الأخطاء، يساعد فهم المعلمات في تحديد مكان انقطاع التدفق.

مقالات ذات صلة

أدلة ذات صلة

التعليقات غير مفعّلة لهذا المقال.