Khắc Phục Sự Cố

Xử lý reCAPTCHA v2 và v3 trên cùng một trang

Một số trang web triển khai cả reCAPTCHA v2 và v3 trên cùng một trang. Mẫu điển hình là: v3 chạy ẩn ở chế độ nền và nếu điểm quá thấp, v2 sẽ xuất hiện dưới dạng thử thách dự phòng rõ ràng. Việc triển khai kép này tạo ra sự nhầm lẫn cho quá trình tự động hóa vì bạn cần xử lý hai loại CAPTCHA khác nhau bằng các phương pháp giải khác nhau. Hướng dẫn này bao gồm các chiến lược phát hiện, giải quyết và các trường hợp khó khăn phổ biến.


Tại sao các trang web sử dụng cả v2 và v3 cùng nhau

User visits page
    ↓
reCAPTCHA v3 runs invisibly in background
    ↓
Score returned to server (e.g., 0.4)
    ↓
Score below threshold (e.g., < 0.7)?
    ├─ YES → Show reCAPTCHA v2 checkbox/image challenge
    └─ NO  → Allow action without visible CAPTCHA

Mẫu này cung cấp tốt nhất của cả hai thế giới:

  • Hầu hết người dùng (điểm v3 cao) không thấy CAPTCHA → ít ma sát
  • Người dùng đáng ngờ (điểm v3 thấp) xem thử thách v2 Dự phòng bảo mật →
  • Nhà điều hành trang web kiểm soát ngưỡng giữa ẩn và hiển thị

Các mẫu triển khai kép

Mẫu 1: Đánh giá trước v3 + dự phòng v2

Mẫu phổ biến nhất. v3 chạy trước và v2 chỉ xuất hiện nếu cần.

<!-- Both scripts loaded -->
<script src="https://www.google.com/recaptcha/api.js?render=V3_SITE_KEY"></script>
<script src="https://www.google.com/recaptcha/api.js?render=explicit" async defer></script>

<form id="loginForm">
    <!-- v2 widget (hidden initially) -->
    <div id="recaptcha-v2-container" style="display:none;">
        <div class="g-recaptcha" data-sitekey="V2_SITE_KEY"></div>
    </div>
    <button type="submit">Login</button>
</form>

<script>
// First attempt: v3 invisible
grecaptcha.ready(function() {
    grecaptcha.execute('V3_SITE_KEY', {action: 'login'}).then(function(v3Token) {
        fetch('/api/verify-v3', {
            method: 'POST',
            body: JSON.stringify({token: v3Token})
        })
        .then(r => r.json())
        .then(data => {
            if (data.score < 0.7) {
                // Score too low → show v2 fallback
                document.getElementById('recaptcha-v2-container').style.display = 'block';
                grecaptcha.render('recaptcha-v2-container', {sitekey: 'V2_SITE_KEY'});
            } else {
                // Score OK → submit form directly
                document.getElementById('loginForm').submit();
            }
        });
    });
});
</script>

Mẫu 2: Các khóa trang web khác nhau cho các hành động khác nhau

Một số trang web sử dụng v3 để giám sát thụ động và v2 cho các hành động có rủi ro cao cụ thể:

Homepage → v3 only (passive score)
Login page → v3 assessment, v2 fallback
Checkout → v2 always (high security)
Contact form → v3 only

Mẫu 3: Chữ đơn, chế độ kép

Google hỗ trợ tải một tập lệnh reCAPTCHA duy nhất xử lý cả v2 và v3:

<script src="https://www.google.com/recaptcha/api.js?render=V3_SITE_KEY"></script>
<script>
    // v3 execute
    grecaptcha.execute('V3_SITE_KEY', {action: 'login'});

    // v2 render (uses a different site key)
    grecaptcha.render('v2-container', {sitekey: 'V2_SITE_KEY'});
</script>

Phát hiện triển khai kép

Phát hiện Python

import requests
import re

def detect_dual_recaptcha(url):
    """Detect if a page uses both reCAPTCHA v2 and v3."""
    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",
    }
    html = requests.get(url, headers=headers, timeout=15).text

    result = {
        "has_v3": False,
        "has_v2": False,
        "v3_site_key": None,
        "v2_site_key": None,
        "dual": False,
        "pattern": None,
    }

    # Detect v3 (render parameter or enterprise.execute)
    v3_match = re.search(r"api\.js\?render=([A-Za-z0-9_-]+)", html)
    if v3_match and v3_match.group(1) != "explicit":
        result["has_v3"] = True
        result["v3_site_key"] = v3_match.group(1)

    # Detect v3 in execute calls
    v3_execute = re.search(
        r"grecaptcha\.(?:enterprise\.)?execute\s*\(\s*['\"]([^'\"]+)['\"]",
        html,
    )
    if v3_execute:
        result["has_v3"] = True
        if not result["v3_site_key"]:
            result["v3_site_key"] = v3_execute.group(1)

    # Detect v2 (g-recaptcha class or explicit render)
    v2_match = re.search(r'data-sitekey="([^"]+)"', html)
    if v2_match:
        key = v2_match.group(1)
        if key != result.get("v3_site_key"):
            result["has_v2"] = True
            result["v2_site_key"] = key

    # Check for explicit v2 render
    v2_render = re.search(
        r"grecaptcha\.render\s*\([^,]+,\s*\{[^}]*sitekey:\s*['\"]([^'\"]+)",
        html,
    )
    if v2_render:
        result["has_v2"] = True
        if not result["v2_site_key"]:
            result["v2_site_key"] = v2_render.group(1)

    result["dual"] = result["has_v3"] and result["has_v2"]

    if result["dual"]:
        # Determine pattern
        if "display:none" in html or "display: none" in html:
            result["pattern"] = "v3_pre_assessment_v2_fallback"
        else:
            result["pattern"] = "v2_v3_simultaneous"

    return result

