
curl과 비슷하지만 Anubis 및 Cloudflare 봇 차단을 우회합니다.
$ nix run github:fzakaria/anubis-fetch -- --text https://lore.kernel.org/
Anubis 작업증명(proof-of-work) 챌린지 뒤에 있는 URL을 가져오기 위한 Go CLI입니다. 레거시 SHA-256 및 WASM 챌린지를 프로세스 내에서 해결하며, 헤드리스 Chromium을 폴백으로 사용합니다.
lore.kernel.org 및 kernel.org와 같은 사이트는 페이지를 제공하기 전에 작업증명을 요구하기 위해 Anubis를 사용합니다. 일반 HTTP 클라이언트는 요청한 콘텐츠 대신 챌린지 페이지를 받을 수 있습니다. anubis-fetch는 챌린지를 해결하고, 답을 제출한 뒤, 결과 페이지를 stdout에 씁니다.
req를 사용하여 Chrome의 TLS 및 HTTP/2 지문을 모방합니다. 이는 Cloudflare를 포함한 수동적 봇 검사에 도움이 될 수 있습니다. Anubis의 fast 및 slow 방식의 경우, 이 도구는 nonce를 계산하고 답을 직접 제출합니다. WASM 방식인 sha256, argon2id, hashx의 경우, 사이트의 모듈을 다운로드하여 wazero로 Go에서 실행합니다.chromedp로 구동되는 헤드리스 Chromium이 사이트에서 제공하는 챌린지 코드를 실행합니다.브라우저 폴백은 Anubis의 preact 및 metarefresh 방식과 Cloudflare 챌린지 페이지(cf-mitigated: challenge 응답)를 처리합니다. 또한 레거시 SHA-256 난이도가 한계를 초과하거나, WASM 실행이 실패 또는 시간 초과되거나, Anubis가 해답을 거부할 때도 폴백합니다. --browser를 사용하면 Chromium으로 시작하고, --no-browser를 사용하면 HTTP 경로를 요구합니다. 세 가지 WASM 방식 모두 --no-browser와 함께 작동합니다.
네이티브 솔버는 가져오기마다 브라우저 프로세스를 시작하는 것을 피합니다. 폴백이 필요한 챌린지를 위해 Chromium은 여전히 Nix 패키지에 포함되어 있습니다.
원래 SHA-256 경로의 대략적인 가져오기 시간:
| 경로 | 실제 시간 | Chromium 필요 |
|---|---|---|
| 프로세스 내 SHA-256 솔버 | ~0.6s | 아니오 |
| 브라우저 폴백 | ~2.0s | 예 |
난이도 2의 로컬 Anubis 서버에 대한 WASM 가져오기 시간:
| WASM 방식 | 중앙값 실제 시간 | Chromium 필요 |
|---|---|---|
| SHA-256 | ~0.025s | 아니오 |
| Argon2id | ~0.55s-2.33s | 아니오 |
| HashX | ~0.041s | 아니오 |
fast 및 slow 방식의 경우, Anubis는 챌린지를 페이지에 포함합니다:
{"rules":{"algorithm":"fast","difficulty":4},
"challenge":{"id":"...","method":"fast","randomData":"6214bd88...","difficulty":4}}
솔버는 hex(sha256(randomData || nonce))가 difficulty개의 0 문자로 시작하는 nonce를 찾습니다. nonce는 십진수 문자열로 인코딩됩니다. 답은 Anubis에 제출됩니다:
GET /.within.website/x/cmd/anubis/api/pass-challenge?id=...&response=<hash>&nonce=<n>&redir=<url>&elapsedTime=<ms>
성공적인 응답은 인증 쿠키를 설정하고 요청한 페이지로 리디렉션합니다. 난이도 4는 평균적으로 약 65,536개의 해시를 필요로 합니다.
sha256, argon2id, hashx의 경우, Anubis는 작업증명을 구현한 WebAssembly 모듈을 제공합니다. anubis-fetch는 모듈을 다운로드하고, 챌린지의 16진수 데이터를 바이트로 디코딩한 뒤, 데이터와 난이도를 모듈에 전달합니다. 모듈은 nonce를 검색하고 위의 동일한 엔드포인트에 제출할 nonce와 해시를 반환합니다.
모듈은 wazero를 사용하여 Go 프로세스 내에서 실행되므로, 이러한 방식은 --no-browser와 함께 작동합니다. 실행에는 메모리 및 시간 제한이 있습니다. 난이도 규칙은 모듈이 정의하며, WASM 난이도 숫자는 레거시 SHA-256 방식과 직접 비교할 수 없습니다.
직접 실행:
$ nix run github:fzakaria/anubis-fetch -- <url>
또는 flake에 입력을 추가:
{
inputs.anubis-fetch.url = "github:fzakaria/anubis-fetch";
}
inputs.anubis-fetch.packages.${system}.default를 home.packages 또는 environment.systemPackages에 추가하세요.
anubis-fetch [flags] URL
| 플래그 | 효과 |
|---|---|
--text | HTML을 일반 텍스트로 변환 |
--timeout MS | 단계별 타임아웃을 밀리초로 설정; 기본값 30000 |
--ua STRING | User-Agent 설정 |
--browser | Chromium을 직접 사용 |
--no-browser | HTTP 솔버가 브라우저 폴백을 필요로 하면 종료 코드 3으로 종료 |
--no-cache | 저장된 쿠키 읽기 및 쓰기 비활성화 |
--help, -h | 사용법을 출력하고 종료 |
# HTML을 stdout으로
anubis-fetch https://lore.kernel.org/
# 일반 텍스트
anubis-fetch --text https://lore.kernel.org/
# HTTP 경로를 요구; 종료 상태 3 확인
anubis-fetch --no-browser https://lore.kernel.org/
쿠키는 호스트별로 $XDG_CACHE_HOME/anubis-fetch/cookies/<host>.json에 저장되며, XDG_CACHE_HOME이 설정되지 않은 경우 ~/.cache/anubis-fetch/cookies/<host>.json에 저장됩니다. 유효한 인증 쿠키가 있으면 이후 요청에서 챌린지를 건너뛸 수 있습니다. Chromium을 통해 얻은 쿠키도 Chromium의 User-Agent와 함께 저장됩니다. Cloudflare는 cf_clearance를 이를 획득한 User-Agent에서만 인정하므로, 이후 해당 호스트에 대한 HTTP 요청은 --ua로 재정의하지 않는 한 저장된 User-Agent를 전송합니다.
--no-cache를 사용하면 저장된 쿠키 없이 가져오거나, 호스트의 파일을 삭제하여 쿠키를 폐기할 수 있습니다. 만료되거나 거부된 쿠키는 새로운 챌린지를 필요로 합니다.
$ nix develop # Go, gopls, Chromium, treefmt
$ go test ./... # Go 단위 테스트
$ nix build # 패키징된 CLI
$ nix flake check # 빌드, 테스트, 포매팅
$ nix fmt # Go 및 Nix 포매팅