Menu

如何绕过 Cloudflare

本文将教你如何使用 NodeJS 和 Playwright 浏览器自动化来绕过 Cloudflare 的“Verifying you are human”页面。

首先我们简要了解一下 Cloudflare 是如何工作的。如果没有 Cloudflare,网站管理员会将网页托管在具有公网 IP 地址的服务器上。它们的域名解析到该 IP,您的浏览器会直接连接到该服务器。

当他们使用 Cloudflare 时,会将 DNS 管理交给 Cloudflare,Cloudflare 会将域名解析为自己的 IP 地址。这些 IP 地址上运行着特殊的代理服务器,用于过滤传入的 HTTP 和 HTTPS 请求。

新访问者会看到一个熟悉的页面,上面写着:“Verifying you are human. This may take a few seconds.”。在这个验证过程中,您可能需要完成验证码。之前他们使用的是 reCAPTCHA,现在则使用他们自家的 Turnstile 验证码。

验证码验证通过后,浏览器会在名为 cf_clearance 的 Cookie 中收到一个唯一的 token。浏览器将使用该 token 从 Cloudflare 的代理服务器请求网站页面。如果该 token 过期,或者 Cloudflare 内部判断该 token 的行为类似于机器人,它将使 token 失效,并再次显示验证码页面。

我们的方法将帮助你通过自动化浏览器会话来获取该 token。请注意,此方法不会泄露网站的真实 IP 地址——该信息仅由 Cloudflare 和网站管理员掌握。这是件好事!

下面是如何使用 NodeJS 和 Playwright 实现这一过程:

// Install packages
// npx install playwright @antiadmin/anticaptchaofficial
import { chromium } from "playwright";
import ac from "@antiadmin/anticaptchaofficial";

// Specify the target website address
const websiteBehindCloudFlare = 'https://yourwebsite.com';

// Set your Anti-Captcha API key here:
ac.setAPIKey('API_KEY_HERE');
ac.setSoftId(0);

let browser = null;
let page = null;


(async () => {

    // Opening the browser
    try {
        console.log('Opening browser ..');
        browser = await chromium.launch({ headless: false });
        console.log('Creating new page ..');
        page = await browser.newPage();
    } catch (e) {
        console.log("Could not open browser: "+e.toString());
        return;
    }


    let params = null;

    try {

        // Doing several attempts to inject our code
        while (!params) {

            console.log('Navigating to the page')
            await page.goto(websiteBehindCloudFlare);

            console.log('Injecting our proxy code to replace window.turnstile');
            await page.evaluate(() => {
                window.turnstile = new Proxy(window.turnstile, {
                  get(target, prop) {
                    if (prop === "render") {
                      return function (a, b) {
                        const p = {
                          websiteURL: window.location.href,
                          websiteKey: b.sitekey,
                          action: b.action,
                          cData: b.cData,
                          chlPageData: b.chlPageData,
                          userAgent: navigator.userAgent,
                        };

                        // saving params in window.params
                        window.params = p;

                        // assigning callback to a variable
                        window.cfCallback = b.callback

                        // calling original render function
                        return target.render.apply(this, arguments);
                      };
                    }
                    return target[prop];
                  },
                });
            });

          console.log('Getting params');
          params = await page.evaluate(() => {
            return new Promise((resolve) => {
              setTimeout(() => resolve(window.params || null), 5000);
            });
          });

          if (!params) {
            console.log('Retrying..');
            await delay(3000);
          }
        }

        console.log("Extracted Turnstile Params:", params);

        console.log('Solving Turnstile captcha with Anti-Captcha')
        const token = await ac.solveTurnstileProxyless(websiteBehindCloudFlare, params.websiteKey, params.action, params.cData, params.chlPageData);

        // Running Cloudflare's callback function we previously assigned to window.cfCallback
        await page.evaluate((token) => {
            window.cfCallback(token)
        }, token);

        console.log('Waiting for redirects to finish')
        await delay(5000);

        // Get all cookies for current page
        const cookies = await page.context().cookies();
        // Find cf_clearance
        const cf_clearance = cookies.filter(c => c.name === 'cf_clearance');

        // Output cookies
        console.log('Cookies:', cookies);
        console.log('cf_clearance:', cf_clearance);



    } catch (e) {
      console.error('Could not inject proxy code:', e);
    }

    // close browser when needed
    // await browser.close();


})();

function delay(time) {
   return new Promise(function(resolve) {
       setTimeout(resolve, time)
   });
}

我们的代码主要完成以下步骤:

1. 打开浏览器窗口并跳转到 Cloudflare 的验证页面;
2. 用我们自定义的代理函数替换 Turnstile 的 render 函数,在其中拦截初始化参数和验证码完成后的回调函数;
3. 将初始化参数发送到 Anti-Captcha API,由人工工作人员为你解决验证码并返回 token;
4. 使用之前保存的回调函数调用 token 作为参数;
5. Cloudflare 内部验证该 token,在浏览器中设置 Cookie,并重新加载页面;
6. 有了这个 cf_clearance,浏览器就可以通过 Cloudflare 代理访问网站内容。