استكشاف الأخطاء

خطأ 403 في Cloudflare Turnstile بعد إرسال الرمز وحلوله

حصلت على رمز Turnstile صالح، ومع ذلك يرد الموقع المستهدف بخطأ 403 Forbidden؟ في معظم الحالات لا تكون المشكلة في الرمز نفسه، بل في ما يحدث بعد إرساله: ملف تعريف الارتباط cf_clearance الذي لم يُحفظ، أو جلسة جديدة فقدت بيانات الاعتماد، أو رؤوس طلب لا تطابق ما يتوقعه Cloudflare. يرتّب هذا الدليل الأسباب الستة الأكثر شيوعاً من الأرجح إلى الأقل، مع طريقة تشخيص كل واحد منها وإصلاحه.


المسار السريع للتشخيص

قبل الدخول في التفاصيل، اتبع هذا الترتيب المنطقي؛ فهو يحصر السبب في أقل من خمس دقائق:

  • تأكد أولاً من أن الصفحة تعرض Turnstile فعلاً وليست شاشة Cloudflare Challenge كاملة.
  • تحقق من أن الاستجابة تحمل رأس Server: cloudflare؛ إن غاب، فالرفض من التطبيق نفسه لا من Cloudflare.
  • افحص ما إذا كان ملف cf_clearance قد وصل في ترويسة Set-Cookie بعد الإرسال.
  • قِس الزمن بين لحظة الحل ولحظة الإرسال؛ إن تجاوز 240 ثانية فالرمز غالباً منتهٍ.
  • ثبّت عنوان IP وUser-Agent بين مرحلتَي الحل والإرسال.

أول ما يجب التأكد منه: Turnstile أم Cloudflare Challenge؟

قبل أن تلاحق ملفات تعريف الارتباط أو الرؤوس، تأكد من نوع الحماية أمامك. فـ Turnstile وCloudflare Challenge نظامان مختلفان، وحلّ أحدهما لا ينفع مع الآخر:

الميزة Turnstile Cloudflare Challenge
شكل الواجهة مربع اختيار ظاهر داخل الصفحة شاشة تحدٍّ تملأ الصفحة بالكامل
طريقة CaptchaAI turnstile cloudflare_challenge
حقل الرمز cf-turnstile-response لا يوجد (يعتمد على ملفات تعريف الارتباط)

إذا كانت الصفحة تعرض شاشة تحدٍّ كاملة بلا نموذج، فأنت أمام Cloudflare Challenge، واستخدم method=cloudflare_challenge بدلاً من طريقة turnstile.


جدول الأسباب من الأكثر شيوعاً إلى الأقل

السبب مدى الشيوع
غياب ملف تعريف الارتباط cf_clearance شائع جداً
انتهاء صلاحية الرمز شائع
نقطة إرسال أو حقل خاطئ شائع
رؤوس طلب ناقصة متوسط
اختلاف عنوان IP بين الحل والإرسال متوسط
الخلط بين Cloudflare Challenge وTurnstile التباس متكرر

السبب الأول والأكثر شيوعاً: ضياع ملف cf_clearance

يضبط Turnstile ملفات تعريف ارتباط أثناء عملية التحقق. إن لم تُرفق هذه الملفات في طلبك التالي، يحظرك Cloudflare مباشرة. الحل هو استخدام جلسة (Session) واحدة تحمل ملفات تعريف الارتباط من مرحلة الحل حتى الطلب النهائي:

import requests

session = requests.Session()

# Step 1: Load the page to get initial cookies
session.get("https://example.com")

# Step 2: Solve Turnstile
token = solve_turnstile(
    api_key="YOUR_API_KEY",
    sitekey="TURNSTILE_SITEKEY",
    pageurl="https://example.com",
)

# Step 3: Submit token to the validation endpoint
# This sets cf_clearance cookie
resp = session.post("https://example.com/api/verify", data={
    "cf-turnstile-response": token,
}, headers={
    "Content-Type": "application/x-www-form-urlencoded",
    "Origin": "https://example.com",
    "Referer": "https://example.com/",
})

# Step 4: Now make your actual request WITH the session cookies
resp = session.get("https://example.com/protected-page")
print(resp.status_code)  # Should be 200 now

المفتاح هنا ليس الرمز في حد ذاته، بل ملف cf_clearance الذي يُضبط بعد إرساله؛ والجلسة الواحدة هي ما ينقل هذا الملف من طلب إلى آخر.


السبب الثاني: انتهاء صلاحية الرمز قبل استخدامه

يبقى رمز Turnstile صالحاً نحو 300 ثانية، لكن الأفضل إرساله فوراً. فكلما طالت المدة بين الحل والإرسال، ارتفع احتمال رفضه:

