
스택의 모든 계층에서 요청을 Chrome 브라우저로 완벽하게 위장하는 차세대 HTTP 스텔스 프록시입니다.
"믿을 수가 없군, 열광학 위장이라니!"
이것은 JA4+ 같은 핑거프린팅을 사용해 특정 HTTP 클라이언트를 차단하는 서비스를 우회하도록 설계된 HTTP 프록시입니다. 이 프록시를 사용하면 curl 같은 선호하는 HTTP 클라이언트를 계속 사용하면서도 실제 (Chrome/Chromium) 웹 브라우저와 불가능할 정도로 구별할 수 없는 핑거프린트를 가질 수 있습니다. thermoptic에는 JavaScript 기반 핑거프린팅을 완화하기 위한 재미있는 기능도 포함되어 있습니다. 또한 웹 브라우저와 저수준 HTTP 클라이언트를 함께 사용하는 하이브리드 스크래핑을 쉽게 만들어 줍니다.
JA4+ 핑거프린팅에 익숙하지 않더라도, 스크래핑을 해본 적이 있다면 아마 한 번쯤 이로 인해 차단당한 경험이 있을 것입니다. Cloudflare 같은 인기 서비스는 이러한 기법(및 다른 트릭)을 사용해 "비인간" HTTP 클라이언트의 사용을 감지하고 요청을 차단합니다. 이러한 서비스는 실제 브라우저로 세션을 시작한 다음 나중에 curl 같은 저수준 클라이언트로 전환하는 것도 핑거프린팅으로 감지할 수 있습니다. thermoptic은 모든 스크래핑 요청에 통일된 "실제" 브라우저 핑거프린트를 제공함으로써 이러한 모든 문제를 해결합니다.
다음은 프록시를 사용하지 않은 curl의 JA4H(HTTP) 핑거프린트 예시입니다.```
$ curl https://ja4db.com/id/ja4h/
ge11nn090000_b6a016211e8a_000000000000_e3b0c44298fc
이것은 Chrome에서 URL을 직접 방문할 때 생성되는 지문과는 상당히 다릅니다:```
ge11cn19enus_f2808f0d04cf_9a10d4221160_7068f58def6e
하지만 프록시를 사용하여 요청을 하면, 우리의 JA4H 지문은 마술처럼 동일합니다:``` $ curl --proxy http://thermoptic:1234 https://ja4db.com/id/ja4h/ ge11cn19enus_f2808f0d04cf_9a10d4221160_7068f58def6e
(우리의 JA4 TLS 지문도 역시 마찬가지입니다).
## 설정
Ubuntu 22.04에서 컨테이너화된 Chrome 인스턴스를 통해 트래픽을 위장하는 `thermoptic` 프록시를 시작하려면:
일반 Docker 설정(GPU 런타임이 없는 호스트에서 작동):```
docker compose up --build
그게 전부입니다. 이제 이를 통해 트래픽을 프록시할 수 있습니다:``` curl --proxy http://127.0.0.1:1234 --insecure https://ja4db.com/id/ja4h/
Important notes:
* 기본적으로 프록시는 인증 없이 실행됩니다. 프록시를 외부에 노출할 계획이라면 환경 변수 `PROXY_USERNAME` 및 `PROXY_PASSWORD`를 사용하여 인증을 설정해야 합니다.
* `---insecure`를 사용하지 않으려면 `./ssl/rootCA.crt`에 있는 생성된 CA 파일을 사용해야 합니다. 이 파일은 `thermoptic`을 처음 실행할 때 생성됩니다.
* `thermoptic`을 `--remote-debugging-port` 플래그와 함께 시작된 모든 Chrome/Chromium 인스턴스에 연결할 수 있습니다. 지문을 가능한 한 눈에 띄지 않게 유지하려면 더 일반적으로 사용되는 환경(예: Windows의 Chrome)을 통해 프록시를 설정하고 사용하는 것이 필수적입니다.
* GPU compose override는 Docker의 NVIDIA 런타임/툴킷이 이미 설치된 NVIDIA 호스트를 위한 것입니다. GPU 장치를 예약하고 `/dev/dri`를 마운트하며 번들로 제공되는 Chrome 컨테이너가 NVIDIA/Vulkan 렌더링 경로로 전환할 수 있게 합니다. 이 기능을 사용하려면 `docker compose -f docker-compose.yml -f docker-compose.gpu.yml up --build`를 실행하세요.
## 기능
- 🕵️ 실제 Chrome 세션을 통해 요청을 재생하여 JA4 지문을 바이트 단위로 일치시키는 [브라우저 패리티 프록시](#how-does-this-cloaking-work-exactly).
- 🤝 `thermoptic`과 HTTP 클라이언트(예: `curl`, `requests` 등)를 통합하는 데 사용자 정의 코드가 거의 또는 전혀 필요하지 않습니다. [프록시 설정](#setup)만 하면 지문 처리가 자동으로 처리됩니다.
- 🪝 요청 전/요청 후/시작 시 자동화를 위한 [Hook 프레임워크](#handling-browser-javascript-fingerprinting-with-thermoptic-hooks)로, 전체 브라우저를 구동하여 챌린지를 해결하거나 아티팩트를 캡처할 수 있습니다.
- 📘 Cloudflare turnstile 해결 hook의 예시는 [`./hooks/onstart.js`](https://github.com/mandatoryprogrammer/thermoptic/blob/main/hooks/onstart.js)에서 볼 수 있습니다.
- 🖥️ Dockerized Chrome 브라우저 창을 제어하기 위한 [웹 브라우저 제어 UI](#control-the-dockerized-chrome-browser-via-web-ui-xpra) (`http://127.0.0.1:14111`). 사이트에 수동으로 로그인한 다음 로그인된 세션으로 프록시를 사용해 자연스럽게 요청을 보내는 데 유용합니다(및 디버깅에도 유용).
- 🔌 `docker-compose.yml`의 `UPSTREAM_PROXY` 환경 변수를 통해 업스트림 HTTP 또는 SOCKS 프록시 URI를 설정합니다.
- 🛡️ 운영자의 수동 관리 없이 멈춘 브라우저를 감지하고 자동으로 복구하는 내장 상태 확인 및 재시작 제어 루프.
- ⚡ HTTP/1.1 및 HTTP/2를 지원하며 두 프로토콜 모두를 통해 트래픽을 프록시할 수 있습니다. (_프록시에는 HTTP/1.1로 통신할 수 있지만, 제어되는 Chrome은 대상 사이트와 다른 프로토콜로 협상할 수 있습니다._)
## 이 클로킹은 정확히 어떻게 작동하나요?

