عندما تقدم 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 بما يلي:
- عنوان IP — يجب أن يأتي من نفس عنوان IP الذي حل التحدي
- وكيل المستخدم — يجب أن يتطابق مع UA المستخدم أثناء التحدي
- النطاق - صالح فقط للنطاق الذي أصدره
# ❌ 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، لا تحتاج إلى تحليل هذه المعلمات يدويًا، حيث يعالج الحل التدفق بأكمله. ولتصحيح الأخطاء، يساعد فهم المعلمات في تحديد مكان انقطاع التدفق.
مقالات ذات صلة
- Cloudflare Challenge مقابل اكتشاف Turnstile
- Cloudflare المُدارة مقابل التحدي التفاعلي
- Cloudflare Turnstile 403 بعد إصلاح الرمز المميز