import time

# Solve
start = time.time()
token = solve_turnstile(...)
solve_time = time.time() - start

# Check if token is still fresh
if solve_time > 240:  # > 4 minutes is risky
    print("Token may be too old, solving again...")
    token = solve_turnstile(...)

# Submit immediately
submit_token(token)

السبب الثالث: إرسال الرمز بالحقل أو بالطريقة الخاطئة

تختلف المواقع في كيفية استقبال رمز Turnstile، وتندرج معظمها ضمن ثلاثة أنماط:

  • حقل مخفي داخل النموذج.
  • رأس مخصص في الطلب.
  • حقل ضمن جسم JSON.

يوضح المثال التالي الأنماط الثلاثة:

# Some sites use a hidden form field
data = {
    "cf-turnstile-response": token,
    "username": "user",
    "password": "pass",
}

# Some sites use a custom header
headers = {
    "X-Turnstile-Token": token,
}

# Some sites use JSON body
json_data = {
    "turnstileToken": token,
    "email": "user@example.com",
}

كيف تعثر على اسم الحقل الصحيح:

  1. افتح أدوات المطور DevTools وانتقل إلى تبويب الشبكة (Network).
  2. أكمل تحدي Turnstile يدوياً داخل المتصفح.
  3. ابحث عن طلب إرسال النموذج بين الطلبات الظاهرة.
  4. افحص جسم الطلب (request body) لتقرأ اسم حقل الرمز الفعلي.

السبب الرابع: رؤوس الطلب الناقصة

يفحص Cloudflare اتساق رؤوس الطلب، فغياب Origin أو Referer أو رؤوس Sec-Fetch-* قد يكفي وحده لإطلاق 403. أعد إرسال الرؤوس كما يرسلها المتصفح تماماً:

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    "Accept-Language": "en-US,en;q=0.9",
    "Origin": "https://example.com",
    "Referer": "https://example.com/login",
    "Sec-Fetch-Dest": "document",
    "Sec-Fetch-Mode": "navigate",
    "Sec-Fetch-Site": "same-origin",
}

session.headers.update(headers)

مثال كامل: من الحل إلى الوصول إلى الصفحة المحمية

يجمع المثال التالي المسار بأكمله في دالة واحدة — قراءة sitekey من الصفحة، ثم الحل عبر CaptchaAI، فاستطلاع النتيجة، وأخيراً إرسال الرمز عبر الجلسة نفسها:

import requests
import time
import re


def solve_turnstile_and_access(target_url, api_key):
    """Complete flow: solve Turnstile and access protected page."""
    session = requests.Session()
    session.headers.update({
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
    })

    # Load page, get cookies and sitekey
    resp = session.get(target_url)
    match = re.search(r'data-sitekey="([^"]+)"', resp.text)
    if not match:
        raise RuntimeError("Turnstile sitekey not found")

    sitekey = match.group(1)

    # Solve via CaptchaAI
    submit_resp = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": api_key,
        "method": "turnstile",
        "sitekey": sitekey,
        "pageurl": target_url,
        "json": 1,
    }, timeout=30)
    task_id = submit_resp.json()["request"]

    # Poll
    for _ in range(12):
        time.sleep(5)
        poll = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": api_key, "action": "get",
            "id": task_id, "json": 1,
        }, timeout=15)
        data = poll.json()
        if data.get("status") == 1:
            token = data["request"]
            break
    else:
        raise TimeoutError("Solve timeout")

    # Submit token using the same session
    form_resp = session.post(target_url, data={
        "cf-turnstile-response": token,
    }, headers={
        "Origin": f"https://{requests.utils.urlparse(target_url).netloc}",
        "Referer": target_url,
    })

    return session, form_resp


# Usage
session, resp = solve_turnstile_and_access(
    "https://example.com/login",
    "YOUR_API_KEY",
)
# session now has valid cookies for subsequent requests

حالة واقعية: 403 يظهر في الطلب الثاني فقط

تخيّل فريقاً في القاهرة يبني أداة لمراقبة أسعار متجر إلكتروني إقليمي محمي بـ Turnstile. يرسل الفريق الرمز فيحصل على 200 OK وتظهر الصفحة المحمية، لكن بعد دقيقتين يطلب المسار نفسه /api/orders فيعود الرد 403. اتُّهم انتهاء صلاحية الرمز، والسبب الحقيقي أن عميل HTTP كان يُنشأ من جديد داخل دالة مساعدة مع كل طلب بجلسة فارغة من ملفات تعريف الارتباط، فلم يصل ملف cf_clearance المضبوط في الاستجابة الأولى إلى الطلب الثاني إطلاقاً.

