So Sánh

Thử thách được quản lý trên Cloudflare so với Thử thách tương tác

Managed Challenge và Interactive Challenge là hai hành động thử thách Cloudflare cho phép cấu hình trong quy tắc WAF, khác nhau ở đúng một điểm: Managed Challenge thích ứng theo khách truy cập — khoảng 90% đi qua mà không thấy CAPTCHA — còn Interactive Challenge luôn bắt buộc tương tác. Cả hai đều giải được bằng phương pháp turnstile của CaptchaAI; việc còn lại là nhận đúng loại thử thách từ mã trạng thái HTTP trước khi gửi request.


Đặc điểm chính của Managed Challenge và Interactive Challenge

  • Năm ra mắt: 2021 với Managed Challenge; kế thừa, có từ trước 2021 với Interactive Challenge.
  • Khả năng thích ứng: Cloudflare tự chọn mức độ khó ở Managed Challenge; Interactive Challenge chỉ có một mức duy nhất.
  • Tỷ lệ vượt vô hình: ~90% với Managed Challenge; không có với Interactive Challenge.
  • Các mức thử thách: vô hình → Turnstile → JS challenge (Managed); luôn hiển thị CAPTCHA (Interactive).
  • Khuyến nghị của Cloudflare: Managed Challenge là mặc định cho quy tắc mới; Interactive Challenge chỉ giữ để tương thích ngược.
  • Ma sát với người dùng: thấp ở Managed Challenge, cao ở Interactive Challenge.
  • Mã trạng thái HTTP: 503 (Managed) so với 403 (Interactive).
  • Phương pháp CaptchaAI: turnstile hoặc cloudflare_challenge cho Managed; chỉ turnstile cho Interactive.

3 bước xác định thử thách trước khi gọi CaptchaAI

  1. Đọc mã trạng thái: 503 gợi ý Managed Challenge hoặc IUAM, 403 gợi ý Interactive Challenge hoặc WAF block.
  2. Quét HTML tìm challenge-platform, đường dẫn managed, hoặc chuỗi jschl để tách các loại.
  3. Chọn phương pháp tương ứng — turnstile cho phần lớn trường hợp, cloudflare_challenge khi thấy "Đang kiểm tra trình duyệt của bạn".

Tình huống thực tế: đội QA outsource kiểm thử site khách hàng

Một kịch bản phổ biến với các công ty outsourcing ở TP.HCM và Hà Nội chạy regression test cho khách hàng nước ngoài: site khách hàng bật Cloudflare, nhưng team QA không biết trước cấu hình Managed hay Interactive Challenge — vì điều này có thể đổi bất cứ lúc nào. Cách xử lý an toàn là log lại mã trạng thái HTTP và dấu hiệu HTML mỗi lần chạy job, thay vì hard-code một phương pháp cố định. Với khối lượng test thấp trên staging, gói BASIC ($15/tháng, 5 thread) của CaptchaAI thường đã đủ; khi cần nhiều luồng CI/CD song song hơn mới tính đến STANDARD ($30/tháng, 15 thread) hoặc các gói cao hơn.


Managed Challenge: Cloudflare tự chọn mức độ khó

Managed Challenge là hành động thử thách được Cloudflare khuyến nghị. Nó dùng một khung quyết định để đưa ra mức thử thách ít gây gián đoạn nhất có thể cho từng khách truy cập.

Cloudflare đánh giá tín hiệu như thế nào

WAF rule triggers Managed Challenge
    ↓
Cloudflare evaluates visitor signals:
  ├─ Browser fingerprint quality
  ├─ IP reputation score
  ├─ TLS fingerprint (JA3/JA4)
  ├─ Request history
  ├─ Behavioral signals
  └─ Device capabilities
    ↓
Risk assessment → Challenge level selected:
  ├─ LOW risk → Invisible pass (no visible UI)
  ├─ MEDIUM risk → Non-interactive Turnstile (background PoW)
  ├─ HIGH risk → Interactive Turnstile (checkbox/widget)
  └─ VERY HIGH risk → JavaScript challenge page (5s wait)
    ↓
Challenge completed
    ↓
qa_session_cookie cookie issued

Bốn nhánh rủi ro trên tương ứng với bốn trải nghiệm mà cùng một script có thể gặp khi chạy lặp lại trên cùng site — không phải lỗi code, mà là Cloudflare phản ứng khác nhau theo tín hiệu từng request.

Khách truy cập thực sự thấy gì

  • Trình duyệt bình thường, IP uy tín (~90%): không thấy gì — vượt qua vô hình.
  • Trình duyệt mới, IP trung tính (~5%): một vòng xoay tải ngắn.
  • Tín hiệu đáng ngờ (~4%): hộp kiểm Turnstile.
  • Tín hiệu rủi ro cao (~1%): trang "Đang kiểm tra trình duyệt của bạn...".

