Phân Tích Kỹ Thuật

Cơ chế gọi lại reCAPTCHA v2: Cách hoạt động của lệnh gọi lại và cách kích hoạt chúng

Khi người dùng hoàn thành thử thách reCAPTCHA v2, Google sẽ gọi hàm gọi lại JavaScript do trang web xác định. Cuộc gọi lại này thường kích hoạt nút gửi, xác thực biểu mẫu hoặc gửi yêu cầu AJAX. Sau khi đưa mã thông báo đã giải quyết từ CaptchaAI, bạn cần kích hoạt lệnh gọi lại tương tự — nếu không biểu mẫu sẽ không nhận ra rằng CAPTCHA đã được giải quyết.


Cách gọi lại hoạt động

Trang web xác định lệnh gọi lại trong tiện ích reCAPTCHA:

<div class="g-recaptcha"
     data-sitekey="6Le-SITEKEY"
     data-callback="onCaptchaSuccess"
     data-expired-callback="onCaptchaExpired">
</div>

<script>
function onCaptchaSuccess(token) {
  document.getElementById('submit-btn').disabled = false;
  document.getElementById('captcha-token').value = token;
}
</script>

Khi người dùng giải CAPTCHA, JavaScript của Google sẽ gọi onCaptchaSuccess(token). Hàm nhận chuỗi mã thông báo làm đối số duy nhất của nó.


Tìm chức năng gọi lại

Cách 1: Kiểm tra thuộc tính data-callback

// In browser console
const widget = document.querySelector('.g-recaptcha');
const callbackName = widget?.getAttribute('data-callback');
console.log('Callback:', callbackName);

Cách 2: Kiểm tra nội bộ grecaptcha

Một số trang web sử dụng grecaptcha.render() với tùy chọn gọi lại thay vì thuộc tính data-callback:

// Search page source for grecaptcha.render
document.querySelectorAll('script:not([src])').forEach(s => {
  if (s.textContent.includes('grecaptcha.render')) {
    console.log(s.textContent.match(/callback\s*:\s*(\w+)/)?.[1]);
  }
});

Cách 3: Chặn đăng ký gọi lại

Chạy phần này trong DevTools trước khi tải trang (Nguồn → Snippets):

const origRender = grecaptcha.render;
grecaptcha.render = function(container, params) {
  console.log('Render callback:', params.callback);
  console.log('Expired callback:', params['expired-callback']);
  return origRender.apply(this, arguments);
};

Kích hoạt lệnh gọi lại sau khi chèn mã thông báo

Python (Selen)

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

API_KEY = "YOUR_API_KEY"
driver = webdriver.Chrome()
driver.get("https://staging.example.com/qa-login")

# Extract sitekey and callback
sitekey = driver.find_element(
    By.CSS_SELECTOR, ".g-recaptcha"
).get_attribute("data-sitekey")

callback = driver.find_element(
    By.CSS_SELECTOR, ".g-recaptcha"
).get_attribute("data-callback")

# Solve with CaptchaAI
resp = requests.post("https://ocr.captchaai.com/in.php", data={
    "key": API_KEY,
    "method": "userrecaptcha",
    "googlekey": sitekey,
    "pageurl": driver.current_url,
    "json": "1",
}).json()
task_id = resp["request"]

token = None
for _ in range(24):
    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["status"] == 1:
        token = result["request"]
        break

# Inject token into textarea
driver.execute_script("""
    document.querySelector('textarea[name="g-recaptcha-response"]').value = arguments[0];
""", token)

# Trigger the callback
if callback:
    driver.execute_script(f"window['{callback}'](arguments[0]);", token)
    print(f"Triggered callback: {callback}")
else:
    # Fallback: try ___grecaptcha_cfg
    driver.execute_script("""
        try {
            var widgetId = Object.keys(___grecaptcha_cfg.clients)[0];
            var callback = ___grecaptcha_cfg.clients[widgetId].aa.l.callback;
            if (typeof callback === 'function') callback(arguments[0]);
        } catch(e) {}
    """, token)
    print("Triggered callback via ___grecaptcha_cfg")