detection = detect_dual_recaptcha("https://staging.example.com/qa-login")
print(detection)

Phát hiện Node.js

const axios = require("axios");

async function detectDualRecaptcha(url) {
    const { data: html } = await axios.get(url, { timeout: 15000 });

    const result = {
        hasV3: false,
        hasV2: false,
        v3SiteKey: null,
        v2SiteKey: null,
        dual: false,
    };

    // v3 detection
    const v3Match = html.match(/api\.js\?render=([A-Za-z0-9_-]+)/);
    if (v3Match && v3Match[1] !== "explicit") {
        result.hasV3 = true;
        result.v3SiteKey = v3Match[1];
    }

    // v2 detection
    const v2Match = html.match(/data-sitekey="([^"]+)"/);
    if (v2Match && v2Match[1] !== result.v3SiteKey) {
        result.hasV2 = true;
        result.v2SiteKey = v2Match[1];
    }

    result.dual = result.hasV3 && result.hasV2;
    return result;
}

detectDualRecaptcha("https://staging.example.com/qa-login").then(console.log);

Giải quyết các chiến lược cho reCAPTCHA kép

Chiến lược 1: Giải v3 trước, sau đó đến v2 nếu cần

Chiến lược tối ưu phản ánh dòng chảy riêng của trang web:

import requests
import time

API_KEY = "YOUR_API_KEY"

