
웹 앱이 전송하는 JavaScript에서 모든 API 요청을 찾아냅니다: 메서드, URL, 본문, 헤더 및 GraphQL 작업까지. 단 하나의 명령으로.
웹 앱이 배포하는 JavaScript에서 그 앱이 수행하도록 만들어진 모든 요청을 복원합니다: 메서드, URL, 본문, 콘텐츠 타입, 헤더.
단일 페이지 앱의 JavaScript 번들에는 그 앱이 수행할 수 있는 모든 API 요청이 들어 있습니다. URL이 주어지면 jshound는 앱의 번들을 찾아 지연 로드되는 청크를 포함한 전체를 크롤링하고, 그 요청들을 추출합니다.
수동적입니다. 수행하는 유일한 요청은 공개 정적 파일, 페이지 및 그 JavaScript에 대한 인증되지 않은 GET입니다. 분석은 로컬에서 실행되며, 앱의 API로 아무것도 전송되지 않습니다.
git clone https://github.com/AmbitSecurity/jshound && cd jshound
python3 -m venv .venv && source .venv/bin/activate
pip install -e .
Python 3.10 이상과 Node 18 이상이 필요합니다.
jshound supabase.com/dashboard
$ jshound supabase.com/dashboard
307 128B https://supabase.com/dashboard
200 19K https://supabase.com/dashboard/org
200 28K https://frontend-assets.supabase.com/studio/8617532ae1a4/_next/static/chunks/1p849pzlxcp4n.js?dpl=dpl_ESaSquAbnWrJqbvvyRh7F1qj5wWH
...
supabase.com 200 2282 files (2281 from frontend-assets.supabase.com, 1 from supabase.com) -> 387 endpoints
1 declared chunk(s) could not be fetched
-> .jshound/supabase.com/endpoints.txt (also requests.jsonl, urls.txt, openapi.json)
frontend-assets.supabase.com의 2,281개 파일도 포함됩니다.POST https://api.supabase.com/platform/auth/{ref}/otp {"phone":"state:phone"}
DELETE https://api.supabase.com/v1/projects/{param_n}/functions/{param_e}
DELETE https://supabase.com/dashboard/api/integrations/stripe-sync application/json {"projectRef":"input:e","startTime":"input:t"}
POST https://supabase.com/docs/api/search/fts application/json {"query":"computed:trim"}
여러 대상 동시에, 또는 stdin으로 목록 전달:
jshound app.example.com api.example.com
cat scope.txt | jshound
이전 실행의 js/ 폴더처럼 이미 디스크에 있는 파일은 네트워크를 건드리지 않고 읽습니다:
$ jshound examples/demo-app
GET https://demo-app.test/api/feature-flags
POST https://demo-app.test/t/events {"sid":"?","evt":"?"}
DELETE https://demo-app.test/v1/sessions/current
POST {baseUrl}/v1/media multipart/form-data {"file":"file-upload"}
POST {baseUrl}/v1/subscribe application/json {"email":"computed:trim","pageUri":"state:href"}
GET {baseUrl}/v1/users/{param_o}/profile
모든 것은 .jshound/<host>/ 또는 -o DIR로 저장됩니다:
endpoints.txt | 위의 표, 한 줄에 하나의 요청 |
requests.jsonl | 요청당 하나의 JSON 객체: method, url, body, content_type, headers, graphql 또는 rpc, 그리고 그것이 나온 페이지와 파일 |
urls.txt | 호스트가 알려진 요청에 대한 METHOD URL, 목록을 받는 도구용 |
openapi.json | Burp, Caido 또는 Postman에 가져올 OpenAPI 3 문서 |
js/ | 가져온 모든 파일 |
{...}**는 jshound가 해석할 수 없는 값으로, 코드가 쓰는 대로 기록됩니다: {baseUrl}, {window.__CONFIG__.apiBaseUrl}. 경로에서 {ref}는 파라미터이고, {param_o}는 함수 파라미터 o입니다./api/surveys/는 jshound가 아직 기반까지 따라가지 않는 코드를 거칩니다. requests.jsonl은 그것이 나온 파일을 알려줍니다.input: 인자, state: 객체의 속성, computed: 호출의 결과, ? 알 수 없음.application/json?**은 호출 지점에서 읽은 것이 아니라 파일의 다른 요청들로부터 추론된 콘텐츠 타입입니다. **~{...}**는 나열된 것보다 더 많은 필드를 가진 본문입니다.{graphql}**은 GraphQL 작업으로, 이름, 타입, 변수가 본문으로 들어갑니다.| bundler | lazy chunk URLs | module tree | how |
|---|---|---|---|
| webpack 5 | yes | yes | reads __webpack_require__.u out of the syntax tree |
| webpack 4 | yes | yes | has no .u, so the named URL builder is matched by shape rather than by name |
| Rspack | yes | yes | webpack-compatible, usually emitting ESM |
| Turbopack | yes | n/a | no builder at all; the chunk list is a literal array |
| Vite / Rollup | yes | n/a | paths are written down (__vite__mapDeps); flat ESM has no registry to walk |
| esbuild | yes | n/a | same |
| Parcel | yes | n/a | the runtime global is suffixed per build (parcelRequire5707) and the chunk table is an object, not an array |
| Metro (React Native) | n/a | n/a | ships one bundle, no chunks; detected by __METRO_GLOBAL_PREFIX__ |
| webpack Module Federation | yes | yes | the builder carries no id map, so ids are taken from the __webpack_require__.e(480) call sites |
jshound는 지정한 대상과 그 대상의 페이지가 로드하는 JavaScript 파일을, 호스팅 위치에 관계없이 요청합니다. supabase의 경우 대부분 frontend-assets.supabase.com입니다. 이들은 어떤 방문자의 브라우저든 다운로드하는 공개 정적 파일입니다. 그 다른 호스트들은 그 GET 외에는 아무것도 받지 않습니다.
대상이 사설 주소 공간(loopback, RFC1918, link local)에서 지정한 URL은 거부합니다. 단, 지정한 대상 자체가 사설이거나 --allow-private를 전달한 경우는 예외입니다.
-o DIR | 결과가 저장될 위치 (기본값 .jshound/<host>) |
-q | 요청이 이루어질 때마다 출력하지 않음 |
-v | 분석 로그도 출력 |
--max-chunks N | 이 개수의 지연 청크와 import 이후 중단 (기본값 50000) |
--no-chunks | 지연 청크를 따라가지 않음 |
--proxy URL | 모든 요청을 프록시를 통해 전송 (또는 JSHOUND_PROXY 설정) |
--proxy-ca FILE | TLS를 가로채는 프록시의 CA 인증서 |
--client PROFILE | 차단될 때 로테이션하는 대신 하나의 브라우저 TLS 프로필을 고정 |
--allow-private | 사설 주소 공간의 URL 허용 (범위 참조) |
blocked by Cloudflare를 보고하고 아무것도 읽지 않습니다. jshound는 curl_cffi가 아는 최신 Chrome, Firefox, Safari를 모방하므로 curl_cffi를 최신으로 유지하세요. --proxy는 속도 제한과 IP 차단에는 도움이 되지만 챌린지에는 도움이 되지 않습니다.document.createElement("script")로 삽입하는 스크립트, 즉 API 호출에서 얻은 URL을 사용하는 스크립트는 jshound가 다운로드하는 어떤 것에도 들어 있지 않습니다.CONTRIBUTING.md를 참조하세요.
MIT.