TECH 으로 돌아가기
TECH HACKER NEWS 8분 읽기 28 READS

헤드리스 브라우저 없이 Cloudflare Turnstile를 푸는 Rust 라이브러리 cfsolve

헤드리스 브라우저 없이 Cloudflare Turnstile를 푸는 Rust 라이브러리 cfsolve
SOURCE IMAGE · HACKER NEWS

웹 자동화나 스크래핑을 다뤄 본 실무자라면 Cloudflare의 봇 차단 장치, 특히 Turnstile 위젯과 챌린지 페이지(challenge page) 앞에서 막힌 경험이 있을 것이다. 지금까지 이 관문을 통과하려면 대개 헤드리스 브라우저를 띄워 실제 자바스크립트 실행 환경을 흉내 내는 방식이 동원됐다. 하지만 헤드리스 브라우저는 무겁고 느리며, 동시 처리 규모를 키울수록 메모리와 CPU 비용이 가파르게 오른다. cfsolve는 이 접근을 뒤집어, 브라우저를 아예 띄우지 않고 요청(request) 기반으로 챌린지를 재현해 토큰을 얻어내는 Rust 라이브러리이자 커맨드라인 도구다.

무엇을 반환하는가

cfsolve가 다루는 대상은 두 가지다. 하나는 페이지에 삽입되는 Turnstile 위젯이고, 다른 하나는 접속을 가로막는 챌린지 페이지다. 위젯의 경우 페이지 URL과 사이트키(sitekey)만 있으면 Turnstile 토큰을 돌려주며, 페이지 HTML은 대부분의 경우 필요하지 않다. 챌린지 페이지의 경우에는 해당 페이지를 직접 받아오거나 그 HTML을 넘겨야 하며, 성공 시 cf_clearance 쿠키를 반환한다. 즉 위젯 통과용 토큰과 사이트 접근용 쿠키라는, Cloudflare 생태계에서 실질적으로 쓰이는 두 산출물을 모두 커버한다.

동작의 핵심은 특정 브라우저를 '사칭'한다는 점이다. cfsolve는 프로파일 파일로 기술된 브라우저 행세를 하는데, 저장소에는 아이폰용 Safari를 흉내 내는 profiles/safari-26-ios.json이 함께 들어 있다. 각 프로파일은 챌린지가 수행하는 브라우저 검사에 대한 응답을 미리 녹화해 둔 JSON 디렉터리를 참조하므로, 프로파일을 복사할 때는 반드시 해당 디렉터리를 함께 옮겨야 한다. 현재 지원되는 프로파일 유형은 Safari와 Chrome(ium) 계열뿐이다.

프로파일을 만드는 수고

이 도구의 성격을 이해하려면 프로파일 생성 과정을 봐야 한다. 녹화 파일을 만드는 일은 어느 정도 수작업(또는 AI의 도움)을 요구한다. 다만 실제 웹 브라우저로 챌린지를 풀되 프록시를 capture-proxy의 주소로 지정해 두면, Cloudflare로 전송되는 디코딩된 페이로드가 기록되어 작업이 한결 수월해진다. 결국 cfsolve는 '한 번 분석해 둔 브라우저 행동을 재생한다'는 전략을 취하는 셈이고, 이는 성능 이점과 유지보수 부담이 동전의 양면처럼 붙어 있음을 뜻한다. Cloudflare가 검사 방식을 바꾸면 녹화된 응답을 다시 떠야 할 가능성이 높다.

빌드 환경도 가볍지 않다. rust-toolchain.toml에 고정된 Rust 버전은 물론, CMake와 C/C++ 컴파일러, libclang, 그리고 BoringSSL을 패치해 빌드하기 위한 Git까지 필요하다. 암호화 핸드셰이크 수준에서 브라우저를 모사해야 하는 특성상 BoringSSL 패치가 들어간다는 점은, 이 도구가 단순한 HTTP 흉내 이상으로 TLS 지문까지 신경 쓴다는 신호다. 의존성으로 쓸 때는 cfsolve를 path 의존성으로 추가하고 [patch] 섹션을 복사해야 하는데, Cargo가 패치를 최상위 Cargo.toml에서만 읽기 때문이다. default-features = false로 내부 도구를 끄면 솔버만 남길 수 있다.