Mã HTML thực tế

Trang Managed Challenge dùng nền tảng thử thách riêng của Cloudflare:

<!-- Managed Challenge page (when visible) -->
<body>
    <div id="challenge-stage">
        <div id="challenge-body-text">
            Verifying you are human. This may take a few seconds.
        </div>

        <!-- Turnstile widget (when rendered) -->
        <div class="cf-turnstile"
             data-sitekey="0x4AAAAAAAC3DHQhMMQ_Rxrg">
        </div>
    </div>

    <!-- Challenge platform script -->
    <script src="/cdn-cgi/challenge-platform/h/g/orchestrate/managed/v1?ray=...">
    </script>
</body>

Interactive Challenge: CAPTCHA luôn hiển thị

Interactive Challenge luôn đưa ra một CAPTCHA hiển thị mà khách truy cập bắt buộc phải tương tác. Không có đường đi vô hình — mọi request đều nhìn thấy và phải hoàn thành thử thách trước khi được phục vụ nội dung.

Cách hoạt động

WAF rule triggers Interactive Challenge
    ↓
Full-page CAPTCHA served (HTTP 403)
    ↓
Visitor must interact with CAPTCHA widget
    ↓
CAPTCHA solved
    ↓
qa_session_cookie cookie issued

Khác với Managed Challenge, ở đây không có bước đánh giá rủi ro nào cả — mọi request đều nhận cùng một trang thử thách, bất kể fingerprint trình duyệt hay uy tín IP tốt đến đâu.

Khách truy cập thực sự thấy gì

Mọi khách truy cập đều gặp một trang thử thách toàn màn hình với tiện ích giống Turnstile:

<!-- Interactive Challenge page -->
<body>
    <div id="challenge-running">
        <div class="main-wrapper">
            <h2>Please verify you are human</h2>

            <!-- Always-visible challenge widget -->
            <div class="challenge-widget">
                <!-- Checkbox + verification -->
            </div>
        </div>
    </div>
</body>

Vì sao Cloudflare khuyên hạn chế dùng

Năm lý do Cloudflare khuyến nghị chuyển sang Managed Challenge:

  1. Luôn hiển thị — 100% khách truy cập thấy thử thách, không có ngoại lệ.
  2. Ma sát cao hơn — mọi khách truy cập đều phải tương tác trước khi vào trang.
  3. Tỷ lệ thoát cao hơn — nhiều người bỏ đi thay vì hoàn thành thử thách.
  4. Không thích ứng theo rủi ro — cả khách truy cập uy tín cũng bị chặn lại như người lạ.
  5. Vấn đề khả năng tiếp cận — ai cũng buộc phải hoàn thành thao tác tương tác, kể cả người dùng công cụ hỗ trợ.

Cách phát hiện bạn đang gặp loại thử thách nào

Trước khi gửi request tới CaptchaAI, cần xác định chính xác loại thử thách — gửi sai phương pháp chỉ tốn thread mà không ra token. Hàm dưới đây đọc mã trạng thái HTTP và nội dung HTML để phân loại:

import requests
import re

def identify_challenge_type(url):
    """Determine if a URL uses Managed or Interactive Challenge."""
    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
    status = response.status_code

    result = {
        "url": url,
        "status": status,
        "challenge_type": None,
        "cf_ray": response.headers.get("cf-ray", ""),
        "solve_method": None,
    }

    if status == 200:
        # Check for inline Turnstile widget (not a challenge page)
        if "cf-turnstile" in html:
            result["challenge_type"] = "turnstile_widget"
            result["solve_method"] = "turnstile"
        else:
            result["challenge_type"] = "none"
        return result

    if status == 503:
        # 503 indicates Managed Challenge or IUAM
        if "managed" in html or "challenge-platform" in html:
            result["challenge_type"] = "managed_challenge"
            result["solve_method"] = "turnstile"  # Managed renders as Turnstile
        elif "jschl" in html:
            result["challenge_type"] = "iuam_js_challenge"
            result["solve_method"] = "cloudflare_challenge"
        else:
            result["challenge_type"] = "unknown_503"
        return result

    if status == 403:
        if "challenge" in html.lower():
            result["challenge_type"] = "interactive_challenge"
            result["solve_method"] = "turnstile"
        else:
            result["challenge_type"] = "waf_block"
            result["solve_method"] = None  # Hard block, not solvable
        return result

    return result

# Usage
info = identify_challenge_type("https://protected-site.com/login")
print(f"Challenge: {info['challenge_type']}")
print(f"Solve with: {info['solve_method']}")

