Request trả về lỗi 403 hay 503 khi bạn crawl một site đứng sau Cloudflare? Câu trả lời quyết định luôn bước sửa tiếp theo. 403 là dấu hiệu của Kiểm tra tính toàn vẹn trình duyệt (Browser Integrity Check — BIC) — một lớp chặn thụ động ở tầng header, không đưa ra bất kỳ thử thách nào để giải. 503 kèm trang thử thách là CAPTCHA của Cloudflare (Turnstile, Managed Challenge, JavaScript Challenge) — một tác vụ mà trình duyệt hợp lệ vượt qua được, và CaptchaAI giải được. Nhầm hai loại chặn này là lỗi debug phổ biến nhất: thêm CaptchaAI vào chỗ chỉ cần sửa header, hoặc loay hoay sửa header cho một thử thách JS thực sự cần solver.
Điểm khác nhau nhanh giữa BIC và thử thách CAPTCHA
- Kiểm tra gì: BIC chỉ nhìn header HTTP; CAPTCHA đánh giá hành vi trình duyệt cộng môi trường thực thi.
- Cần JavaScript? BIC không cần — chặn ở tầng header; CAPTCHA thì có, phải thực thi JS.
- Người dùng thấy gì? BIC: không thấy gì khi qua, hoặc 403 khi chặn. CAPTCHA: widget thử thách hoặc trang JS.
- HTTP status khi chặn: BIC trả 403; CAPTCHA trả 503.
- Giải được không? BIC thì không — chỉ sửa header, không có gì để "giải". CAPTCHA thì có, giải bằng CaptchaAI.
- Cookie cấp sau khi qua: BIC không cấp cookie; CAPTCHA cấp
qa_session_cookie. - Cần CaptchaAI? BIC không cần, sửa header là đủ. CAPTCHA thì cần.
- Bật mặc định? BIC bật sẵn trên mọi gói Cloudflare; CAPTCHA thì cấu hình theo từng rule.
- Áp dụng cho: BIC áp dụng cho mọi request; CAPTCHA chỉ áp dụng cho request khớp rule WAF.
BIC là gì và kiểm tra ra sao
BIC đánh giá header của request HTTP để phát hiện traffic rõ ràng không đến từ trình duyệt thật, chạy trước bất kỳ thử thách JavaScript hay CAPTCHA nào. Nó nhìn vào năm nhóm dấu hiệu:
- User-Agent: UA thiếu, rỗng, hoặc nằm trong danh sách xấu — ví dụ
python-requests/2.31, curl, wget. - Thứ tự header: Header sắp xếp bất thường, đặc trưng của thư viện HTTP không phải trình duyệt.
- Header trình duyệt bị thiếu: Thiếu
Accept,Accept-Language,Accept-Encoding— dấu hiệu của HTTP client tối giản. - Chữ ký bot đã biết: UA của spam bot, scanner, hoặc
Googlebotgiả mạo từ IP không thuộc Google. - IP trong blacklist: IP datacenter hoặc IP độc hại đã ghi nhận trong blocklist.
Toàn bộ quy trình diễn ra theo thứ tự sau:
Request hits Cloudflare edge
↓
BIC evaluates HTTP headers:
├─ User-Agent present and valid?
├─ Required headers (Accept, Accept-Language) present?
├─ Header order consistent with browser?
└─ IP not on abuse list?
↓
Pass → Request forwarded to origin
OR
Fail → 403 Forbidden (no challenge offered)
BIC hết chặn ngay khi request gửi kèm header giống trình duyệt thật — không cần giải CAPTCHA nào cả. Ví dụ bằng Python:
import requests
# ❌ FAILS BIC — minimal headers
response = requests.get("https://cloudflare-protected.com")
# User-Agent: python-requests/2.31.0
# Result: 403 Forbidden
# ✅ PASSES BIC — browser-like headers
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,"
"image/avif,image/webp,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
"Connection": "keep-alive",
"Upgrade-Insecure-Requests": "1",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "none",
"Sec-Fetch-User": "?1",
}
response = requests.get("https://cloudflare-protected.com", headers=headers)
# Result: 200 OK (passed BIC)
Ở Node.js, logic tương tự áp dụng cho axios:
const axios = require("axios");
// Browser-like headers to pass BIC
const headers = {
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0",
Accept:
"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
Connection: "keep-alive",
"Upgrade-Insecure-Requests": "1",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "none",
"Sec-Fetch-User": "?1",
};
async function fetchWithBIC(url) {
const response = await axios.get(url, { headers });
console.log(`Status: ${response.status}`);
return response.data;
}
Thử thách CAPTCHA của Cloudflare hoạt động ra sao
Thử thách CAPTCHA chỉ xuất hiện sau khi request đã qua BIC. Chúng cần JavaScript thực thi và đưa ra một tác vụ giải được. Cloudflare dùng bốn dạng chính:
- Widget Turnstile — dev nhúng trực tiếp vào trang, hiển thị widget trên form. CaptchaAI xử lý bằng method
turnstile. - Managed Challenge — kích hoạt khi khớp rule WAF, thích ứng vô hình hoặc dạng checkbox. Method
turnstile. - JavaScript Challenge — kích hoạt bởi rule IUAM hoặc WAF, hiển thị trang "Checking your browser". Method
cloudflare_challenge. - Interactive Challenge — xuất hiện khi mức nghi ngờ cao, thử thách toàn trang. Method
cloudflare_challenge.
Luồng xử lý khác hẳn BIC:
Request passes BIC check
↓
WAF rules evaluate bot score, IP, path
↓
Rule triggers CAPTCHA challenge (HTTP 503)
↓
Browser executes JavaScript challenge
↓
Challenge solved → qa_session_cookie cookie issued
↓
Subsequent requests pass with cookie
Phân biệt chặn BIC với thử thách CAPTCHA bằng code
Khi request bị chặn, việc xác định đúng loại quyết định cách sửa:
import requests
def diagnose_cloudflare_block(url):
"""Determine if block is BIC or CAPTCHA."""
# Intentionally use minimal headers to trigger BIC
minimal_response = requests.get(url, timeout=15, allow_redirects=False)
# Use browser headers to bypass BIC
browser_headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 Chrome/120.0.0.0",
"Accept": "text/html,application/xhtml+xml,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
}
browser_response = requests.get(
url, headers=browser_headers, timeout=15, allow_redirects=False
)
result = {
"minimal_headers_status": minimal_response.status_code,
"browser_headers_status": browser_response.status_code,
}
if minimal_response.status_code == 403 and browser_response.status_code == 200:
result["diagnosis"] = "BIC only — fix headers to pass"
result["fix"] = "Add browser-like headers"
elif minimal_response.status_code == 403 and browser_response.status_code == 403:
result["diagnosis"] = "IP or WAF block — not just BIC"
result["fix"] = "Change IP or check WAF rules"
elif browser_response.status_code == 503:
html = browser_response.text
if "jschl" in html:
result["diagnosis"] = "IUAM JavaScript challenge"
result["fix"] = "Use CaptchaAI cloudflare_challenge method"
elif "cf-turnstile" in html or "challenge-platform" in html:
result["diagnosis"] = "Managed/Turnstile challenge"
result["fix"] = "Use CaptchaAI turnstile method"
else:
result["diagnosis"] = "Unknown Cloudflare challenge"
result["fix"] = "Inspect page source for challenge type"
elif browser_response.status_code == 200:
html = browser_response.text
if "cf-turnstile" in html:
result["diagnosis"] = "Page loads but has Turnstile widget"
result["fix"] = "Use CaptchaAI turnstile method for form submission"
else:
result["diagnosis"] = "No challenge — page accessible"
result["fix"] = "None needed"
return result
# Usage
diagnosis = diagnose_cloudflare_block("https://example-cf-site.com")
print(f"Diagnosis: {diagnosis['diagnosis']}")
print(f"Fix: {diagnosis['fix']}")
Bốn tình huống thực tế khi debug Cloudflare
Với các team QA/automation outsource tại Việt Nam đang chạy scraping hoặc kiểm thử trên nhiều site đứng sau Cloudflare cùng lúc, log riêng status code theo từng domain giúp khoanh vùng nhanh hơn nhiều so với đoán mò. Bốn tình huống dưới đây bao trùm gần hết các ca thực tế.
Tình huống 1 — chỉ bị chặn bởi BIC:
Request with python-requests UA → 403
Request with Chrome UA → 200 ✓
Fix: Add proper browser headers. No CaptchaAI needed.
Tình huống 2 — qua được BIC, gặp CAPTCHA:
Request with Chrome UA → 503 (challenge page)
Fix: Headers are fine. Dùng CaptchaAI để solve the challenge.
Tình huống 3 — dính cả BIC lẫn CAPTCHA:
Request with python-requests UA → 403 (BIC block)
Request with Chrome UA → 503 (CAPTCHA challenge)
Fix: First fix headers, then solve CAPTCHA with CaptchaAI.
Tình huống 4 — không phải BIC, không phải CAPTCHA, chỉ là IP bị chặn:
Request with python-requests UA → 403
Request with Chrome UA → 403
Fix: Neither BIC nor solvable challenge. IP is blocked.
Try different IP/proxy.
Header chuẩn để vượt qua BIC
Bộ header dưới đây đủ để hầu hết request qua được BIC ngay lần đầu:
CLOUDFLARE_SAFE_HEADERS = {
# Mandatory
"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",
"Accept-Encoding": "gzip, deflate, br",
# Strongly recommended
"Connection": "keep-alive",
"Upgrade-Insecure-Requests": "1",
# Sec-Fetch headers (modern Chrome)
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "none",
"Sec-Fetch-User": "?1",
# Recommended for consistency
"Sec-Ch-Ua": '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
"Sec-Ch-Ua-Mobile": "?0",
"Sec-Ch-Ua-Platform": '"Windows"',
}
Ngược lại, các header sau gần như chắc chắn kích hoạt chặn:
User-Agent: python-requests/2.31.0— định danh thư viện HTTP đã biết.User-Agent: curl/7.81.0— định danh công cụ CLI.- Thiếu header
Accept— trình duyệt thật luôn gửi Accept. - Thiếu
Accept-Language— mọi trình duyệt đều gửi header này. User-Agent: ""(rỗng) — không hợp lệ, lộ rõ automation.User-Agent: Googlebot/2.1từ IP không thuộc Google — giả danh bot đã biết.
Khắc phục sự cố thường gặp
- 403 với header tối giản, 200 với header trình duyệt: chỉ là BIC — dùng header giống trình duyệt thật.
- 403 với mọi tổ hợp header: IP bị chặn hoặc dính rule WAF — đổi IP hoặc proxy khác.
- 503 kèm trang thử thách: thử thách CAPTCHA, không phải BIC — dùng CaptchaAI.
- 403 xuất hiện ngắt quãng: rate limit hoặc theo phiên — giảm tần suất request, giữ phiên ổn định.
- Header đã đúng nhưng vẫn 403: kiểm tra fingerprint TLS (JA3) — dùng
curl_cffihoặc trình duyệt thật.
Câu hỏi thường gặp
Sự khác biệt cốt lõi giữa BIC và thử thách CAPTCHA của Cloudflare là gì?
BIC là kiểm tra thụ động ở tầng header, trả về 403 mà không đưa ra thứ gì để giải — sửa header là xong. Thử thách CAPTCHA (Turnstile, Cloudflare Challenge) trả về 503 kèm một tác vụ thật sự cần giải, và đó là phần CaptchaAI xử lý.
Có thể tắt BIC cho website của mình không?
Có. Người vận hành site tắt được BIC trong Cloudflare dashboard, mục Security > Settings. BIC bật mặc định trên mọi gói Cloudflare, kể cả gói miễn phí.
Làm sao biết chắc mình đang gặp BIC chứ không phải rate limit hay bị chặn IP?
Đổi header sang bộ header giống trình duyệt thật rồi gửi lại cùng một request. Nếu 403 biến mất, đó là BIC. Nếu vẫn 403 dù header đã đúng chuẩn, nhiều khả năng là chặn IP hoặc rate limit theo phiên — hai lỗi này header không sửa được.
CaptchaAI có xử lý được BIC không?
Không — BIC không đưa ra thử thách nào để giải, nên CaptchaAI không có việc để làm ở bước này. Sửa header HTTP là đủ để qua BIC. CaptchaAI chỉ vào việc khi Cloudflare chuyển sang Turnstile hoặc Cloudflare Challenge sau khi BIC đã qua.
Team QA/automation ở Việt Nam nên tổ chức debug lỗi 403/503 Cloudflare thế nào?
Log riêng status code theo domain thay vì gộp chung. 403 xuất hiện hàng loạt trên nhiều domain thường là lỗi header ở tầng proxy pool — sửa được, không cần CaptchaAI. 503 xuất hiện rải rác thường do rule WAF hoặc bot-score, cần CaptchaAI giải Turnstile hoặc Cloudflare Challenge. Tách hai luồng debug này giúp team không tốn thời gian sửa sai chỗ khi chạy QA hoặc scraping trên nhiều site cùng lúc.
Tóm tắt
BIC của Cloudflare chặn request có header rõ ràng không phải trình duyệt (403); thử thách CAPTCHA đưa ra tác vụ giải được (503). Sửa header giống trình duyệt thật là đủ cho BIC — không cần CaptchaAI. Thử thách CAPTCHA (Turnstile, Cloudflare Challenge) thì cần CaptchaAI để giải. Luôn chẩn đoán đúng loại chặn trước: sửa header cho BIC, dùng CaptchaAI cho CAPTCHA, đổi IP cho chặn cứng.