def solve_v3(site_key, page_url, action="login"):
    """Solve reCAPTCHA v3 and return token."""
    submit = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY,
        "method": "userrecaptcha",
        "googlekey": site_key,
        "pageurl": page_url,
        "version": "v3",
        "action": action,
        "json": 1,
    }).json()

    task_id = submit["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("v3 solve timeout")

def solve_v2(site_key, page_url):
    """Solve reCAPTCHA v2 and return token."""
    submit = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY,
        "method": "userrecaptcha",
        "googlekey": site_key,
        "pageurl": page_url,
        "json": 1,
    }).json()

    task_id = submit["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("v2 solve timeout")

def solve_dual_recaptcha(v3_key, v2_key, page_url, action="login"):
    """Handle dual reCAPTCHA: try v3, fall back to v2."""
    # Step 1: Try v3
    v3_token = solve_v3(v3_key, page_url, action)

    # Step 2: Submit v3 token to target
    response = requests.post(f"{page_url}/verify", data={
        "g-recaptcha-response": v3_token,
    })

    # Step 3: Check if v2 fallback is needed
    if "recaptcha" in response.text.lower() and v2_key:
        print("v3 score too low — v2 fallback triggered")
        v2_token = solve_v2(v2_key, page_url)
        return {"version": "v2", "token": v2_token}

    return {"version": "v3", "token": v3_token}

result = solve_dual_recaptcha(
    v3_key="6LcExample_v3_key",
    v2_key="6LcExample_v2_key",
    page_url="https://staging.example.com/qa-login",
)
print(f"Solved with {result['version']}")

Cách 2: Bỏ v3, giải trực tiếp v2

Nếu bạn biết trang web luôn hiển thị v2 cho lưu lượng truy cập tự động (điểm v3 sẽ thấp), hãy bỏ qua v3 và giải quyết v2 ngay lập tức:

# If you consistently fail v3 assessment, just solve v2 directly
token = solve_v2(v2_site_key, page_url)
submit_form(token)

Điều này giúp tiết kiệm thời gian và chi phí cho việc giải quyết v3 có thể không vượt qua ngưỡng.

Chiến lược 3: Xử lý dựa trên trình duyệt

Đối với các hoạt động triển khai phức tạp, hãy sử dụng trình duyệt để xử lý luồng dự phòng:

from selenium import webdriver
from selenium.webdriver.common.by import By
import time

driver = webdriver.Chrome()
driver.get("https://staging.example.com/qa-login")
time.sleep(3)

# Check if v2 widget is visible
v2_visible = driver.execute_script("""
    const container = document.querySelector('.g-recaptcha');
    if (!container) return false;
    const style = window.getComputedStyle(container.parentElement);
    return style.display !== 'none' && style.visibility !== 'hidden';
""")

if v2_visible:
    # v2 is showing — solve v2
    sitekey = driver.find_element(
        By.CSS_SELECTOR, "[data-sitekey]"
    ).get_attribute("data-sitekey")
    token = solve_v2(sitekey, driver.current_url)
    driver.execute_script(
        f'document.getElementById("g-recaptcha-response").value = "{token}";'
    )
else:
    # v3 only — solve v3
    # Extract v3 key from page source
    v3_key = driver.execute_script(
        "return document.querySelector('script[src*=\"render=\"]')"
        ".src.match(/render=([^&]+)/)[1];"
    )
    token = solve_v3(v3_key, driver.current_url)
    # Inject v3 token into the form
    driver.execute_script(f"""
        const input = document.createElement('input');
        input.type = 'hidden';
        input.name = 'g-recaptcha-response';
        input.value = '{token}';
        document.querySelector('form').appendChild(input);
    """)

driver.find_element(By.CSS_SELECTOR, "form").submit()

Vỏ cạnh

Hai khóa trang web khác nhau trên cùng một trang

Các trang web sử dụng reCAPTCHA kép sẽ có HAI khóa trang web khác nhau - một cho v3 và một cho v2. Khóa v3 xuất hiện trong URL tập lệnh ?render=KEY và trong grecaptcha.execute('KEY', ...). Khóa v2 xuất hiện trong data-sitekey="KEY" trên div tiện ích. Sử dụng sai key cho phiên bản sai sẽ tạo ra token không hợp lệ.

reCAPTCHA Enterprise với dự phòng v2

Một số triển khai Enterprise sử dụng v3 Enterprise để tính điểm và v2 cho các thử thách:

# Detect and handle Enterprise + v2 combo
if "recaptcha/enterprise.js" in html:
    # Use enterprise parameter for v3
    v3_params = {"enterprise": 1, "version": "v3"}
else:
    v3_params = {"version": "v3"}

Nhiều biểu mẫu trên một trang

Nếu một trang có nhiều biểu mẫu (đăng nhập + đăng ký), mỗi biểu mẫu có thể có phiên bản reCAPTCHA riêng. Trích xuất khóa trang web từ biểu mẫu cụ thể mà bạn đang nhắm mục tiêu:

# Target the login form specifically
login_form = soup.find("form", id="login-form")
widget = login_form.find(attrs={"data-sitekey": True})
sitekey = widget["data-sitekey"]

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

Tôi có cần giải cả v2 và v3 trên cùng một trang không?

Không. Thông thường, bạn giải v3 trước (nó chạy tự động). Nếu điểm v3 vượt qua ngưỡng của trang web, không có thử thách v2 nào xuất hiện và bạn đã hoàn thành. Bạn chỉ cần giải v2 nếu điểm v3 kích hoạt dự phòng.

Tôi có thể sử dụng một lệnh gọi API CaptchaAI cho reCAPTCHA kép không?

Số v2 và v3 là các loại CAPTCHA riêng biệt với các khóa trang web và phương pháp giải khác nhau. Mỗi yêu cầu lệnh gọi API riêng tới CaptchaAI. Tuy nhiên, bạn chỉ cần thực hiện một cuộc gọi nếu v3 vượt qua mà không kích hoạt v2.

Làm cách nào để biết liệu dự phòng v2 có được kích hoạt hay không?

Kiểm tra phản hồi của máy chủ sau khi gửi mã thông báo v3. Nếu phản hồi chứa HTML tiện ích v2 hoặc kích hoạt thử thách v2 (chuyển hướng hoặc phản hồi AJAX bằng HTML CAPTCHA), thì dự phòng đã được kích hoạt. Trong trình duyệt, hãy kiểm tra xem vùng chứa v2 có hiển thị sau khi gửi v3 hay không.

Tôi sử dụng khóa trang web nào cho mỗi phiên bản?

Khóa trang v3 nằm trong URL tập lệnh: api.js?render=V3_KEY. Khóa trang web v2 có trong tiện ích HTML: data-sitekey="V2_KEY". Chúng luôn là những chìa khóa khác nhau.


Tóm tắt

Việc triển khai reCAPTCHA kép sử dụng v3 để đánh giá trước vô hình và v2 làm dự phòng rõ ràng khi điểm v3 quá thấp. Phát hiện cả hai phiên bản bằng cách kiểm tra tham số kết xuất (v3) và widget data-sitekey (v2). Chiến lược tự động hóa tối ưu là: giải v3 trước bằngCaptchaAI, gửi mã thông báo và chỉ giải quyết v2 nếu kích hoạt dự phòng. Mỗi phiên bản yêu cầu một lệnh gọi API riêng với khóa trang web riêng.

bài viết liên quan

  • Ứng dụng trang đơn Recaptcha động
  • Cách giải quyết cuộc gọi lại Recaptcha V2 bằng Api
  • Xử lý cửa quay Recaptcha V2 trên cùng một trang web
Os comentários estão desativados para este artigo.