الإصلاح: أنشئ requests.Session() مرة واحدة ومرّرها إلى كل الطلبات اللاحقة على النطاق نفسه. الرمز يُستخدم مرة واحدة فقط، أما ما ينقلك إلى ما بعد ذلك فهو ملف تعريف الارتباط داخل الجلسة. والقاعدة العملية: بعد نجاح الإرسال، تعامل مع الجلسة — أو مع سياق المتصفح BrowserContext في Playwright — بوصفها بيانات الاعتماد طويلة الأمد لا مع الرمز.

وإذا كنت تحل Turnstile بكميات كبيرة عبر مسارات متوازية، فتذكّر أن خطط CaptchaAI تُحسب على أساس الخيوط (threads) لا على أساس كل عملية حل، بدءاً من خطة BASIC ($15 شهرياً، 5 خيوط)، مع عدد غير محدود من عمليات الحل لكل خيط.


قائمة تحقق سريعة قبل أن تلوم الخدمة

راجع هذه النقاط قبل فتح تذكرة دعم؛ فمعظم حالات 403 المبلَّغ عنها تُكتشف هنا:

  • ثبات سلسلة User-Agent نفسها أثناء الحل وأثناء الإرسال.
  • ثبات عنوان IP الصادر بين الحل والإرسال (أو تثبيت البروكسي على مستوى الجلسة).
  • تطابق رأسَي Origin وReferer مع رابط الصفحة المستهدفة.
  • إرسال الرمز خلال 240 ثانية من استلامه.
  • إرسال الرمز مرة واحدة فقط، فرموز Turnstile للاستخدام الواحد.
  • التحقق من اسم حقل النموذج في DevTools (cf-turnstile-response أو اسم مخصص).
  • إعادة استخدام الجلسة نفسها عبر الحل ثم الإرسال ثم الطلبات التالية.
  • إعادة استخراج data-sitekey في كل تشغيل، فمفتاح الموقع قد يتغير.
  • التأكد أن الصفحة تعرض Turnstile فعلاً لا شاشة Cloudflare Challenge كاملة.
  • التأكد من وصول Set-Cookie: cf_clearance=... في الاستجابة بعد الإرسال.

جدول استكشاف الأخطاء

المشكلة السبب المرجّح الإجراء
403 رغم أن الرمز صالح ملفات تعريف ارتباط الجلسة مفقودة استخدم الجلسة نفسها لكل الطلبات
403 في الصفحات اللاحقة لم يُضبط cf_clearance يجب أن يُعيد التحقق من الرمز ملف تعريف الارتباط
ينجح مرة ثم يعود 403 انتهت صلاحية ملف تعريف الارتباط أعد الحل للحصول على ملف جديد
403 دائماً شاشة تحدٍّ كاملة لا Turnstile استخدم طريقة cloudflare_challenge

الأسئلة الشائعة

لماذا يظهر 403 رغم أن الرمز صالح؟

لأن اجتياز Turnstile لا يكتمل بالرمز وحده. بعد إرساله يضبط Cloudflare ملف cf_clearance، وهذا الملف — لا الرمز — هو ما يسمح بالطلبات التالية. فإن ضاع الملف بسبب جلسة جديدة أو رؤوس غير متطابقة، يعود 403 رغم صلاحية الرمز.

هل يمكن إعادة استخدام رمز Turnstile في أكثر من طلب؟

لا. رمز Turnstile للاستخدام مرة واحدة فقط. أرسله في طلب واحد، ثم اعتمد على ملفات تعريف الارتباط الناتجة في الجلسة لبقية الطلبات. إعادة إرسال الرمز نفسه ستُقابَل بالرفض.

كيف أميّز Turnstile عن Cloudflare Challenge بسرعة؟

Turnstile مربع اختيار صغير داخل نموذج الصفحة، وحقله cf-turnstile-response. أما Cloudflare Challenge فشاشة كاملة بلا نموذج، تعتمد على ملفات تعريف الارتباط وتُحل بطريقة cloudflare_challenge. فإن لم تجد حقل الرمز في الصفحة، فأنت غالباً أمام Challenge.

هل يلزم بروكسي لحل Turnstile عبر CaptchaAI؟

غالباً لا. فنظراً لارتفاع معدل نجاح CaptchaAI على Turnstile، ينجح الحل عادةً دون بروكسي. أضف بروكسي فقط إذا كان الموقع يتحقق من تطابق عنوان IP بين الحل والإرسال. وتذكّر أن ملف cf_clearance مرتبط بـ User-Agent وقد يرتبط بعنوان IP، فحافظ على ثباتهما طوال مدة الجلسة.


أدلة ذات صلة


عالجت خطأ 403؟ ابدأ بحل Turnstile مع CaptchaAI بثبات.

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