당신은 깨끗한 주거용 IP를 구매했고, 완벽하게 로테이션하는데, 여전히 첫 요청에서 403을 받습니다. IP가 문제가 아닙니다 — 당신의 TLS 핸드셰이크가 문제입니다. TLS 지문은 서버가 당신의 HTTP 요청에서 단 1바이트도 읽기 전에 클라이언트 라이브러리를 식별하게 해줍니다. 이 가이드는 JA3/JA4를 설명하고, Python의 requests가 왜 탐지하기 쉬운지 보여주며, curl_cffi와 tls-client로 실제 브라우저를 위장하는 작동 코드를 제공합니다.
어떤 클라이언트든 HTTPS 연결을 열 때, 자신의 TLS 버전, 암호화 스위트(cipher suite), 확장(extension), 타원 곡선(elliptic curve), 그리고 그것들 전체의 순서를 알리는 ClientHello를 보냅니다. 그 순서는 그것을 만든 라이브러리에 놀랍도록 특정적입니다. 이를 해시하면 JA3 지문(또는 더 새롭고 강건한 JA4)을 얻습니다.
Chrome은 하나의 지문을 생성합니다. Firefox는 또 다른 것을. Python의 requests(urllib3와 OpenSSL 위에 구축됨)는 "자동화"라고 외치는 지문을 생성합니다 — 그리고 그것은 수백만 개의 봇에 걸쳐 동일합니다. 안티-봇 시스템은 이것들의 차단 목록을 유지합니다. 당신의 IP가 아무리 주거용이라 해도, 알려진 봇 JA3는 플래그됩니다.
무엇이든 고치기 전에, 측정하세요. 당신의 스크래퍼에서 JIBAO의 무료 JA3/JA4 지문 검사기로 요청을 보내고 실제 Chrome이 보여주는 것과 비교하세요. JA3 해시가 다르다면, 타깃은 당신을 사람과 구별할 수 있습니다 — 그리고 Cloudflare도 마찬가지입니다.
requests와 httpx는 TLS를 시스템의 OpenSSL에 넘깁니다. 헤더와 심지어 User-Agent까지 하루 종일 바꿀 수 있지만, 그 아래의 핸드셰이크는 여전히 Chrome의 것이 아니라 OpenSSL의 것입니다. 핸드셰이크 위장 없는 헤더 위장은 "브라우저 헤더를 복사했는데도 여전히 차단된다"가 발생하는 가장 흔한 이유입니다. 브라우저의 실제 TLS 스택을 모방하는 클라이언트가 필요합니다.
curl_cffi는 실제 브라우저 TLS 및 HTTP/2 지문을 재현하는 curl 빌드인 curl-impersonate에 바인딩됩니다. 인자 하나로 당신의 핸드셰이크는 Chrome처럼 보입니다:
# pip install curl_cffi
from curl_cffi import requests
# impersonate a real Chrome TLS + HTTP/2 fingerprint
r = requests.get(
"https://tls.browserleaks.com/json",
impersonate="chrome131",
)
print(r.json()["ja3_hash"]) # now matches real Chrome
API는 requests를 그대로 따르므로, 기존 스크래퍼를 마이그레이션하는 것은 대부분 한 줄의 import 변경입니다. 지원되는 타깃에는 최근 Chrome, Edge, Safari, Firefox 빌드가 포함됩니다 — 하나를 골라 최신 상태로 유지하세요. 브라우저가 업데이트되면서 지문이 로테이션되기 때문입니다.
지문 일치와 IP 로테이션은 대안이 아니라 상호 보완적입니다. 둘 다 사용하세요: 깨끗한 주거용 IP 위의 브라우저급 핸드셰이크가 실제로 통과하는 것입니다:
from curl_cffi import requests
PROXY = "socks5h://USERNAME:[email protected]:10001"
r = requests.get(
"https://example.com/protected",
impersonate="chrome131",
proxies={"http": PROXY, "https": PROXY},
timeout=30,
)
print(r.status_code)
tls-client(Go uTLS 구현 위의 Python 래퍼)는 또 다른 견고한 옵션으로, 이름이 붙은 프로필의 대규모 라이브러리를 제공합니다:
# pip install tls-client
import tls_client
session = tls_client.Session(
client_identifier="chrome_120",
random_tls_extension_order=True,
)
session.proxies = {
"http": "socks5h://USERNAME:[email protected]:10001",
"https": "socks5h://USERNAME:[email protected]:10001",
}
r = session.get("https://example.com/protected")
print(r.status_code)
random_tls_extension_order=True는 정적이고 재사용 가능한 지문을 피하기 위해 확장 순서를 섞습니다 — 시간이 지남에 따라 정확히 일치하는 JA3를 추적하는 시스템에 대해 유용합니다.
일부 타깃은 어떤 HTTP 클라이언트도 재현하지 못하는 JavaScript 실행 신호(캔버스, WebGL, 이벤트 타이밍)를 확인합니다. 그럴 때는 실제 브라우저를 구동하세요 — 스텔스와 함께 Playwright와 Puppeteer에서 프록시 사용하기를 참고하세요. 트레이드오프는 비용과 속도입니다: curl_cffi 같은 HTTP 클라이언트는 요청당 훨씬 저렴하므로, 충분한 곳에서는 그것을 사용하고 전체 브라우저는 가장 어려운 타깃을 위해 남겨두세요.
curl_cffi(impersonate=) 또는 tls-client로 핸드셰이크를 일치시키세요 — 헤더만으로는 충분하지 않습니다.TLS 지문은 대부분의 "깨끗한 IP인데도 여전히 차단됨" 이야기에서 빠진 계층입니다. 핸드셰이크를 고치고, 주거용 IP를 유지하면, 성공률이 급등합니다. 가장 까다로운 WAF에 대한 전체 스택은 2026 Cloudflare 우회 레시피를 읽으세요.
신규 사용자는 가입 시 500MB를 받고, 첫 충전 시 추가 보너스를 받습니다. 기간 한정 혜택입니다.