JavaScript (Puppeteer)

const puppeteer = require('puppeteer');

// After solving and getting the token...
await page.evaluate((token, callbackName) => {
  // Set textarea value
  const textarea = document.querySelector(
    'textarea[name="g-recaptcha-response"]'
  );
  textarea.value = token;
  textarea.style.display = 'block'; // sometimes hidden

  // Trigger callback
  if (callbackName && typeof window[callbackName] === 'function') {
    window[callbackName](token);
    console.log(`Called ${callbackName}()`);
  } else {
    // Fallback: search grecaptcha config
    try {
      const clients = ___grecaptcha_cfg.clients;
      const widgetId = Object.keys(clients)[0];
      const cb = clients[widgetId]?.aa?.l?.callback;
      if (typeof cb === 'function') cb(token);
    } catch (e) {}
  }
}, token, callbackName);

Các trang web không có dữ liệu gọi lại

Một số trang web không sử dụng lệnh gọi lại. Thay vào đó, họ kiểm tra grecaptcha.getResponse() khi biểu mẫu được gửi. Đối với các trang web này, hãy ghi đè chức năng:

driver.execute_script("""
    const token = arguments[0];
    document.querySelector('textarea[name="g-recaptcha-response"]').value = token;
    // Override getResponse to return the token
    if (typeof grecaptcha !== 'undefined') {
        grecaptcha.getResponse = function() { return token; };
    }
""", token)

# Then submit the form normally
driver.find_element(By.CSS_SELECTOR, "form").submit()

Cuộc gọi lại đã hết hạn

Một số trang web xác định data-expired-callback để tắt nút gửi khi mã thông báo hết hạn. Nếu mã thông báo của bạn sắp hết hạn, lệnh gọi lại này có thể kích hoạt và khóa lại biểu mẫu. Giải quyết gần thời gian nộp bài để tránh điều này.

// Check for expired callback
const expiredCallback = document.querySelector('.g-recaptcha')
  ?.getAttribute('data-expired-callback');
console.log('Expired callback:', expiredCallback);

Khắc phục sự cố

Vấn đề Nguyên nhân Cách xử lý
Biểu mẫu vẫn bị vô hiệu hóa sau khi tiêm Cuộc gọi lại không được kích hoạt Tìm và gọi hàm gọi lại
ReferenceError: function not defined Gọi lại được xác định trong một bao đóng Sử dụng dự phòng ___grecaptcha_cfg
Đã chèn mã thông báo nhưng AJAX không được gửi Gọi lại kích hoạt AJAX, không gửi biểu mẫu Kiểm tra chức năng gọi lại làm gì
Mã thông báo được chấp nhận nhưng trang hiển thị lỗi Mã thông báo đã hết hạn trước khi gọi lại Giải quyết gần thời gian nộp bài

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

Điều gì sẽ xảy ra nếu không có cuộc gọi lại nào cả?

Một số trang web chỉ kiểm tra mã thông báo ở phía máy chủ khi biểu mẫu được gửi. Trong trường hợp đó, chỉ cần đặt giá trị vùng văn bản g-recaptcha-response và gửi biểu mẫu là đủ.

Tên hàm gọi lại có thể thay đổi giữa các lần tải trang không?

Có, trên một số trang web. Luôn trích xuất tên gọi lại một cách linh hoạt từ DOM thay vì mã hóa cứng nó.

reCAPTCHA v3 có sử dụng cơ chế gọi lại tương tự không?

Không. reCAPTCHA v3 sử dụng grecaptcha.execute() để trả về Lời hứa. Không có tiện ích hiển thị hoặc thuộc tính data-callback.


Giải quyết reCAPTCHA v2 bằng cách xử lý gọi lại thích hợp bằng CaptchaAI

Nhận khóa API của bạn tạicaptchaai.com.


Hướng dẫn liên quan

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