Phân Tích Kỹ Thuật

Quy trình phản hồi thử thách của GeeTest v3: Nghiên cứu sâu về kỹ thuật

GeeTest v3 không dùng một token duy nhất như reCAPTCHA — nó xâu chuỗi ba nhóm giá trị: gt (định danh trang), challenge (token phiên dùng một lần) và bộ ba geetest_challenge / geetest_validate / geetest_seccode sinh ra sau khi người dùng giải xong. Sai thứ tự lấy — dùng — nộp các giá trị này, hoặc dùng challenge đã hết hạn, là lý do phổ biến nhất khiến request tới CaptchaAI bị từ chối. Bài viết đi qua từng bước của quy trình phản hồi thử thách GeeTest v3, kèm code Python trích xuất tham số và request thực tế gửi tới CaptchaAI.

GeeTest v3 hoạt động qua hai giai đoạn phản hồi thử thách

Toàn bộ quy trình chia làm hai giai đoạn tách biệt — một giai đoạn chạy ở server của trang web, một giai đoạn chạy trên trình duyệt của người dùng:

Giai đoạn 1 — đăng ký thử thách ở phía server

Backend của trang web liên hệ GeeTest để xin một thử thách mới cho phiên hiện tại:

Site Backend → GeeTest Server: "Give me a challenge for this user"
GeeTest Server → Site Backend: { gt, challenge, new_captcha }
Site Backend → Browser: Passes gt and challenge to the page

Giai đoạn 2 — người dùng giải, server xác minh

Trình duyệt hiển thị thử thách bằng gtchallenge nhận được, người dùng thao tác (kéo thanh trượt, bấm icon…), rồi kết quả được gửi ngược về server để xác minh với GeeTest:

Browser: Renders slider/puzzle using gt + challenge
User: Solves the challenge
Browser → Site Backend: { geetest_challenge, geetest_validate, geetest_seccode }
Site Backend → GeeTest Server: Verifies the three values
GeeTest Server → Site Backend: { result: "success" }

GeeTest online và offline khác nhau thế nào

GeeTest v3 có chế độ dự phòng khi không kết nối được máy chủ GeeTest:

  • Trực tuyến (success = 1) — phản hồi thử thách thông thường với máy chủ GeeTest.
  • Ngoại tuyến (success = 0) — xác minh cục bộ, đơn giản hoá, thử thách tạo ngay trên trình duyệt.

Phần lớn trang production dùng chế độ trực tuyến, nên các ví dụ dưới đây theo luồng đó.

Dưới đây là năm bước của quy trình phản hồi thử thách GeeTest v3 ở chế độ trực tuyến, từ lúc trang load tới lúc server xác nhận kết quả.

Bước 1 — gọi API đăng ký lấy gt và challenge

Backend gọi endpoint đăng ký của GeeTest:

GET https://api.geetest.com/register.php?gt=GT_ID&json_format=1

Kết quả trả về:

{
  "success": 1,
  "gt": "81dc9bdb52d04dc20036dbd8313ed055",
  "challenge": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
  "new_captcha": true
}

Ý nghĩa từng tham số:

  • gt — GeeTest ID, định danh tài khoản GeeTest của trang web.
  • challenge — token thử thách, chỉ dùng cho phiên này.
  • new_captcha — có dùng định dạng CAPTCHA mới hay không.

Lưu ý: giá trị challenge chỉ dùng được một lần và có thời hạn. Mỗi lần trang được tải lại, GeeTest sinh ra một challenge mới.

Bước 2 — trình duyệt render widget GeeTest

Trang nhận gtchallenge, rồi khởi tạo widget:

initGeetest({
  gt: "81dc9bdb52d04dc20036dbd8313ed055",
  challenge: "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
  offline: false,
  new_captcha: true,
  product: "float"
}, function(captchaObj) {
  captchaObj.appendTo('#captcha-container');
  captchaObj.onSuccess(function() {
    var result = captchaObj.getValidate();
    // result contains: geetest_challenge, geetest_validate, geetest_seccode
  });
});

Bước 3 — GeeTest chọn loại thử thách nào

GeeTest v3 có nhiều dạng thử thách, và trang web không tự chọn — GeeTest quyết định dựa trên cấu hình trang và hồ sơ rủi ro của người dùng:

Bốn dạng thử thách GeeTest v3 có thể hiển thị:

  • Thanh trượt — kéo mảnh ghép để khớp đúng vị trí trong ảnh.
  • Nhấp icon — bấm các biểu tượng đúng thứ tự hiển thị.
  • Nhấp chữ — bấm ký tự tiếng Trung theo đúng thứ tự.
  • Không gian — thử thách suy luận không gian, bấm/chọn theo yêu cầu.

Với CaptchaAI, loại thử thách không ảnh hưởng cách gửi request — luôn nộp cùng gtchallenge.

Bước 4 — ba giá trị trả về sau khi giải

Sau khi người dùng hoàn thành thử thách, widget sinh ra ba giá trị:

{
  "geetest_challenge": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6xy",
  "geetest_validate": "abc123def456_validate",
  "geetest_seccode": "abc123def456_validate|jordan"
}
  • geetest_challenge — token thử thách đã biến đổi (bản gốc cộng thêm 2 ký tự).
  • geetest_validate — hash xác thực.
  • geetest_seccode — mã bảo mật (validate cộng hậu tố \|jordan).

Bước 5 — server gửi kết quả cho GeeTest xác minh