Đối chiếu tín hiệu theo từng loại

  • Managed Challenge: HTTP 503, có challenge-platform trong HTML, có đường dẫn managed trong script, không luôn hiển thị tiện ích, có thể vượt qua vô hình.
  • Interactive Challenge: HTTP 403, có challenge-platform trong HTML nhưng không có đường dẫn managed, luôn hiển thị tiện ích, không có đường đi vô hình.
  • IUAM (JS challenge kế thừa): HTTP 503, không có challenge-platform, có jschl trong HTML, không hiển thị tiện ích, không vượt qua vô hình.
  • WAF block thuần túy: HTTP 403, không có bất kỳ dấu hiệu thử thách nào ở trên — đây là chặn cứng, không giải được bằng CaptchaAI.

Giải từng loại thử thách bằng CaptchaAI

Cả hai loại thử thách đều đi qua cùng hai endpoint quen thuộc — in.php để gửi task, res.php để polling kết quả — nên phần khác biệt duy nhất giữa các đoạn code dưới đây nằm ở method và cách lấy sitekey.

Giải Managed Challenge

Managed Challenge thường hiển thị dưới dạng tiện ích Cloudflare Turnstile. Dùng phương pháp turnstile của CaptchaAI:

import requests
import time

API_KEY = "YOUR_API_KEY"

def solve_managed_challenge(url, sitekey=None):
    """Solve Cloudflare Managed Challenge."""
    # If sitekey not provided, extract from page
    if not sitekey:
        import re
        headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                          "AppleWebKit/537.36 Chrome/120.0.0.0",
        }
        page = requests.get(url, headers=headers, timeout=15)
        match = re.search(
            r'data-sitekey=["\']([0-9x][A-Za-z0-9_-]+)["\']', page.text
        )
        sitekey = match.group(1) if match else None

    if not sitekey:
        # No visible Turnstile — try cloudflare_challenge method
        return solve_js_challenge(url)

    submit = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY,
        "method": "turnstile",
        "sitekey": sitekey,
        "pageurl": 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("Solve timed out")

def solve_js_challenge(url):
    """Fallback to cloudflare_challenge method."""
    submit = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY,
        "method": "cloudflare_challenge",
        "sitekey": "managed",
        "pageurl": 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("Solve timed out")

Lưu ý hàm solve_managed_challenge tự rơi về solve_js_challenge khi không tìm thấy sitekey trên trang — đây là dấu hiệu Managed Challenge đã leo thang lên JS challenge thay vì hiển thị Turnstile.

Giải Interactive Challenge

Interactive Challenge luôn hiển thị một tiện ích. Dùng cùng phương pháp turnstile:

def solve_interactive_challenge(url, sitekey):
    """Solve Cloudflare Interactive Challenge (legacy)."""
    submit = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY,
        "method": "turnstile",
        "sitekey": sitekey,
        "pageurl": 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("Solve timed out")

Ở đây sitekey được truyền sẵn từ bước phát hiện phía trên, khác với solve_managed_challenge vốn tự trích xuất sitekey khi cần.

Node.js: xử lý cả hai loại trong cùng một hàm

const axios = require("axios");

const API_KEY = "YOUR_API_KEY";

async function solveCloudflareChallenge(url, type = "managed") {
  const method = type === "js_challenge" ? "cloudflare_challenge" : "turnstile";
  const sitekey =
    type === "js_challenge" ? "managed" : await extractSitekey(url);

  const submit = await axios.post("https://ocr.captchaai.com/in.php", null, {
    params: {
      key: API_KEY,
      method,
      sitekey: sitekey || "managed",
      pageurl: url,
      json: 1,
    },
  });

  const taskId = submit.data.request;

  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) {
      return result.data.request;
    }
  }

  throw new Error("Solve timed out");
}

