Hướng Dẫn Thực Hành

Giải quyết cửa quay Cloudflare bằng Node.js và CaptchaAI

Cloudflare Turnstile đang thay thế reCAPTCHA trên nhiều trang web. Hướng dẫn này trình bày toàn bộ quy trình Node.js: phát hiện Turnstile, trích xuất khóa trang web, giải quyết thông qua CaptchaAI và gửi mã thông báo.


Điều kiện tiên quyết

  • Node.js 18+ (tìm nạp gốc)
  • Khóa API CaptchaAI

Bước 1: Phát hiện và trích xuất sitekey

async function extractTurnstileSitekey(url) {
  const resp = await fetch(url, {
    headers: {
      "User-Agent":
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36",
    },
  });
  const html = await resp.text();

  // Method 1: data-sitekey attribute on Turnstile div
  const divMatch = html.match(
    /class=["'][^"]*cf-turnstile[^"]*["'][^>]*data-sitekey=["']([0-9x][A-Za-z0-9_-]+)["']/
  );
  if (divMatch) return divMatch[1];

  // Method 2: data-sitekey on any element (Turnstile keys start with 0x)
  const attrMatch = html.match(
    /data-sitekey=["'](0x[A-Za-z0-9_-]+)["']/
  );
  if (attrMatch) return attrMatch[1];

  // Method 3: In JavaScript turnstile.render call
  const jsMatch = html.match(
    /turnstile\.render\s*\([^,]+,\s*\{[^}]*sitekey\s*:\s*["']([0-9x][A-Za-z0-9_-]+)["']/
  );
  if (jsMatch) return jsMatch[1];

  // Method 4: Generic sitekey in inline script
  const inlineMatch = html.match(
    /sitekey\s*:\s*["'](0x[A-Za-z0-9_-]+)["']/
  );
  if (inlineMatch) return inlineMatch[1];

  return null;
}

Bước 2: Giải quyết Turnstile qua CaptchaAI

const API_KEY = "YOUR_API_KEY";

function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

async function solveTurnstile(sitekey, pageurl, action = null) {
  // Submit task
  const submitData = {
    key: API_KEY,
    method: "turnstile",
    sitekey: sitekey,
    pageurl: pageurl,
    json: "1",
  };

  if (action) {
    submitData.action = action;
  }

  const submitResp = await fetch("https://ocr.captchaai.com/in.php", {
    method: "POST",
    body: new URLSearchParams(submitData),
  });
  const submitResult = await submitResp.json();

  if (submitResult.status !== 1) {
    throw new Error(`Submit error: ${submitResult.request}`);
  }

  const taskId = submitResult.request;
  console.log(`Task ID: ${taskId}`);

  // Poll for result
  for (let i = 0; i < 30; i++) {
    await sleep(5000);

    const pollResp = await fetch(
      `https://ocr.captchaai.com/res.php?${new URLSearchParams({
        key: API_KEY,
        action: "get",
        id: taskId,
        json: "1",
      })}`
    );
    const pollResult = await pollResp.json();

    if (pollResult.status === 1) {
      return pollResult.request;
    }

    if (pollResult.request === "ERROR_CAPTCHA_UNSOLVABLE") {
      throw new Error("Turnstile unsolvable");
    }
  }

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

Bước 3: Gửi mã thông báo

async function submitTurnstileForm(url, formData, token) {
  const body = new URLSearchParams({
    ...formData,
    "cf-turnstile-response": token,
  });

  const resp = await fetch(url, {
    method: "POST",
    headers: {
      "Content-Type": "application/x-www-form-urlencoded",
      "User-Agent":
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36",
    },
    body,
  });

  return {
    status: resp.status,
    body: await resp.text(),
  };
}

Hoàn tất luồng đăng nhập

async function loginWithTurnstile(loginUrl, credentials) {
  // Step 1: Extract sitekey
  const sitekey = await extractTurnstileSitekey(loginUrl);
  if (!sitekey) {
    throw new Error("Turnstile sitekey not found");
  }
  console.log(`Sitekey: ${sitekey}`);

  // Step 2: Solve Turnstile
  const token = await solveTurnstile(sitekey, loginUrl);
  console.log(`Token: ${token.substring(0, 50)}...`);

  // Step 3: Submit form
  const result = await submitTurnstileForm(loginUrl, credentials, token);
  console.log(`Result: ${result.status}`);

  return result;
}

// Usage
const result = await loginWithTurnstile("https://staging.example.com/qa-login", {
  email: "user@example.com",
  password: "pass123",
});

Lớp giải quyết sản xuất

class TurnstileSolver {
  #apiKey;

  constructor(apiKey) {
    this.#apiKey = apiKey;
  }

  async solve(sitekey, pageurl, options = {}) {
    const taskId = await this.#submit(sitekey, pageurl, options);
    return await this.#poll(taskId);
  }

  async detectAndSolve(url) {
    const sitekey = await this.#detect(url);
    if (!sitekey) throw new Error("No Turnstile found");
    return await this.solve(sitekey, url);
  }

  async #detect(url) {
    const resp = await fetch(url, {
      headers: { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0" },
    });
    const html = await resp.text();
    const match = html.match(/data-sitekey=["'](0x[A-Za-z0-9_-]+)["']/);
    return match ? match[1] : null;
  }

  async #submit(sitekey, pageurl, options) {
    const body = new URLSearchParams({
      key: this.#apiKey,
      method: "turnstile",
      sitekey,
      pageurl,
      json: "1",
      ...(options.action && { action: options.action }),
      ...(options.cdata && { data: options.cdata }),
    });

    const resp = await fetch("https://ocr.captchaai.com/in.php", {
      method: "POST",
      body,
    });
    const data = await resp.json();

    if (data.status !== 1) throw new Error(`Submit: ${data.request}`);
    return data.request;
  }

  async #poll(taskId) {
    const params = new URLSearchParams({
      key: this.#apiKey,
      action: "get",
      id: taskId,
      json: "1",
    });

    for (let i = 0; i < 30; i++) {
      await new Promise((r) => setTimeout(r, 5000));
      const resp = await fetch(`https://ocr.captchaai.com/res.php?${params}`);
      const data = await resp.json();

      if (data.status === 1) return data.request;
      if (data.request === "ERROR_CAPTCHA_UNSOLVABLE") {
        throw new Error("Unsolvable");
      }
    }
    throw new Error("Timed out");
  }
}

// Usage
const solver = new TurnstileSolver("YOUR_API_KEY");
const token = await solver.detectAndSolve("https://staging.example.com/qa-login");

Cloudflare Turnstile với các tham số hành động và cData

Một số triển khai Turnstile bao gồm các tham số actioncData:

// Extract action from the page
function extractTurnstileAction(html) {
  const match = html.match(
    /data-action=["']([^"']+)["']|action\s*:\s*["']([^"']+)["']/
  );
  return match ? match[1] || match[2] : null;
}

// Solve with action
const token = await solver.solve(sitekey, pageurl, {
  action: "login",
  cdata: "session_abc123",
});

Xác minh mã thông báo phía máy chủ

Nếu bạn đang xây dựng một máy chủ xác minh mã thông báo Turnstile:

async function verifyTurnstileToken(token, ip) {
  const resp = await fetch(
    "https://challenges.cloudflare.com/turnstile/v0/siteverify",
    {
      method: "POST",
      headers: { "Content-Type": "application/x-www-form-urlencoded" },
      body: new URLSearchParams({
        secret: "YOUR_TURNSTILE_SECRET_KEY",
        response: token,
        remoteip: ip,
      }),
    }
  );

  const data = await resp.json();
  return data.success;
}

Khắc phục sự cố

Triệu chứng nguyên nhân sửa chữa
Khóa trang web bắt đầu bằng 6Le Đó là reCAPTCHA, không phải Turnstile Sử dụng method=userrecaptcha
Mã thông báo bị từ chối Sitekey sai hoặc đã hết hạn Giải nén lại sitekey, gửi nhanh hơn
Không tìm thấy khóa trang web Cloudflare Turnstile được tải qua JavaScript Thay vào đó hãy sử dụng Puppeteer/Playwright
ERROR_BAD_PARAMETERS Thiếu khóa trang web hoặc pageurl Kiểm tra cả hai đều có mặt
Phản hồi 403 sau khi gửi Phát hiện bot trên tiêu đề Sử dụng tác nhân người dùng thực tế

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

Turnstile khác với reCAPTCHA như thế nào?

Turnstile là giải pháp thay thế CAPTCHA của Cloudflare. Nó thường ẩn, giải quyết nhanh hơn và sử dụng tham số API method=turnstile thay vì method=userrecaptcha.

Tôi có cần chỉ định tham số hành động không?

Chỉ khi việc triển khai Turnstile của trang web sử dụng nó. Kiểm tra data-action trong HTML hoặc action: trong JavaScript.

Tỷ lệ thành công của việc giải quyết Turnstile là bao nhiêu?

CaptchaAI đạt tỷ lệ thành công 100% trong các thử thách Cloudflare Turnstile.


Tóm tắt

Giải Cloudflare Turnstile bằng Node.js vàCaptchaAI: giải nén khóa trang web (bắt đầu bằng 0x), giải quyết thông qua API method=turnstile và gửi mã thông báo dưới dạng cf-turnstile-response.

bài viết liên quan

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