TLS 핑거프린팅 (JA3/JA4): 왜 깨끗한 IP가 차단되는가

주거용 IP는 깨끗하고, 헤더도 완벽한데 첫 요청에서 403이 발생합니다. 문제는 TLS 핸드셰이크입니다 — HTTP가 교환되기 전에 안티봇 시스템이 읽는 지문입니다.

모든 스크래퍼가 결국 맞닥뜨리는 퍼즐입니다: 주거용 IP는 깨끗하고, User-Agent는 최신 Chrome 문자열이며, 헤더도 완벽한데 첫 요청이 403으로 돌아옵니다. 아무리 회전해도 해결되지 않습니다. 이유는 차단이 헤더가 읽히기 전에 발생했기 때문입니다. 현대의 안티봇 시스템은 TLS 핸드셰이크를 지문으로 삼고, 기본 Python, Go 또는 curl 클라이언트는 ClientHello에서 봇임을 알립니다, HTTP보다 한 단계 아래에서. 이것이 JA3와 JA4 핑거프린팅이 하는 일이며, 왜 curl이 동일한 URL에서 403을 받고 브라우저는 200을 받는지의 이유입니다.

TLS 핑거프린팅이 읽는 것

모든 HTTPS 연결은 TLS 핸드셰이크로 시작됩니다. 클라이언트는 ClientHello를 보내며, 특정 순서로 원하는 TLS 버전, 지원하는 암호화 스위트, 제공하는 확장(SNI, ALPN 등), 타원 곡선 및 포인트 형식을 광고합니다. 이 중 어느 것도 브라우저를 직접적으로 명명하지 않지만, 정확한 조합과 순서는 소프트웨어 스택의 거의 고유한 서명입니다. Chrome의 목록은 Firefox와 다르고, 둘 다 Python의 requests나 Go의 net/http와 크게 다릅니다. 핸드셰이크를 읽으면 HTTP 바이트가 교환되기 전에 클라이언트를 추측할 수 있습니다.

JA3: 다섯 필드를 하나의 MD5 해시로

JA3는 2017년 Salesforce의 엔지니어들이 발표한 클래식한 방법입니다. ClientHello에서 다섯 개의 필드 — TLS 버전, 암호화, 확장, 타원 곡선 및 포인트 형식 — 을 가져와 연결하고, 문자열을 MD5로 처리합니다. 구체적인 예: 필드들이

771,4865-4866-4867,0-11-10-35-16-5-13,29-23-24,0

e7d705a3286e19ea42f587b344ee6865로 해시됩니다 — 이는 표준 curl 빌드에 속하는 핑거프린트입니다. 안티봇 벤더들은 이러한 해시의 데이터베이스를 유지합니다. JA3가 알려진 스크래핑 라이브러리와 일치하는 요청은 더 엄격한 속도 제한, 도전, 또는 완전한 차단을 받습니다. 가장 강력한 검사는 상관관계입니다: User-Agent가 Chrome 120이라고 주장하지만 JA3가 python-requests라고 말하면, 그 모순만으로도 실패의 원인이 됩니다.

왜 JA3가 JA4로 대체되었는가

JA3는 안정적인 신호로서의 약점이 있습니다. Chrome 110과 Firefox 114부터 브라우저는 핑거프린팅을 저항하기 위해 모든 연결에서 TLS 확장의 순서를 무작위로 만듭니다. 이는 실제 브라우저가 이제 각 세션마다 다른 JA3 해시를 생성한다는 것을 의미하며, 따라서 원시 JA3는 진짜 사용자에게 잘못된 긍정을 던집니다. 업계의 대응은 JA3N (해시하기 전에 확장을 정렬하여 무작위화를 취소하는 정규화된 변형)과 JA3의 창시자가 만든 FoxIO의 새로운 스킴인 JA4입니다.