Backend gửi cả ba giá trị này cho GeeTest để xác nhận:

POST https://api.geetest.com/validate.php

seccode=abc123def456_validate|jordan
&challenge=a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6xy
&sdk=geetest-python-3.0.0

GeeTest phản hồi:

{
  "seccode": "abc123def456_validate",
  "validate": "abc123def456_validate"
}

Để CaptchaAI giải thử thách thay bạn, bạn phải tự lấy gtchallenge từ trang trước khi gọi API — có ba cách phổ biến để lấy hai giá trị này.

Ví dụ thực tế: một đội QA automation tại công ty outsourcing ở TP.HCM kiểm thử luồng đăng nhập được bảo vệ bởi GeeTest v3 slider trên staging trước khi release. Thay vì giải thủ công mỗi lần chạy CI, họ dùng Playwright chặn response đăng ký, lấy gt/challenge, rồi gửi cho CaptchaAI — pipeline end-to-end chạy tự động, không cần người ngồi giải captcha.

Cách 1 — bắt response của request đăng ký

from playwright.sync_api import sync_playwright
import json

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page()

    geetest_params = {}

    def handle_response(response):
        if "register" in response.url and "geetest" in response.url:
            data = response.json()
            geetest_params["gt"] = data.get("gt")
            geetest_params["challenge"] = data.get("challenge")

    page.on("response", handle_response)
    page.goto("https://staging.example.com/qa-login")

    # Wait for GeeTest to load
    page.wait_for_selector(".geetest_holder")
    print(f"gt: {geetest_params.get('gt')}")
    print(f"challenge: {geetest_params.get('challenge')}")

Cách 2 — đọc trực tiếp từ DOM

Nếu trang lưu gt/challenge trong thuộc tính data-*, đọc thẳng bằng JavaScript evaluate:

gt = page.evaluate("() => document.querySelector('[data-gt]')?.dataset.gt")
challenge = page.evaluate("() => document.querySelector('[data-challenge]')?.dataset.challenge")

Cách 3 — tìm trong lệnh gọi initGeetest

Khi hai cách trên không khả dụng, tìm trực tiếp trong mã nguồn trang, nơi initGeetest được gọi:

import re
source = page.content()
gt_match = re.search(r"gt['\"]?\s*[:=]\s*['\"]([a-f0-9]{32})['\"]", source)
challenge_match = re.search(r"challenge['\"]?\s*[:=]\s*['\"]([a-f0-9]{32})['\"]", source)

Gửi gt và challenge tới CaptchaAI để lấy seccode

Với gtchallenge đã có, gửi task tới CaptchaAI:

POST https://ocr.captchaai.com/in.php

key=YOUR_API_KEY
&method=geetest
&gt=81dc9bdb52d04dc20036dbd8313ed055
&challenge=a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
&pageurl=https://staging.example.com/qa-login
&json=1

Polling kết quả:

GET https://ocr.captchaai.com/res.php?key=YOUR_API_KEY&action=get&id=TASK_ID&json=1

CaptchaAI trả về:

{
  "status": 1,
  "request": {
    "geetest_challenge": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6xy",
    "geetest_validate": "abc123def456_validate",
    "geetest_seccode": "abc123def456_validate|jordan"
  }
}

Ba giá trị này — geetest_challenge, geetest_validate, geetest_seccode — chính là những gì bước xác minh phía server của trang web cần, y hệt như khi người dùng tự giải.

Các lỗi thường gặp khi tích hợp GeeTest v3

  • challenge rỗng — bước đăng ký thất bại; kiểm tra xem trang có load GeeTest đúng cách không.
  • Giải pháp bị từ chốichallenge đã hết hạn; lấy challenge mới và giải ngay, không trì hoãn.
  • Sai giá trị gt — trang có nhiều widget GeeTest; trích xuất gt từ đúng widget đang hiển thị.
  • Trả đủ ba giá trị nhưng form không submit — thiếu trường input trên form; điền cả ba giá trị vào đúng input tương ứng.

Câu hỏi thường gặp về GeeTest v3

CaptchaAI có hỗ trợ giải GeeTest v4 không?

Chưa. CaptchaAI hiện chỉ hỗ trợ GeeTest v3 (method=geetest); GeeTest v4 đang sắp ra mắt, chưa có ngày phát hành chính thức.

Nên trích xuất gt và challenge vào thời điểm nào trong pipeline automation?

Ngay sau khi widget GeeTest render xong, thường là lúc selector .geetest_holder xuất hiện. Trích xuất càng sớm càng tốt vì challenge có thời hạn ngắn, chỉ khoảng 1–2 phút.

Loại thử thách (thanh trượt, icon, chữ Hán) có làm thay đổi cách gọi CaptchaAI không?

Không. Dù GeeTest hiển thị thanh trượt, icon hay chữ Hán, bạn luôn gửi cùng cặp gt/challenge tới in.php với method=geetest.

Vì sao request gửi tới CaptchaAI báo challenge không hợp lệ dù vừa lấy xong?

Nhiều khả năng challenge đã bị dùng hoặc hết hạn — mỗi challenge chỉ giải được một lần, thường hết hạn sau 1–2 phút. Lấy challenge mới ngay trước khi gửi, đừng cache lại để dùng nhiều lần.

Bài viết liên quan

Bước tiếp theo với CaptchaAI

Đã hiểu rõ luồng gt/challenge/seccode — lấy API key CaptchaAI và đưa bộ ba giá trị này vào pipeline automation của bạn.

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