용어집

TLS 핑거프린트(JA3 / JA4)란 무엇인가요?

TLS 지문은 클라이언트의 TLS 핸드셰이크의 특정 구조(암호 목록, 확장, ALPN 값, GREASE 바이트 등)에서 파생된 해시로, 애플리케이션 계층 데이터가 교환되기 전에 기본 HTTP 클라이언트, 브라우저 또는 라이브러리를 식별합니다.

JA3와 JA4가 어떻게 작동하는지, 스크래퍼가 HTTP 요청을 보내기도 전에 Python requests나 curl을 사용하고 있다는 사실을 어떻게 드러내는지, 그리고 이를 무력화하는 방법을 이해합니다.

설명

클라이언트가 TLS 연결을 열면, 가장 첫 번째 바이트는 클라이언트가 지원하는 암호화 스위트, TLS 버전, 확장 기능, 타원 곡선, ALPN 값을 설명하는 ClientHello 패킷입니다. 이러한 속성의 정확한 목록과 순서는 구현에 따라 다릅니다. Chrome의 ClientHello는 Firefox의 것과 다르고, Firefox의 것은 curl의 것과 다르며, curl의 것은 Python의 `requests` 라이브러리의 것과 다릅니다.

JA3(및 그 후속 버전인 JA4)는 ClientHello의 구조를 짧은 식별자로 변환하는 해시 형식입니다. 안티봇 벤더는 들어오는 모든 TLS 연결에 대해 이 해시를 계산하고 알려진 시그니처와 대조합니다. 스크레이퍼가 Python `requests`를 사용하는 경우, TLS 지문이 OpenSSL 기본값과 일치하여 단 하나의 HTTP 바이트도 보내기 전에 '실제 브라우저가 아님'으로 즉시 식별됩니다.

이것이 IP와 User-Agent가 올바르게 보이더라도 많은 스크레이퍼가 Cloudflare, Akamai 및 유사한 스택에서 실패하는 이유입니다. TLS 계층은 요청이 Chrome에서 온 것이 아님을 드러냅니다. 최신 스텔스 라이브러리(`curl_cffi`, `tls-client`, 적절한 실행 플래그를 사용한 Playwright 등)는 이를 피하기 위해 실제 브라우저의 TLS 지문을 모방합니다.

작동 방식

JA3는 ClientHello의 다섯 가지 필드, 즉 TLS 버전, 지원되는 암호 스위트, 지원되는 확장, 지원되는 타원 곡선, 지원되는 타원 곡선 점 형식으로 지문을 구성합니다. 이를 결합하여 MD5 해시를 생성하고 32자 시그니처를 만듭니다.

JA4(현대적 대체 방식)는 여기에 ALPN, 버전, SNI 존재 여부, GREASE 처리 방식을 추가하고, 무작위화에 강한 안정적인 방식으로 확장을 정렬합니다. JA4에는 QUIC(JA4Q), HTTP(JA4H), SSL 세션(JA4S)용 변형도 있습니다. 서버는 지문을 계산하여 허용/차단 목록과 대조하거나 다른 신호와 함께 위험 점수 모델에 입력합니다.

타입

JA3

원본 TLS ClientHello 핑거프린트, 정렬된 cipher / extension / curve / format 필드의 MD5입니다. 널리 사용되지만 최신 브라우저의 extension 순서 무작위화에 취약합니다.

JA3S

JA3의 서버 측 대응물로, TLS ServerHello를 지문화합니다. 클라이언트가 아닌 서버 소프트웨어 스택을 식별하는 데 사용됩니다.

JA4

JA3의 최신 후속작입니다. GREASE, 무작위화, 확장 순서를 더 견고하게 처리합니다. JA4(TCP), JA4Q(QUIC), JA4H(HTTP), JA4L(지연 시간), JA4T(TCP 핑거프린트), JA4X(X.509 인증서)로 분리됩니다.

Akamai BMP / Datadome / Cloudflare bot.management

JA3/JA4를 기반으로 추가 신호(TLS 확장 순서 랜덤화 특이점, GREASE 바이트 검사, 패킷 타이밍)를 더한 독자적인 안티봇 핑거프린트입니다. 실제 브라우저를 사용하지 않고는 위조가 사실상 불가능합니다.

일반적인 사용 사례

HTTP 계층 이전에 HTTP 클라이언트(curl, requests, Python http.client)를 식별
TLS 계층에서의 봇 방어
네트워크 포렌식 및 IDS 규칙
클라이언트 유형별 속도 제한
커스텀 또는 변형된 스크래핑 클라이언트 감지
자주 묻는 질문

자주 묻는 질문

다음에 대한 일반적인 질문 tls 핑거프린트.

User-Agent는 클라이언트가 평문으로 전송하는 HTTP 헤더이므로 원하는 대로 설정할 수 있습니다. JA3는 TLS 핸드셰이크 자체의 구조에서 계산되므로 헤더를 설정하는 것만으로는 변경할 수 없습니다. JA3를 변경하려면 기본 TLS 클라이언트 라이브러리나 그 설정을 변경해야 합니다.

TLS 지문 불일치 가능성이 높습니다. Python `requests`는 urllib3의 TLS 스택을 사용하는데, 이는 Chrome과 일치하지 않는 JA3/JA4를 생성합니다. Cloudflare는 User-Agent가 Chrome이라고 표시되어 있어도 이를 탐지합니다. 이를 해결하려면 Chrome의 TLS를 위장하는 `curl_cffi`를 사용하거나 Playwright/Puppeteer를 통해 실제 브라우저를 실행하세요.

실제 Chrome / Edge / Firefox / Safari는 각각 고유한 JA3를 가지고 있습니다(그리고 단순한 차단 목록을 무력화하기 위해 약간씩 무작위화합니다). curl, wget, Python requests, Go의 net/http, Node의 https, OkHttp, Java HttpClient 등 수십 가지 도구는 각각 식별 가능한 고유 JA3를 가지고 있습니다. 이를 정리한 공개 데이터베이스(ja3er.com, abuse.ch)도 존재합니다.

`curl_cffi`(Python), `cycletls`(Go), `tls-client`(Go/Python)와 같은 TLS 위장 HTTP 클라이언트를 사용하거나 Playwright/Puppeteer를 통해 실제 Chromium 브라우저를 실행하세요. 이러한 라이브러리는 Chrome의 정확한 ClientHello 구조를 재현하여 JA3/JA4가 Chrome과 일치하도록 만들어 스크립트임을 드러내지 않습니다.

최신 Chrome은 이미 캐싱과 핑거프린팅을 어렵게 만들기 위해 GREASE 확장을 통해 ClientHello를 무작위화합니다. JA4는 이를 처리하도록 설계되었습니다. 클라이언트 측에서의 단순한 무작위화는 결과가 실제 브라우저와 다르게 보이기 때문에 오히려 식별을 더 쉽게 만드는 경우가 많습니다. 대신 실제 브라우저의 JA3를 매칭하세요.

간접적으로 그렇습니다. 프록시는 TLS 지문을 변경하지 않습니다. 클라이언트는 여전히 목적지와 종단 간 TLS 핸드셰이크를 수행합니다. 하지만 레지덴셜 IP는 기본적인 의심 수준을 낮추므로, 레지덴셜 IP에서 나온 비Chrome JA3는 안티봇 시스템에서 때때로 허용되는 반면, 데이터센터 IP에서 나온 동일한 JA3는 즉시 차단됩니다. 그럼에도 불구하고 두 계층을 모두 수정하는 것이 올바른 해결책입니다.