JA4는 더 읽기 쉽고 위조하기 어렵습니다. a_b_c 레이아웃을 사용하며, 예를 들어 t13d1516h2_8daaf6152771_e5627efa2ab1입니다. 접두사만으로도 많은 것을 알 수 있습니다: t는 TCP, 13은 TLS 1.3, d는 도메인 기반 SNI, 15는 암호화 스위트, 16은 확장, h2는 첫 번째 ALPN으로 HTTP/2를 의미합니다 — 그 뒤로는 정렬된 암호화와 확장 및 서명 알고리즘의 두 개의 잘린 해시가 이어집니다. JA4는 한 가족 중 하나입니다: JA4S는 서버를, JA4H는 HTTP 헤더를, JA4X는 인증서를, JA4T는 원시 TCP 레이어를 핑거프린트합니다.

기본 클라이언트가 TLS 핸드셰이크에서 차단되고 브라우저 모양의 클라이언트가 통과하는 다이어그램, HTTP가 전송되기 전에
JA3/JA4 조회는 핸드셰이크에서 발생합니다 — 일치하지 않는 핑거프린트는 헤더가 읽히기 전에 403입니다.

왜 깨끗한 IP가 당신을 구하지 못하는가

이것은 프록시에만 투자하는 사람들을 혼란스럽게 만드는 부분입니다. 깨끗한 주거용 IP는 사이트에 트래픽이 실제 네트워크에서 온다는 것을 알립니다. 브라우저와 일치하지 않는 TLS 핸드셰이크는 스크립트에서 온다는 것을 알립니다. 이 두 신호가 일치하지 않을 때, 핸드셰이크가 이깁니다, 왜냐하면 실수로 위조하기 훨씬 어렵기 때문입니다. 천 개의 깨끗한 출구를 회전해도 모든 요청이 동일한 python-requests JA3를 가지고 있다면 여전히 실패할 것입니다. IP와 핑거프린트는 별개의 축입니다 — 둘 다 맞춰야 합니다.

구체적으로, 이는 Cloudflare로 보호된 대상에 대한 통과율에서 나타납니다: 기본 requests 클라이언트는 대략 2%의 요청을 통과하고, HTTP/2를 사용하는 httpx는 조금 더 나아지며, 브라우저와 일치하는 클라이언트는 중간 80%에 도달합니다. 모든 경우 동일한 IP 풀입니다. 변수는 TLS 스택입니다. Akamai는 TLS 핑거프린트를 HTTP/2 핑거프린트 — SETTINGS 프레임 값, 윈도우 크기 및 스트림 우선순위 — 와 결합하여 기준을 더 높입니다, 그래서 올바른 JA3도 HTTP/2 레이어가 스크립트처럼 보이면 잡힐 수 있습니다. 왜 Akamai가 대부분의 프록시 트래픽을 차단하는지에 대한 우리의 분석은 그 스택에 대해 더 깊이 들어갑니다.

기본 python-requests에서 httpx 및 curl_cffi를 거쳐 헤드리스 브라우저까지 클라이언트별 Cloudflare 통과율의 막대 차트
모든 경우 동일한 깨끗한 IP — TLS 스택만이 통과율을 변경합니다. 해결책은 핸드셰이크, 출구가 아닙니다.

실제로 통과하는 가장 옵션

암호화 문자열을 조정하여 표준 클라이언트에 브라우저 핸드셰이크를 붙일 수 없습니다 — OpenSSL과 urllib3 노브는 JA3가 읽는 모든 매개변수를 노출하지 않습니다. 작동하는 것은 브라우저의 정확한 TLS 방언을 사용하는 클라이언트입니다:

# curl_cffi: a browser-shaped handshake in two lines
from curl_cffi import requests

session = requests.Session(impersonate="chrome120")
r = session.get(
    "https://example.com",
    proxies={"https": "http://USER:PASS@gate.quantumproxies.io:8000"},
    timeout=20,
)
print(r.status_code)  # matched JA3 + a clean residential exit

