Tutorial

Solve Cloudflare Turnstile dengan Node.js dan CaptchaAI

Cloudflare Turnstile menggantikan reCAPTCHA di banyak situs. Panduan ini mencakup alur Node.js secara lengkap: mendeteksi Turnstile, mengekstrak sitekey, menyelesaikan melalui CaptchaAI, dan mengirimkan token.


Prasyarat

  • Node.js 18+ (pengambilan asli)
  • Kunci API CaptchaAI

Langkah 1: Deteksi dan ekstrak 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;
}

Langkah 2: Selesaikan Turnstile melalui 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");
}

Langkah 3: Kirimkan token

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(),
  };
}

Selesaikan alur masuk

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",
});

Kelas pemecah produksi

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");

Turnstile dengan parameter tindakan dan cData

Beberapa implementasi Turnstile mencakup parameter action dan cData:

// 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",
});

Verifikasi token sisi server

Jika Anda membangun server yang memverifikasi token 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;
}

Pemecahan Masalah

Gejala Penyebab Solusi
Sitekey dimulai dengan 6Le Itu reCAPTCHA, bukan Turnstile Gunakan method=userrecaptcha
Token ditolak Kunci situs salah atau kedaluwarsa Ekstrak ulang sitekey, kirim lebih cepat
Tidak ada sitekey yang ditemukan Turnstile dimuat melalui JavaScript Gunakan Dalang/Playwright sebagai gantinya
ERROR_BAD_PARAMETERS Kunci situs atau pageurl tidak ada Periksa keduanya ada
403 respons setelah dikirim Deteksi bot pada header Gunakan Agen Pengguna yang realistis

Pertanyaan yang sering diajukan

Apa perbedaan Turnstile dengan reCAPTCHA?

Turnstile adalah pengganti CAPTCHA Cloudflare. Biasanya tidak terlihat, lebih cepat dipecahkan, dan menggunakan parameter API method=turnstile, bukan method=userrecaptcha.

Apakah saya perlu menentukan parameter tindakan?

Hanya jika penerapan Turnstile di situs tersebut menggunakannya. Periksa data-action di HTML atau action: di JavaScript.

Berapa tingkat keberhasilan solve Turnstile?

CaptchaAI mencapai tingkat keberhasilan 100% pada tantangan Turnstile.


Ringkasan

Selesaikan Cloudflare Turnstile dengan Node.js danCaptchaAI: ekstrak sitekey (dimulai dengan 0x), selesaikan melalui API method=turnstile, dan kirimkan token sebagai cf-turnstile-response.

Artikel Terkait

Komentar dinonaktifkan untuk artikel ini.