* `thermoptic`이 프록시로 설정된 상태에서 `curl`과 같은 HTTP 클라이언트를 사용하여 HTTP 요청이 이루어집니다.
* `thermoptic`은 요청을 분석하여 어떤 유형의 브라우저 요청이어야 하는지 가장 잘 판단합니다(예: 수동 URL 방문? 양식 제출? `fetch()` 요청?).
* `thermoptic`은 [Chrome 디버깅 프로토콜 (CDP)](https://chromedevtools.github.io/devtools-protocol/)을 사용하여 브라우저를 조종하고 실제 웹 브라우저에서 일반적으로 발생하는 것과 똑같이 요청을 모방하는 페이지를 설정합니다.
* `thermoptic`은 모킹된 컨텍스트를 통해 요청을 트리거하고 HTTP 응답을 캡처합니다.
* `thermoptic`은 HTTP 응답을 클라이언트에 다시 보냅니다.
브라우저가 전체 스택을 사용하여 실제로 요청을 수행하기 때문에 결과적으로 생성되는 JA4 지문은 동일합니다.
참고: 많은 WAF가 웹 브라우저에 대한 JavaScript 수준의 지문 인식을 사용하기 때문에 `thermoptic`은 스크래핑 프로세스의 주요 단계에서 브라우저를 활용할 수 있는 hook도 제공합니다. 자세한 내용은 [이 섹션](#handling-browser-javascript-fingerprinting-with-thermoptic-hooks)을 참조하세요.
## 왜 다른 솔루션 대신 *이* 접근 방식인가요?
솔직히 말해서, 다른 접근 방식은 브라우저 지문 인식 문제에 대한 실용적인 장기 솔루션이 되지 못하게 하는 근본적인 결함이 있습니다.
브라우저 JA4+ 지문 인식을 "이겨내려는" 많은 다른 시도는 브라우저 스택의 다양한 계층을 재구현하는 방식으로 이루어집니다. 이 접근 방식에는 다음과 같은 여러 심각한 단점이 있습니다:
* "실제" 브라우저 구현의 동작을 완벽하게 일치시키기 위해 세심한 주의가 필요합니다. 결과적으로 *어떤* 특이한 동작이나 차이점이라도 이러한 클라이언트를 "실제" 브라우저 구현과 구별하는 데 사용될 수 있습니다.
* 스택의 한 계층에서만 문제를 해결하려고 시도합니다. Chrome은 웹 브라우징 경험을 제공하기 위해 여러 프로토콜을 사용합니다. 결과적으로 TLS 계층을 완벽하게 일치시키더라도 HTTP 계층이 바이트 단위로 완벽하지 않으면 정체가 드러날 수 있습니다.
* "실제" 브라우저는 정기적으로 동작을 변경하므로 지문도 변경되며, 그 결과 이러한 도구는 이를 보완하기 위해 지속적으로 더 집중적인 개발 작업이 필요합니다.
대조적으로, `thermoptic`은 HTTP 요청을 수행하기 위해 브라우저 자체를 사용하기 때문에:
* TCP, TLS, HTTP와 같은 스택의 각 계층은 요청이 *일반적으로* 발생하는 방식으로 *실제* 브라우저를 사용하여 만들어지기 때문에 실제 브라우저와 구별할 수 없습니다.
* 다양한 계층에서 브라우저 동작의 변경은 최소한의 영향만 미치며, `thermoptic`이 제어하는 브라우저만 최신 지문 세트에 맞게 업데이트하면 됩니다.
물론, 어떤 솔루션에도 단점이 없는 것은 아닙니다. `thermoptic` 접근 방식의 단점에 대한 자세한 목록은 `DOWNSIDES.md` 문서를 참조하세요.
## FAQ
### 왜 이름이 `thermoptic`인가요?
"Thermoptic"("thermoptic camouflage"의 약자)은 [Ghost in the Shell (1995) 애니메이션에서 Major가 사용한](https://ghostintheshell.fandom.com/wiki/Thermoptic_camouflage) 가상의 위장술을 참조한 것입니다. 영화에서 이 위장술은 가시광선과 열복사를 포함한 여러 감지 스펙트럼에서 착용자를 숨길 수 있는 것으로 묘사됩니다. 마찬가지로 이 도구는 HTTP, TLS 등 여러 채널에서 지문 인식을 피해 사용자를 숨기려고 시도합니다.
### JA4+는 지문의 **모음(suite)**입니다! 어떤 것들을 스푸핑하나요?
이 도구는 연결된 Chrome/Chromium 브라우저와 정확히 동일하도록 다음 JA4 지문을 스푸핑합니다:
* JA4 (TLS 지문)
* JA4H (HTTP 지문)
* JA4X (X509 TLS 인증서 지문)
* JA4T (TCP 지문)
### 다른 업스트림 HTTP/SOCKS 프록시를 사용하고 싶으면 어떻게 하나요?
`thermoptic`은 이제 제어되는 Chrome 인스턴스를 내부 `proxyrouter` 서비스를 통해 라우팅하므로 Chrome을 업스트림 HTTP 또는 SOCKS 프록시(자격 증명이 필요한 프록시 포함)로 지정할 수 있습니다. `docker-compose.yml`의 `proxyrouter` 서비스 아래에서 `UPSTREAM_PROXY` 값을 편집하여 업스트림 프록시 URI를 설정하세요. 이 값을 비워 두면 Chrome은 인증되지 않은 클러스터 내 프록시를 통해 인터넷에 직접 연결됩니다.
업스트림 SOCKS 프록시 설정 예시:```yaml
proxyrouter:
environment:
UPSTREAM_PROXY: "socks5://username:[email protected]:1080"
Be aware that some upstream proxies can change low-level fingerprints (for example, TCP metadata) which may reduce parity with a residential browser.
일부 업스트림 프록시는 저수준 지문(예: TCP 메타데이터)을 변경하여 일반 가정용 브라우저와의 일치도를 낮출 수 있다는 점에 유의하세요.
thermoptic은 클라이언트가 Cookie 헤더에 지정한 쿠키를 사용해 브라우저를 로드합니다. 그러면 요청이 브라우저 컨텍스트에서 실행될 때 이러한 쿠키가 포함됩니다. 이는 서버가 쿠키의 순서나 그와 유사한 값싼 속임수로 지문을 판별할 수 없도록 하기 위한 것입니다.
참고: 이 쿠키는 요청이 끝난 후에도 유지됩니다. 쿠키 정리 로직을 구현하려면 thermoptic 훅을 작성하세요.
네, thermoptic은 이와 같은 혼합 사용을 지원합니다. 자세한 내용은 이 섹션을 참조하세요.
X-Fetch-*, Origin, Referer 같은 헤더를 올바르게 설정해야 합니다. 이러한 헤더를 thermoptic에 알려주지 않으면 요청을 적절히 은밀한 방식으로 실행할 수 없습니다.
컨텍스트 헤더를 설정하지 않으면 thermoptic은 대상 사이트가 기대하는 것과 정확히 일치하지 않을 수 있는 기본값을 설정합니다. 예를 들어 Origin 헤더를 설정하지 않으면 Origin을 null로 설정하고, Referer 헤더를 설정하지 않으면 Referer를 전혀 보내지 않습니다.
요청이 가능한 한 은밀하게 이루어지도록 이러한 컨텍스트 헤더를 포함하는 것이 가장 좋습니다! thermoptic은 마음을 읽을 수 없고 요청만 읽을 수 있습니다 :).
일반적으로 이는 JavaScript/브라우저 수준 검사를 통과하기 위해 일시적으로 전체 웹 브라우저를 사용하는 thermoptic 훅의 경우에만 적용됩니다. 이러한 훅과 전체 브라우저 모드를 일시적으로 사용할 때는 봇으로 지문 판별되지 않도록 주의해야 합니다(예: Runtime.enable 같은 함정 피하기).
여기서 작용하는 윤리적 고려 사항과 복잡한 게임 이론은 README 하나로 답할 수 있는 것보다 훨씬 큽니다. 그래도 이메일/Twitter/Github으로 저를 비판할 때 다음의 지나치게 단순화된 항목 중 어느 하나에 대해 반박해 보세요:
스크래핑 군비 경쟁에 대한 더 많은 농담을 원하신다면 적어도 제게 맥주 한 잔은 사주시길 부탁드립니다. 솔직히 말하면, 저는 README에 이런 지루한 윤리 에세이를 쓰는 것을 싫어하니, 저를 당신의 삶을 더 힘들게 만들고 싶어 하는 사악한 너드라고 상상해도 좋습니다.
thermoptic 훅으로 브라우저 JavaScript 지문 판별 처리하기thermoptic을 사용하면 다음 시점에 브라우저 작업을 수행하도록 사용자 지정 스크립트를 구성할 수 있습니다:
ON_START_HOOK_FILE_PATH)BEFORE_REQUEST_HOOK_FILE_PATH)AFTER_REQUEST_HOOK_FILE_PATH)이를 통해 Chrome 디버깅 프로토콜을 사용해 클릭을 수행하고, 검증 단계에서 실제 웹 브라우저를 요구하는 사이트에 적절한 쿠키를 설정할 수 있습니다. 그런 다음 thermoptic 프록시를 사용해 동일한 브라우저를 통해 세션을 위장한 채 계속할 수 있습니다.
이렇게 하려면 적절한 훅 JavaScript 파일을 사용자 지정 코드로 수정하여 제공된 chrome-remote-interface 인터페이스를 통해 브라우저를 적절히 조율하세요:```
// cdp is an instance of a connected browser, use it to run your browser actions
export async function hook(cdp) {
console.log([STATUS] Browser start hook called successfully!);
}
예제 구현은 [`./hooks/onstart.js`](https://github.com/mandatoryprogrammer/thermoptic/blob/main/hooks/onstart.js) 파일을 참조하세요. 이 파일은 [Cloudflare turnstile CAPTCHA를 우회](https://github.com/mandatoryprogrammer/thermoptic/blob/main/tutorials/turnstile/cloudflare-turnstile-bypass.md)합니다(및 기타 Cloudflare 봇 방지 검사).
## Docker화된 Chrome 브라우저를 Web UI로 제어하기 (Xpra)
`thermoptic`에는 `http://127.0.0.1:14111`에서 사용할 수 있는 Xpra 웹 UI가 포함되어 있습니다. 이를 통해 Docker화된 Chrome 브라우저를 손쉽게 수동으로 제어할 수 있습니다:
<img src="https://assets.kitploit.com/production/public/readmes/49068/0fa1b187f46405dda2b0db5d461619daa6a7bdad2c385cb51994e870d9054d10.png" width="100%">
다음과 같은 작업에 유용합니다:
* `curl`과 같은 선호하는 HTTP 클라이언트를 사용해 `thermoptic`을 통해 인증된 요청을 보낼 수 있도록 계정에 로그인합니다.
* 예를 들어 브라우저에서 `reddit.com`에 로그인하면 `thermoptic`을 통해 Reddit에 보내는 모든 요청이 자동으로 귀하의 Reddit 계정으로 인증됩니다!
* 사용자 정의 `thermoptic` 훅을 디버깅하고 웹사이트의 문제를 확인합니다.
## 구성
다음 환경 변수는 `thermoptic`이 실행될 때 어떻게 구성되어야 하는지 지정합니다.
`HTTP_PROXY_PORT`: `thermoptic` 프록시가 수신 대기해야 하는 포트입니다. Docker에서 `thermoptic`을 실행하는 경우 `ports` 매핑 필드도 일치하도록 변경해야 합니다.
`CHROME_DEBUGGING_PORT`: Chrome 디버깅 프로토콜이 노출되는 포트입니다. 이 포트는 `--remote-debugging-port` 플래그를 `9222`와 같은 값으로 설정하여 Chrome/Chromium을 실행할 때 지정됩니다.
`CHROME_DEBUGGING_HOST`: Chrome 디버깅 프로토콜이 노출되는 호스트입니다. 브라우저가 로컬에서 실행되고 `thermoptic`이 Docker에서 실행되지 않는 경우 일반적으로 `127.0.0.1`입니다. Docker에서 실행 중이라면 `host.docker.internal`을 사용해야 할 수 있습니다. 자세한 내용은 [Docker 문서](https://docs.docker.com/desktop/features/networking/#i-want-to-connect-from-a-container-to-a-service-on-the-host)를 참조하세요.
`PORT`: Chrome 컨테이너가 나머지 스택에 게시하는 CDP 포트입니다. `socat` 브리지가 예상대로 계속 작동하도록 `CHROME_DEBUGGING_PORT`와 일치시켜 유지하세요.
`CHROME_CONTROL_PORT`: thermoptic이 브라우저를 관리하는 데 사용하는 Chrome 제어 서비스 포트입니다(예: 재시작 요청 전송).
`CHROME_CONTROL_COOLDOWN_MS`: Chrome 재시작 시도 사이의 최소 시간(밀리초)입니다. 여러 오류가 연속으로 빠르게 발생할 때 빠른 재시작 루프를 방지하는 데 사용합니다.
`ENABLE_GUI_CONTROL`: `true`로 설정하면 xpra 웹 패널이 실행되어 `http://127.0.0.1:14111`에 접속해 컨테이너화된 Chrome을 조작할 수 있습니다. 헤드리스 전용 실행에서는 비활성화하세요.
`CHROME_SCREEN_WIDTH` / `CHROME_SCREEN_HEIGHT`: Docker화된 headful Chrome 디스플레이의 픽셀 크기입니다.
`CHROME_ENABLE_GPU`: 번들로 제공되는 Chrome 컨테이너가 호스트 GPU 가속을 사용하려 시도할지 여부를 제어합니다. `auto`(기본값)는 필요한 런타임과 디바이스 노드가 있을 때 NVIDIA/Vulkan 경로를 활성화하고, 그렇지 않으면 소프트웨어 렌더링으로 대체합니다. `false`로 설정하면 기존의 소프트웨어 전용 동작을 강제합니다.
`CHROME_PROFILE_RECOVERY`: `true`(기본값)인 경우 번들 Chrome 실행기는 손상된 프로필에서 관찰된 것과 동일한 크래시 루프 종료 코드(`133`)로 Chrome이 즉시 종료되면 복구를 한 번 시도합니다. 잘못된 프로필 내용은 컨테이너 내부의 `/tmp/chrome-profile-recovery/` 아래로 이동된 후 깨끗한 프로필로 다시 시도합니다.
`PROXY_USERNAME`: 프록시에 대한 인증에 사용되는 사용자 이름이며 기본값은 `changeme`입니다. 설정하지 않으면 프록시는 인증 없이 실행됩니다.
`PROXY_PASSWORD`: 프록시에 대한 인증에 사용되는 비밀번호이며 기본값은 `changeme`입니다. 설정하지 않으면 프록시는 인증 없이 실행됩니다.
`THERMOPTIC_CONTAINER_RUNTIME`: thermoptic이 번들 컨테이너 내부에서 실행 중임을 나타냅니다. 이 값을 `true`로 유지하세요. 전체 Docker 설정에서만 의미가 있는 내장 상태 확인과 같은 동작을 제어합니다.
`HEALTHCHECK_ENDPOINT_PORT`: thermoptic이 상태 확인 웹 엔드포인트를 노출하는 포트입니다. 상태 확인 작업자가 프록시를 통해 이 엔드포인트를 호출합니다. 응답이 중지되면 Chrome이 자동으로 다시 시작되어 멈춘 세션을 해제합니다.
`HEALTHCHECK_ENDPOINT_PATH`: 위에서 설명한 상태 확인 엔드포인트가 제공하는 HTTP 경로입니다. 다른 URL이 필요하면 변경하세요.
`ON_START_HOOK_FILE_PATH`: 프록시 시작 시 실행할 사용자 정의 Node 코드입니다. 이 훅이 완료될 때까지 프록시는 수신 대기를 시작하지 않습니다. `./hooks/`의 예제를 참조하세요. 샘플은 프록시를 시작하기 전에 브라우저를 사용해 Cloudflare의 JavaScript 브라우저 검사를 클릭하여 통과하는 방법을 보여줍니다.
`BEFORE_REQUEST_HOOK_FILE_PATH`: 요청이 프록시되기 전에 실행할 사용자 정의 Node 코드입니다. 사이트 HTTP 요청이 이루어지기 전에 브라우저가 특정 검사를 통과해야 하는 경우 유용합니다.
`AFTER_REQUEST_HOOK_FILE_PATH`: 요청이 프록시된 후 실행할 사용자 정의 Node 코드입니다. 클라이언트가 `Cookie` 헤더를 통해 설정한 쿠키를 정리하는 등의 작업에 유용합니다.
`DEBUG`: 버그가 발생했을 때 `true`로 설정하면 이슈를 등록하기 전에 thermoptic이 상세 진단 정보를 출력합니다. 일반 운영 중에는 `false`로 유지하세요.
## 보안
현재 `thermoptic`은 명시적으로 신뢰하는 HTTP 클라이언트에서만 사용하도록 설계되었습니다. 신뢰할 수 없는 사용자에게 노출되어서는 *안* 됩니다.
보안 취약점이 발견되면 `mandatory@` Gmail로 보고서를 보내주세요.