API 사용 패턴과 주의점

라이브러리 설계는 실제 운영을 고려한 흔적이 보인다. Browser는 한 번 로드해 공유하도록 권장되며, 동시 작업은 각자 별도의 연결과 쿠키를 갖는다. 페이지를 가져오는 방식은 PageSource로 제어하는데, Navigate는 cfsolve가 직접 페이지를 받아오고, 사이트키만 있을 때는 Blank를 쓰면서 --page에 실제 사이트 URL을 지정하고 위젯을 명시한다. 로그인 뒤편의 페이지처럼 이미 받아 둔 HTML이 있으면 URL과 HTML을 함께 넘기면 된다. 위젯은 교차 사이트 iframe 안에서 돌기 때문에 로그인 쿠키가 없어도 된다는 설명은, 인증 영역 뒤의 위젯 처리에서 특히 유용하다. 사이트가 action과 cData를 설정하면 그 값을 함께 넘기고, 설정하지 않으면 None으로 두면 된다. 여러 위젯이 있을 때는 사이트키로 특정 위젯을 고르며, --sitekey를 지정하면 챌린지 페이지에서는 실패한다.

챌린지 처리에는 browser.clear가 쓰이고, 직접 받아 둔 페이지가 있으면 clear_fetched에 FetchedPage로 넘긴다. 반환되는 Clearance에는 cf_clearance 쿠키, 페이지의 전체 쿠키, 보호된 페이지 본문이 담긴다. 챌린지가 없으면 Error::NotChallenged로 실패하고, URL이 위젯인지 챌린지인지 모를 때는 양쪽을 아우르는 browser.solve를 쓰면 된다. 프록시는 작업 단위로 Options를 통해 HTTP·HTTPS·SOCKS5로 지정할 수 있으며, 라이브러리 연산은 기본적으로 조용하지만 Sink를 구현해 options.sink에 넣으면 진행 메시지와 디버그 파일을 받을 수 있다.

실무적으로 가장 중요한 제약은 반복해서 강조되는 한 문장이다. cf_clearance 쿠키는 프로파일과 동일한 IP 주소 및 user agent에서 전송해야 하며, 그렇지 않으면 Cloudflare가 거부한다. 즉 토큰이나 쿠키를 얻었다고 끝이 아니라, 그 산출물을 실제로 쓰는 요청의 네트워크·브라우저 지문이 녹화 당시와 일치해야 한다는 뜻이다. 프록시 설정과 user agent 관리를 느슨하게 하면 애써 통과한 챌린지가 무용지물이 된다.

라이선스는 MIT이되 vendor/에 들어간 패치된 의존성은 각자의 라이선스를 따른다. 정리하면 cfsolve는 헤드리스 브라우저의 무게를 걷어내고 요청 재생 방식으로 효율을 노린 접근이지만, 프로파일 녹화라는 선행 비용과 Cloudflare 변경에 따른 유지보수 리스크, 그리고 IP·user agent 일치 요건이라는 운영 제약을 함께 떠안는다. 봇 탐지와 그 우회가 끝없이 맞물리는 영역인 만큼, 도입을 검토한다면 기술적 매력뿐 아니라 대상 사이트의 이용약관과 법적·윤리적 경계도 함께 따져야 한다.

SOURCE · HACKER NEWS
원문 전체 보기 → https://github.com/chris124567/cfsolve
SHARE
NEXT · CHOOSE

변화를 읽었다면,
내가 만들 수익 구조를 고릅니다.

정보를 더 모으는 데서 멈추지 않고, 광고·외주·판매·중개·구독 중 내 상황에 맞는 출발점을 정해보세요.

21가지 수익 구조 살펴보기 →
처리 중...