인터넷에 떠도는 대부분의 "Cloudflare 우회 방법" 튜토리얼은 2024년 말부터 더 이상 작동하지 않습니다. 그 이유는 Cloudflare가 새로운 방어 기법을 추가했기 때문이 아닙니다. JA3 핑거프린팅과 기본적인 헤더 검사 같은 기존 방어 기법이, 모든 편법을 무력화하는 새로운 세대의 방어 기법으로 교체되었기 때문입니다. 이 가이드는 2026년에 Cloudflare가 실제로 무엇을 검사하는지, 왜 cloudscraper, undetected-chromedriver, 그리고 대부분의 "스텔스" 플러그인이 실패하는지, 그리고 여전히 프로덕션에서 작동하는 4계층 레시피를 설명합니다.
솔직한 요약을 먼저 말하자면, 단 하나의 비법은 없습니다. Cloudflare를 안정적으로 우회하려면 올바른 IP, 올바른 TLS 핑거프린트, 올바른 HTTP/2 프레임 순서, 그리고 (Bot Management 등급의 경우) 진짜 브라우저가 필요합니다. 이 중 하나라도 잘못되면, 요청이 오리진 서버에 도달하기도 전에 엣지 필터에서 걸러집니다.
Cloudflare의 봇 탐지는 엣지에서 일련의 필터 파이프라인으로 실행됩니다. 모든 요청은 순서대로 이 필터들을 통과합니다. 가장 먼저 거부하는 필터가 이기므로, 어떤 핑거프린트나 헤더가 검사되기도 전에 IP 평판만으로 요청이 실패할 수 있습니다.
이것이 가장 먼저이자 가장 비용이 적게 드는 검사입니다. Cloudflare는 ASN(Autonomous System Number)을 키로 하는 데이터베이스를 유지합니다. 잘 알려진 클라우드 제공업체에 속한 ASN(AWS AS16509, GCP AS15169, Azure AS8075, OVH AS16276, DigitalOcean AS14061, Hetzner AS24940, Vultr AS20473)은 가장 높은 수준의 정밀 조사를 받습니다. 완벽한 브라우저 수준의 핑거프린트를 가지고 있어도, 이러한 ASN에서 출발하는 요청은 무죄가 입증될 때까지 유죄로 취급됩니다.
주거용 ASN(Comcast AS7922, Verizon AS701, China Telecom AS4134, BT AS2856)은 정당한 것으로 추정됩니다. 어설픈 Python 핑거프린트를 가진 주거용 IP의 요청은 여전히 통과할 수 있는 반면, 완벽한 Chrome 핑거프린트를 가진 데이터센터 IP의 요청은 챌린지를 받거나 차단됩니다.
JA4는 FoxIO가 출시한 JA3의 2023년 후속 버전입니다. 이는 특정 TLS ClientHello 필드를 해싱합니다: TLS 버전, 암호 스위트(순서대로), 확장(순서대로), ALPN 프로토콜, 서명 알고리즘, 지원 그룹. 출력은 t13d1516h2_8daaf6152771_b1ff8ab2d16f와 같은 결정론적 핑거프린트입니다.
실제 Chrome 124는 특정한 하나의 JA4를 생성합니다. 실제 Firefox 124는 다른 것을 생성합니다. Python의 requests 라이브러리(urllib3와 OpenSSL을 사용)는 어떤 실제 브라우저도 내보내지 않는 JA4를 생성하는데, 암호 순서와 확장 목록이 Chrome이나 Firefox 어느 쪽과도 일치하지 않기 때문입니다. Cloudflare는 어떤 HTTP 헤더를 파싱하기도 전에 이 패턴을 표시합니다.
그 함의는: 시스템 OpenSSL이나 기본 Python TLS를 사용하는 모든 라이브러리는 탐지 가능하다는 것입니다. 여기에는 requests, aiohttp, httpx(기본 설정), 그리고 이들 위에 구축된 모든 "우회" 래퍼가 포함됩니다.
HTTP/2 연결은 settings 프레임, window update, priority 프레임, headers 프레임을 전달합니다. 브라우저는 이들을 특정 값과 함께 특정 순서로 전송합니다. Chrome 124는 이 정확한 값으로 초기 SETTINGS 프레임을 보낸 다음, WINDOW_UPDATE, 그다음 HEADERS를 보냅니다. HTTP/2가 활성화된 Python의 httpx는 다른 settings 페이로드를 보내고 Chrome이 포함하는 priority 프레임을 생략합니다.
HTTP/2 의사 헤더 순서 또한 신원을 누설합니다. Chrome은 :method, :authority, :scheme, :path를 그 순서로 보냅니다. Firefox는 :method, :path, :authority, :scheme를 보냅니다. 대부분의 Python과 Go 라이브러리는 이들을 알파벳 순으로 직렬화합니다. Cloudflare는 선언된 User-Agent에 대해 예상되는 패턴과 순서를 비교하여 불일치를 표시합니다.
HTTP/1.1 헤더는 삽입 순서를 보존합니다. 실제 Chrome은 헤더를 고정된 순서로 보냅니다: Host, Connection, Cache-Control, sec-ch-ua, sec-ch-ua-mobile, sec-ch-ua-platform, Upgrade-Insecure-Requests, User-Agent, Accept, Sec-Fetch-Site, Sec-Fetch-Mode, Sec-Fetch-User, Sec-Fetch-Dest, Accept-Encoding, Accept-Language. Python의 requests는 이들을 재정렬하고 때때로 대소문자를 다르게 표기합니다. 헤더를 올바른 순서로 수동으로 설정하더라도, 기저 라이브러리가 이를 다시 정렬하기 때문에 도움이 되지 않습니다.
이전 필터들을 통과했지만 점수가 여전히 의심스러우면, Cloudflare는 JavaScript 챌린지를 제공합니다. 이 스크립트는 브라우저 환경 값(canvas 해시, WebGL 렌더러, audio context, navigator 속성, 타이밍 측정)으로부터 토큰을 계산하고 XHR을 통해 제출합니다. 어떤 HTTP 클라이언트도 이를 해결할 수 없습니다. 진짜 브라우저가 필요하며, 그 브라우저는 진짜처럼 보여야 합니다(navigator.webdriver = true가 없어야 하고, 누락된 속성이 없어야 합니다).
Bot Management 등급에서는 Cloudflare가 지속적으로 실행되는 스크립트를 통해 마우스 움직임, 스크롤 속도, 클릭 타이밍, 키 입력 동역학을 수집합니다. 페이지를 로드하고 마우스를 한 번도 움직이지 않은 채 즉시 스크래핑하는 헤드리스 브라우저는 몇 초 안에 탐지됩니다. 실제 사용자는 불규칙하게 움직이고, 멈추고, 다시 읽습니다. 봇은 선형적으로 스크롤하고 픽셀 단위로 정확하게 클릭합니다.
2021-2024년 스크래핑을 떠받쳤던 편법 도구들은 모두 하나의 실패 모드를 공유합니다: 보이는 표면은 패치하지만 기저의 TLS 스택은 패치하지 않습니다.
| 도구 | 패치하는 것 | 2026년에 실패하는 이유 |
|---|---|---|
cloudscraper | JS 챌린지 솔버 (레거시) | Cloudflare는 2023년에 Turnstile로 이동; 레거시 챌린지는 폐기됨 |
undetected-chromedriver | Selenium 누설 플래그 패치 | JA4가 기저 chromedriver TLS에서 여전히 누설됨; navigator.webdriver는 40개 이상의 신호 중 하나일 뿐 |
selenium-stealth | 위조된 JS 속성 주입 | Cloudflare는 JS가 아닌 C++ 계층에서 읽음; 위조가 불일치로 탐지됨 |
FlareSolverr | 일회성 챌린지 해결을 위해 Chromium 래핑 | cf_clearance가 솔버 IP에 바인딩됨; 새 프록시는 토큰을 즉시 무효화함 |
기본 puppeteer-extra-plugin-stealth | 약 17개 탐지 지점 패치 | Cloudflare는 2024-2025년에 플러그인이 다루지 않는 약 12개의 새로운 검사를 추가함 |
패턴은 명확합니다: 진짜 브라우저를 래핑하고 알려진 누설을 패치하는 도구는 몇 달 안에 군비 경쟁에서 집니다. 브라우저의 TLS 스택을 시뮬레이션하는 도구(curl_cffi, tls-client)는 와이어에 더 가깝게 위치하기 때문에 살아남았습니다.
2026년에 작동하는 우회는 네 계층 모두가 필요합니다. 어느 하나라도 건너뛰면 성공률이 한 자릿수로 떨어집니다.
이것은 Cloudflare Pro 이상을 실행하는 모든 사이트에 대해 타협의 여지가 없습니다. IP 평판 필터는 TLS 핸드셰이크가 완료되기 전에 데이터센터 ASN을 거부합니다. cf_clearance 쿠키가 살아남도록 최소 10분 동안 스티키 세션이 있는 주거용 프록시를 사용하세요.
curl_cffi(Python) 또는 tls-client(Go/Python)를 사용하세요. 둘 다 Chrome의 정확한 암호 순서, 확장 목록, ALPN 값을 탑재한 수정된 BoringSSL에 링크됩니다.
from curl_cffi import requests
response = requests.get(
"https://target.com/api/products",
impersonate="chrome124",
proxies={"https": "http://user-session-abc123:[email protected]:10001"},
timeout=30,
)
print(response.status_code, len(response.text))
impersonate="chrome124" 매개변수는 ClientHello가 Chrome 124와 바이트 단위로 일치하도록 TLS 스택을 교체합니다. JA4 해시는 실제 Chrome 124 설치와 동일할 것입니다. 이를 주거용 프록시와 결합하면 처음 두 필터를 통과합니다.
curl_cffi는 impersonate를 사용할 때 헤더를 Chrome의 순서로 자동 설정합니다. 사용자 정의 헤더를 추가하는 경우, 중간에 삽입하기보다 끝에 추가하세요. 실제 Chrome이 보내지 않을 헤더(예: 일반 내비게이션에서의 X-Requested-With)는 설정하지 마세요.
Accept-Language의 경우, 프록시의 지리적 위치와 일치시키세요. Accept-Language: zh-CN,zh;q=0.9를 보내는 미국 주거용 IP는 작지만 실제적인 신호입니다. 미국 IP에는 en-US,en;q=0.9를, 독일 IP에는 de-DE,de;q=0.9를 사용하는 식입니다. 이것은 무료로 고칠 수 있는 몇 안 되는 신호 중 하나입니다.
대상이 Managed Challenge를 트리거하면(응답 본문에 CF 챌린지 페이지가 보이면), curl_cffi 단독으로는 이를 해결할 수 없습니다. 패치된 Chromium이 있는 Playwright로 전환하세요.
from playwright.sync_api import sync_playwright
from rebrowser_playwright.sync_api import sync_playwright as rebrowser_sync
with rebrowser_sync() as p:
browser = p.chromium.launch(
headless=True,
proxy={
"server": "http://gate.jibaoproxy.com:10001",
"username": "user-session-abc123",
"password": "pass",
},
)
context = browser.new_context(
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
viewport={"width": 1920, "height": 1080},
locale="en-US",
timezone_id="America/New_York",
)
page = context.new_page()
page.goto("https://target.com/", wait_until="networkidle")
# cf_clearance is now in context.cookies()
cookies = context.cookies()
cf_clearance = next((c for c in cookies if c["name"] == "cf_clearance"), None)
browser.close()
기본 playwright 대신 rebrowser-playwright를 사용하세요. 이는 Cloudflare가 헤드리스 자동화를 탐지하기 위해 읽는 CDP 런타임 누설(Runtime.enable, 페이지에 대한 CDP 명령 노출)을 패치합니다. 챌린지를 통과한 후, 쿠키에서 cf_clearance를 추출하여 실제 스크래핑 루프를 위해 curl_cffi로 넘겨주세요. 브라우저는 요청당이 아니라 세션당 한 번 필요합니다.
가장 저렴한 프록시를 사용하려는 본능은 Cloudflare로 보호되는 사이트에서 거의 항상 틀립니다. 실제 숫자로 계산을 따라가 봅시다.
가정: 평균 HTML 페이지 500KB, 총 100,000페이지 스크래핑, 대상은 Bot Fight Mode가 활성화된 Cloudflare Pro 사용.
| 설정 | 대역폭 비용 | 성공률 | 성공당 요청 수 | 총 비용 | 페이지당 비용 |
|---|---|---|---|---|---|
| 데이터센터 $0.8/GB + requests | $0.0005 / req | 0.5% | 200 | $10,000 | $0.10 |
| 데이터센터 $0.8/GB + curl_cffi | $0.0005 / req | 3% | 33 | $1,650 | $0.0165 |
| 주거용 $2/GB + requests | $0.0033 / req | 40% | 2.5 | $825 | $0.0083 |
| 주거용 $2/GB + curl_cffi | $0.0033 / req | 92% | 1.09 | $360 | $0.0036 |
| 주거용 $2/GB + Playwright (rebrowser) | $0.017 / req (assets + JS) | 96% | 1.04 | $1,700 | $0.017 |
주목할 만한 두 가지 발견:
이것은 Cloudflare로 보호되는 대상을 대규모로 스크래핑하는 고객에게 우리가 추천하는 패턴입니다. Playwright 사용(느리고 비싼)을 최소화하고 curl_cffi 사용(빠르고 저렴한)을 최대화합니다.
from curl_cffi import requests as cf_requests
from rebrowser_playwright.sync_api import sync_playwright
PROXY_USER_FMT = "user-session-{sid}"
PROXY_HOST = "http://gate.jibaoproxy.com:10001"
PROXY_PASS = "your_password"
def get_cf_clearance(target_url, session_id):
"""One-shot Playwright call to solve the challenge and extract cf_clearance."""
with sync_playwright() as p:
browser = p.chromium.launch(
headless=True,
proxy={"server": PROXY_HOST,
"username": PROXY_USER_FMT.format(sid=session_id),
"password": PROXY_PASS},
)
ctx = browser.new_context(user_agent="Mozilla/5.0 ... Chrome/124.0.0.0 Safari/537.36")
page = ctx.new_page()
page.goto(target_url, wait_until="networkidle", timeout=45000)
cookies = ctx.cookies()
browser.close()
return {c["name"]: c["value"] for c in cookies}
def scrape_with_clearance(urls, session_id, cookies):
"""Reuse the same session_id (sticky IP) for all requests."""
proxy = f"http://{PROXY_USER_FMT.format(sid=session_id)}:{PROXY_PASS}@gate.jibaoproxy.com:10001"
out = []
for url in urls:
r = cf_requests.get(
url,
impersonate="chrome124",
proxies={"https": proxy},
cookies=cookies,
timeout=30,
)
if r.status_code == 200:
out.append((url, r.text))
elif r.status_code in (403, 503) and "challenge" in r.text.lower():
# cf_clearance expired; re-solve
cookies = get_cf_clearance(url, session_id)
r = cf_requests.get(url, impersonate="chrome124",
proxies={"https": proxy}, cookies=cookies)
out.append((url, r.text))
return out, cookies
# Usage
session_id = "scrape-job-2026-05-27"
cookies = get_cf_clearance("https://target.com/", session_id)
results, cookies = scrape_with_clearance(target_urls, session_id, cookies)
이 레시피의 핵심 포인트:
일부 Cloudflare 배포는 합리적인 비용으로는 우회할 수 없습니다. 이러한 신호가 보이면, 절대 안정화되지 않을 우회에 예산을 태우는 대신 전략을 전환하세요(API를 사용하거나, 사이트 소유자와 제휴하거나, 데이터를 구매하세요).
| 대상 등급 | 레시피 | 예상 성공률 |
|---|---|---|
| CF Free / Pro (Bot Fight 없음) | 데이터센터 + curl_cffi | 60-75% |
| CF Free / Pro + Bot Fight Mode | 주거용 + curl_cffi | 85-93% |
| CF Business | 주거용 + curl_cffi + 가끔 Playwright | 80-90% |
| CF Business + Turnstile | 주거용 + rebrowser-playwright (모든 요청) | 70-85% |
| CF Enterprise + Bot Management | 모바일 주거용 + rebrowser + 행동 시뮬레이션 | 30-60% |
| CF Enterprise + Bot Management + 사용자 정의 WAF | 스크래핑하지 말 것; API 또는 제휴 추구 | <10% |
JIBAO Proxy는 240개 이상의 국가에 걸친 9천만 개 이상의 IP, 최대 60분의 스티키 세션, 그리고 $2/GB부터 시작하는 국가 단위 타겟팅을 갖춘 동적 주거용 프록시를 제공합니다. 모바일 IP의 경우 동적 모바일 프록시를 참조하세요. 둘 다 curl_cffi, tls-client, Playwright, Puppeteer, Selenium, 그리고 HTTP/SOCKS5 프록시를 지원하는 모든 HTTP 클라이언트와 즉시 작동합니다.
관련 읽을거리: 스티키 vs 회전 프록시 세션은 세션 구성을 깊이 있게 다룹니다. AI 에이전트를 위한 프록시는 Cloudflare 우회 워크플로와 크게 겹치는 AI 에이전트 사용 사례를 설명합니다.
500MB 무료 트래픽을 받으세요. 약속하기 전에 당신의 대상에 대해 curl_cffi + 스티키 주거용 조합을 실행해 보세요.
무료 체험 시작하기신규 사용자는 가입 시 500MB를 받고, 첫 충전 시 추가 보너스를 받습니다. 기간 한정 혜택입니다.