그 스니펫에서 프록시를 주목하세요. 가장과 깨끗한 출구는 상호 보완적이지 대체가 아닙니다: 브라우저 모양의 핸드셰이크는 TLS 검사를 통과하게 하고, 깨끗한 주거용 IP는 요청을 평판 차단 목록에서 벗어나게 합니다. 둘을 결합하면 두 축을 한 번에 해결할 수 있습니다.

Scraper API로 TLS 무기 경쟁을 건너뛰세요

전체 문제를 넘길 때

DIY 가장은 대상이 탐지를 회전시키거나, HTTP/2 핑거프린트를 추가하거나, JavaScript 실행을 요구할 때까지 작동합니다 — 그러면 브라우저 에뮬레이션 라이브러리를 두 번째 직업으로 유지하게 됩니다. Scraper API는 실제, 회전하는 브라우저 핑거프린트를 가지고, HTTP/2 레이어와 일치하며, 필요에 따라 JS를 실행하고, 단일 호출로 깨끗한 HTML, markdown 또는 JSON을 반환합니다. 이는 TLS 무기 경쟁을 다른 사람의 문제로 전환시키고 데이터를 계속 진행할 수 있게 합니다. 사이트가 자동화를 플래그하는 방법에 대한 더 넓은 그림은 모든 프록시 탐지 신호에 대한 우리의 가이드를 참조하세요.

자주 묻는 질문

JA3 핑거프린트란 무엇인가요?

JA3 핑거프린트는 TLS ClientHello에서 가져온 다섯 개의 필드 — TLS 버전, 암호화 스위트, 확장, 타원 곡선 및 포인트 형식 — 의 MD5 해시입니다. 각 소프트웨어 스택이 이러한 필드를 다르게 정렬하기 때문에, 해시는 HTTP 데이터가 교환되기 전에 클라이언트(Chrome, Firefox, curl, Python)를 식별합니다.

JA3와 JA4의 차이점은 무엇인가요?

JA3는 다섯 개의 ClientHello 필드를 MD5로 해시하며, 브라우저가 확장 순서를 무작위로 만들면 깨집니다. FoxIO의 JA4는 해시하기 전에 필드를 정렬하여 무작위화를 견디고, 사람이 읽을 수 있는 메타데이터 접두사를 추가하며, QUIC/HTTP/3, ALPN 및 서명 알고리즘을 다룹니다. JA4는 더 신뢰할 수 있는 현대 신호이며, JA3N은 JA3의 정규화된 임시 방편입니다.

프록시만으로 TLS 핑거프린팅을 우회할 수 있나요?

아니요. 프록시는 IP를 변경하지만 핸드셰이크는 변경하지 않습니다. TLS 핑거프린트가 알려진 스크래핑 라이브러리와 일치하면, 출구를 회전해도 도움이 되지 않습니다 — 모든 요청이 여전히 봇 서명을 가지고 있습니다. 브라우저의 TLS 스택을 재현하는 클라이언트가 필요하며, 그 위에 IP 평판을 위한 깨끗한 프록시가 필요합니다.

Python requests는 감지 가능한 TLS 핑거프린트를 가지고 있나요?

네. requests는 독특한 암호화 및 확장 순서를 가진 urllib3를 사용하며, 안티봇 벤더들이 이를 카탈로그화하여, JA3는 알려진 봇 서명입니다. curl_cffi로 전환하고 impersonate 프로필을 사용하여 브라우저와 일치하는 핸드셰이크를 전송하세요.

TLS 핑거프린팅은 싸움을 HTTP 아래로 이동시켰으며, 이것이 헤더 트릭과 IP 회전이 혼자서는 충분하지 않게 된 이유입니다. 핸드셰이크를 맞추고, 출구를 깨끗하게 유지하면, 첫 요청에서 403 문제가 사라집니다. 이는 기술적인 지침이지, 사이트의 약관을 무시하라는 허가가 아닙니다 — 항상 법과 대상의 규칙 내에서 스크래핑하세요.

Scraper API가 JA3, JA4 및 HTTP/2를 처리하게 하세요