async function extractSitekey(url) {
  try {
    const response = await axios.get(url, {
      headers: { "User-Agent": "Mozilla/5.0 Chrome/120.0.0.0" },
      validateStatus: () => true,
    });
    const match = response.data.match(
      /data-sitekey=["']([0-9x][A-Za-z0-9_-]+)["']/
    );
    return match ? match[1] : null;
  } catch {
    return null;
  }
}

Khi site chuyển từ Interactive sang Managed

Cloudflare khuyến nghị site chuyển từ Interactive Challenge sang Managed Challenge. Nếu site bạn đang tự động hóa chuyển đổi, đây là những gì thay đổi trong pipeline:

  1. Interactive → Managed: request có thể bắt đầu qua vô hình, với khả năng khoảng 90%.
  2. HTTP 403 → 503: cần cập nhật logic kiểm tra mã trạng thái trong script.
  3. Luôn hiển thị → thích ứng: tiện ích Turnstile có thể không còn xuất hiện trong HTML mỗi lần request.
  4. Cùng một sitekey: code giải CaptchaAI của bạn giữ nguyên, không cần viết lại.
  5. Cùng cookie qa_session_cookie: logic xử lý cookie sau khi giải không đổi.

Khắc phục sự cố thường gặp

Sáu tình huống đội QA thường gặp — nhận đúng nguyên nhân giúp tránh gửi sai phương pháp và tốn thread oan:

  • 503 không thấy tiện ích: Managed Challenge đã vượt qua vô hình — không cần làm gì, bạn đã qua.
  • 503 kèm "Đang kiểm tra trình duyệt của bạn": Managed Challenge nâng cấp lên JS challenge — dùng phương pháp cloudflare_challenge.
  • 403 kèm CAPTCHA hiển thị: đây là Interactive Challenge (legacy) — dùng phương pháp turnstile.
  • 403 không có thử thách nào: đây là WAF block thuần túy, không phải thử thách — đổi IP hoặc mẫu request thay vì gọi CaptchaAI.
  • Loại thử thách đổi ngẫu nhiên qua các lần chạy: Managed Challenge đang thích ứng theo tín hiệu — xử lý cả Turnstile lẫn JS challenge trong cùng một luồng.
  • Cookie qa_session_cookie từ loại này bị từ chối ở loại khác: hai luồng thử thách khác nhau trên cùng domain — luôn giải đúng thử thách đang được đưa ra tại thời điểm đó, đừng tái dùng cookie cũ.

Trước mỗi lần chạy job, kiểm tra xem site trả về trang thử thách toàn màn hình hay chỉ nhúng tiện ích trong luồng ứng dụng, và ghi lại kết quả kèm URL cùng định danh proxy — nhờ vậy khi site đổi cấu hình, team phát hiện ngay thay vì chỉ thấy job fail.


Câu hỏi thường gặp

Năm câu hỏi dưới đây là những gì đội automation/QA thường thắc mắc nhất sau khi đã đọc phần phát hiện và giải thử thách ở trên.

Vì sao trang tôi đang tự động hóa đột nhiên trả về 503 thay vì 403?

Nhiều khả năng site vừa chuyển từ Interactive Challenge sang Managed Challenge — đây là hướng Cloudflare khuyến khích. Cập nhật logic kiểm tra mã trạng thái để xử lý cả 503 lẫn 403, và ưu tiên thử phương pháp turnstile trước.

CaptchaAI tính phí ra sao khi Managed Challenge vượt qua tôi vô hình?

Không tốn gì. Nếu Managed Challenge đánh giá request là rủi ro thấp, nó cho qua thẳng với HTTP 200 và không có thử thách hiển thị nào — không cần gọi CaptchaAI, nên không dùng thread nào. Bạn chỉ trả tiền thread khi thực sự có task gửi tới in.php, tức là:

  • Request nhận HTTP 503 kèm tiện ích Turnstile hoặc trang JS challenge.
  • Request nhận HTTP 403 với CAPTCHA Interactive Challenge hiển thị.

Có. Cả Managed Challenge và Interactive Challenge đều phát hành cùng một cookie qa_session_cookie sau khi giải xong, nên logic lưu và tái sử dụng cookie trong code của bạn không cần phân biệt loại thử thách.

Làm sao phân biệt Interactive Challenge với một WAF block thông thường?

Cả hai đều trả về HTTP 403, nhưng chỉ Interactive Challenge có widget CAPTCHA và chuỗi challenge trong HTML. Một WAF block thuần túy không có gì để giải — đổi IP hoặc mẫu request thay vì cố gửi task tới CaptchaAI.

sitekey Turnstile có đổi khi site chuyển từ Interactive sang Managed không?

Không. sitekey gắn với site, không gắn với loại thử thách, nên code giải CaptchaAI của bạn giữ nguyên qua đợt chuyển đổi — chỉ có mã trạng thái HTTP và tần suất xuất hiện tiện ích là thay đổi.


Tóm tắt

Managed Challenge của Cloudflare chọn thích ứng mức độ khó cho từng khách truy cập — từ vô hình đến JS challenge đầy đủ — trong khi Interactive Challenge luôn đưa ra một CAPTCHA hiển thị. Cả hai đều phát hành cùng cookie qa_session_cookie và đều giải được bằng CaptchaAI: dùng turnstile cho phần lớn trường hợp, cloudflare_challenge cho các trang JS challenge. Managed Challenge là mặc định hiện nay; Interactive Challenge chỉ còn tồn tại vì lý do tương thích ngược.

Bài viết liên quan

Os comentários estão desativados para este artigo.