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."라는 텍스트가 표시된 잘 알려진 페이지를 보게 됩니다. 이 확인 과정 중에는 CAPTCHA를 풀어야 할 수도 있습니다. 이전에는 reCAPTCHA를 사용했지만, 이제는 자체 제작한 Turnstile CAPTCHA를 사용합니다.
CAPTCHA 검증에 성공하면, 브라우저는 cf_clearance라는 이름의 쿠키에 고유한 토큰을 받습니다. 브라우저는 이 토큰을 사용해 Cloudflare 프록시를 통해 웹사이트 페이지를 요청합니다. 이 토큰이 만료되거나 Cloudflare가 내부적으로 봇처럼 행동한다고 판단할 경우, 토큰은 무효화되고 다시 CAPTCHA 확인 페이지가 나타납니다.
이 방법은 자동화된 브라우저 세션을 통해 해당 토큰을 얻을 수 있도록 도와줍니다. 이 방법은 웹사이트의 실제 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 함수를 프록시 함수로 대체하여 초기화 매개변수와 CAPTCHA 완료 콜백을 가로챕니다.
3. 초기화 매개변수를 Anti-Captcha API로 전송합니다. 사람이 CAPTCHA를 풀고 토큰을 제공합니다.
4. 이전에 저장해 둔 콜백 함수를 Turnstile 토큰을 인자로 하여 호출합니다.
5. Cloudflare는 내부적으로 토큰을 검증하고 쿠키를 브라우저에 설정한 후 페이지를 새로 고칩니다.
6. 이렇게 생성된 cf_clearance 쿠키를 통해 브라우저는 Cloudflare 프록시를 통해 웹사이트 콘텐츠를 가져옵니다.