
CVE-2025-29927 스캐너입니다.
This is a professional-grade scanner designed to detect the CVE-2025-29927 middleware bypass vulnerability in Next.js applications.
X-Middleware-Subrequest 헤더를 사용하여 내부 경로를 테스트하여 Next.js 미들웨어를 우회합니다pip install -r requirements.txt playwright install
### 스캐너 실행```bash
python main.py --domain https://example.com --threads 10 --timeout 10 --save
python main.py --help
| Option | Description |
|----------------|--------------------------------------------|
| `--domain` | 대상 사이트 기본 URL (필수) |
| `--user-agent` | 사용자 지정 User-Agent (기본값: Chrome 문자열) |
| `--timeout` | 요청 타임아웃 (기본값: 10초) |
| `--proxy` | 프록시 주소 (선택 사항) |
| `--save` | 결과를 `results.txt`에 저장 |
| `--threads` | 스레드 수 (기본값: 10) |
| `--wordlist` | 공통 경로를 포함한 단어 목록 |
---
## 🐳 Docker 사용법
### Docker 이미지 빌드```bash
docker build -t cve-scanner .
docker run -it --rm cve-scanner --domain https://example.com --save
---
## ⚙️ GitHub Actions
이 프로젝트는 푸시 시 설정을 테스트하기 위한 GitHub Actions 워크플로우를 포함합니다. 다음을 수행합니다:
- 의존성 설치
- Playwright 브라우저 설치
- `--help` 확인 실행
`.github/workflows/python.yml` 파일을 참조하세요.
---
## 🧱 구조```
.
├── main.py # Entry point
├── config.py # CLI parser
├── crawler.py # Playwright crawler
├── scanner.py # Multi-threaded vulnerability testing
├── requirements.txt
├── Dockerfile
└── .github/workflows
CVE-2025-29927 취약점 개요
CVE-2025-29927은 공격자가 미들웨어 기반 인증 및 권한 부여를 우회할 수 있게 하는 치명적인 Next.js 보안 결함입니다. HTTP 요청에 특수 내부 헤더(X-Middleware-Subrequest)를 포함시킴으로써, 공격자는 Next.js 서버를 속여 미들웨어 실행을 건너뛰게 하여 보호된 라우트에 접근할 수 있습니다. 실제로 인증 미들웨어에 의해 일반적으로 차단되는 요청(예: 401/403 반환 또는 로그인 페이지로 리디렉션)은 이 헤더가 존재하면 정상적으로 처리되어 보안 검사를 효과적으로 우회합니다. 이 취약점은 Next.js 버전 11.1.4부터 15.2.2까지 영향을 미치며, 관리자는 애플리케이션을 보호하기 위해 패치를 적용하거나 완화 조치(예: 프록시에서 이 헤더 제거)를 구현할 것을 권장합니다.
웹 애플리케이션에서 이 취약점을 탐지하려면 내부 엔드포인트를 발견하고 악의적인 헤더로 테스트하여 무단 접근이 가능한지 확인해야 합니다. 아래는 대상 웹사이트를 크롤링하고(전체 JavaScript 지원) CVE-2025-29927을 스캔하는 고급 Python 스크립트의 설계 계획으로, 모든 명시된 요구사항을 충족합니다.
JavaScript로 렌더링된 콘텐츠를 포함한 심층 크롤링 요구사항을 충족하기 위해 Playwright를 사용합니다(속도와 현대적인 API로 인해 Selenium보다 선호됨). Playwright는 동적 웹 애플리케이션과 최신 JS 프레임워크를 처리할 수 있는 강력한 헤드리스 브라우저 자동화 라이브러리입니다. Selenium과 비교하여 Playwright는 더 현대적인 API(Chrome DevTools Protocol 기반)를 제공하며 동기 및 비동기 작동을 모두 지원하여 사용 사례에 더 나은 성능을 제공할 수 있습니다. 주요 라이브러리 및 설치 지침은 다음과 같습니다:
playwright – 헤드리스 브라우저 자동화용(SPA 또는 JS가 필요한 페이지 로드). (설치: pip install playwright 및 playwright install 실행하여 브라우저 바이너리 획득).
requests 또는 httpx – 스캐닝 단계에서 HTTP 요청 전송용. 단순성을 위해 requests를 사용하거나 비동기 지원을 위해 httpx/aiohttp를 사용할 수 있습니다. (설치: pip install requests 또는 pip install httpx).
bs4 (BeautifulSoup) – 필요 시 HTML 파싱 및 링크 추출용. Playwright는 DOM을 직접 쿼리할 수 있지만, 페이지의 HTML 콘텐츠에 BeautifulSoup을 사용하는 것이 앵커 태그를 찾는 간단한 방법입니다. (설치: pip install beautifulsoup4).
concurrent.futures (내장) 또는 asyncio – 동시성 구현용. 멀티스레딩을 위해 Python의 concurrent.futures.ThreadPoolExecutor를 사용합니다(추가 설치 불필요). 비동기 방식을 사용하는 경우 httpx와 함께 Python의 asyncio를 사용하여 병렬 요청을 수행할 수 있습니다.
(선택 사항) argparse – 대화형 메뉴 대신 CLI 인터페이스를 원할 경우 명령줄 인수 파싱용. (내장 모듈)
선정 이유: Playwright는 복잡한 설정 없이 동적 콘텐츠를 스크래핑할 수 있는 능력 때문에 선택되었습니다. "Playwright를 사용하면 헤드리스 브라우저를 자동화하여... 사람처럼 웹을 탐색할 수 있으므로 동적 JavaScript 기반 웹사이트를 스크래핑하는 데 탁월합니다". 이를 통해 크롤러가 스크립트에 의해 생성된 링크나 UI 요소(단순한 requests 기반 크롤러는 놓칠 수 있는)를 볼 수 있습니다.
크롤러 모듈은 Playwright를 헤드리스 모드로 사용하여 대상 사이트의 심층 크롤링을 수행합니다. 목표는 JS 실행 후에만 드러나는 경로를 포함하여 테스트할 내부 경로(엔드포인트)를 발견하는 것입니다. 크롤러의 주요 설계 사항:
헤드리스 브라우저 탐색: Playwright를 통해 헤드리스 모드로 브라우저 인스턴스(예: Chromium)를 시작합니다. 사용자가 지정한 경우 사용자 정의 User-Agent로 브라우저 컨텍스트를 사용합니다(자세한 내용은 다음 섹션에서). 예를 들어, browser.new_context(user_agent=<user_agent_string>)로 컨텍스트를 생성하여 선택한 User-Agent를 에뮬레이트할 수 있습니다. 프록시가 구성된 경우 시작 시 적용합니다(Playwright는 브라우저 또는 컨텍스트 시작 시 프록시 서버 설정을 허용합니다).
재귀적 크롤링 전략: 주어진 기본 URL(시드)에서 시작합니다. page.goto(base_url, timeout=<T>)를 사용하여 페이지를 로드합니다(timeout 설정 가능). 네트워크가 유휴 상태가 될 때까지 기다리거나 필요 시 동적 콘텐츠 로드를 위해 짧은 지연을 추가합니다. 그런 다음 링크를 추출합니다. 링크 추출 방법은 두 가지입니다:
links = page.evaluate("Array.from(document.querySelectorAll('a[href]'), a => a.href)")), 또는<a href> 속성을 찾습니다.링크 필터링: 대상 도메인 내에 있지 않은 링크를 필터링하여 내부 링크만 유지합니다. 또한 이미지, CSS, JS 등과 같은 정적 파일 URL을 무시합니다. 예를 들어, .css, .js, .jpg, .png, .gif, .svg, .woff 등의 파일 확장자를 가진 URL을 건너뜁니다. 실용적인 접근 방식(ProjectDiscovery 템플릿에서 영감을 얻음)은 초기 슬래시 이후에 '점(dot)'을 포함하는 경로를 무시하는 것입니다. 그들은 정규식 패턴 href=['"](https://github.com/houmanpashaei/cve-2025-29927/blob/main/%5C/%5B%5E.%5C%22%27%5D%2B)['"]로 엔드포인트를 추출했습니다. 이는 마침표를 포함하지 않는 내부 경로를 캡처하므로 정적 자원을 건너뜁니다. 코드에서 유사한 로직을 구현하여 정적 리소스나 외부 링크를 큐에 넣지 않도록 합니다.
추적 및 깊이 제어: 무한 루프나 반복을 방지하기 위해 방문한 URL 집합을 유지합니다. 사이트 링크 그래프의 BFS 탐색을 위해 큐(FIFO)를 사용합니다. 선택적으로 사용자가 크롤링 깊이 제한 또는 방문할 최대 페이지 수를 지정하여 대규모 사이트에서 무한 실행을 방지할 수 있습니다.
JavaScript 렌더링 콘텐츠: 실제 브라우저를 사용하기 때문에 스크립트에 의해 DOM에 추가된 링크(예: 데이터를 가져온 후 메뉴를 렌더링하는 React 앱)도 크롤러에 표시됩니다. 필요한 경우 클릭이나 상호작용을 고려할 수 있습니다(예: 특정 페이지가 사용자 작업 후에만 로드되는 경우). 그러나 단순성과 속도를 유지하기 위해 초기 설계는 각 로드된 페이지에서 hrefs를 수집하는 데 중점을 둡니다. 대상 애플리케이션이 요구하는 경우 나중에 무한 스크롤이나 클릭 뒤의 콘텐츠를 처리하도록 개선할 수 있습니다.
효율성: Playwright는 비동기 API를 사용하여 여러 페이지/탭을 병렬로 실행하는 것을 지원합니다. asyncio.gather로 여러 페이지를 인스턴스화하여 여러 링크를 동시에 가져올 수 있습니다. 초기 구현에서는 순차적으로 크롤링하는 더 간단한 접근 방식(구현이 더 쉬움)을 사용하고 성능을 위해 멀티스레드 스캐닝에 의존합니다. 필요한 경우 고급 최적화는 비동기 크롤링(async with async_playwright() 사용 및 여러 page.goto 호출 대기)을 포함할 수 있습니다. 그러나 브라우저 자동화는 리소스를 많이 사용하므로 시스템에 과부하를 주지 않도록 한 번에 하나 또는 몇 개의 브라우저 페이지만 유지하는 신중한 접근이 좋습니다.
스크립트는 시작 시 사용자 친화적인 설정 메뉴를 제공하여 사용자가 스캐닝 매개변수를 사용자 정의하거나 기본값을 수락할 수 있도록 합니다. 이는 대화형 콘솔 메뉴(input() 프롬프트 사용) 또는 명령줄 인수(보다 전문적인 CLI 느낌을 위해 argparse 사용)를 통해 수행할 수 있습니다. 옵션은 다음과 같습니다:
사용자 정의 User-Agent: 사용자는 크롤러와 스캐너가 사용할 사용자 정의 User-Agent 문자열을 지정할 수 있습니다. 이는 Playwright 브라우저 컨텍스트와 모든 직접 HTTP 요청에 적용됩니다. 기본값이 아닌 User-Agent를 사용하면 간단한 봇 탐지를 피하는 데 도움이 될 수 있습니다. (기본적으로 Playwright는 식별 가능한 것을 사용할 수 있습니다; 위에서 보여준 것처럼 쉽게 재정의할 수 있습니다.) 예를 들어, 사용자는 Windows의 Chrome으로 식별되는 문자열을 입력할 수 있으며, 이를 Playwright의 컨텍스트 생성에 전달합니다.
요청 시간 제한: 사용자는 페이지 로드 및 HTTP 요청에 대한 시간 제한(초)을 설정할 수 있습니다. 이는 스캐너가 응답하지 않는 엔드포인트에서 너무 오래 대기하는 것을 방지합니다. 크롤링의 경우 page.goto(timeout=...)에, 스캐닝의 경우 요청(예: requests.get(timeout=...))에 이 설정을 적용합니다.
프록시 설정: 사용자가 트래픽을 프록시를 통해 라우팅하려는 경우(익명성 또는 내부 호스트 접근을 위해), 프록시 URL(필요시 자격 증명)을 입력할 수 있습니다. 스크립트는 Playwright 브라우저가 시작 시 이 프록시를 사용하도록 구성합니다(예: browser.launch(proxy={"server": "http://<proxy_host>:<port>", "username": "...", "password": "..."}) (예제에 표시된 대로). 마찬가지로 요청의 경우 프록시 매개변수(또는 환경 변수)를 적절히 설정합니다.
(선택 사항) rich 또는 colorama – 가독성을 높이기 위한 색상 또는 형식화된 콘솔 출력용. (설치: pip install rich 또는 pip install colorama).
파일 출력: 메뉴는 사용자가 결과를 파일(예: results.txt)에 저장할지 묻습니다. 저장하는 경우 스크립트는 발견된 취약한 엔드포인트와 세부 정보를 화면 출력 외에도 이 파일에 기록합니다. 그렇지 않은 경우 결과는 stdout에만 출력됩니다. (필요 시 모든 스캔된 경로를 상세 로그에 기록할 수 있지만, 파일은 사용자 선호도에 따라 긍정 결과나 전체 보고서를 특별히 기록합니다.)
기타 옵션: 디버그 로깅을 위한 'Verbose 모드' 또는 필요 시 '최대 크롤링 깊이/페이지'와 같은 토글을 포함할 수 있습니다. 이는 사용자가 스캔을 세밀하게 조정하는 데 도움이 됩니다. 초기 범위에서는 위의 네 가지 주요 옵션으로 충분합니다.
메뉴 시스템은 전용 설정/준비 모듈에 구현됩니다. 이는 프롬프트를 출력하고 입력을 수집하는 함수로, 사용자가 Enter를 누르면 적절한 기본값(예: 기본 user-agent는 표준 값, 기본 시간 제한 = 10초, 프록시 없음, 파일 출력 없음)을 사용합니다. 이는 상호작용을 명확하게 유지하고 나중에 명령줄 인수를 추가하면 인수를 통해 필요한 모든 설정을 제공하여 대화형 프롬프트를 건너뛸 수 있으므로 스크립트를 비대화형으로도 실행할 수 있습니다.
성능은 스캐너에 매우 중요하며, 특히 많은 엔드포인트가 발견되는 경우 더욱 그렇습니다. 스크립트는 속도를 위해 멀티스레딩 또는 asyncio(또는 이들의 조합)를 통해 동시성을 활용합니다:
멀티스레드 스캐닝: 발견된 경로 스캐닝(헤더와 함께 HTTP 요청 전송)은 I/O 바운드 작업이므로 Python 스레드를 사용하여 안전하게 병렬화할 수 있습니다. I/O 작업은 GIL(Global Interpreter Lock)을 해제하여 여러 스레드가 네트워크 요청을 동시에 진행할 수 있게 합니다. concurrent.futures.ThreadPoolExecutor를 사용하여 각각 스캐닝 작업의 일부를 처리하는 작업자 스레드 풀을 구성할 수 있습니다. 이는 프로세스를 크게 가속화할 수 있습니다: 예를 들어, 5개의 스레드를 병렬로 실행하면 다른 웹 스크래핑 컨텍스트에서 볼 수 있듯이 스캐닝 시간을 약 5배 단축할 수 있습니다. 스레드 수를 설정 가능하게 하거나 속도와 서버 부하를 균형있게 조절하는 적절한 기본값(예: 10개 스레드)을 선택할 수 있습니다. 각 스레드는 테스트할 엔드포인트의 공유 큐에서 URL을 가져옵니다.
Asyncio 대안: 또는 비동기 방식을 사용할 수 있으며, 특히 Playwright를 비동기 모드로 사용하거나 HTTP 요청에 httpx를 사용하는 경우에 적합합니다. 여러 요청을 동시에 await할 수 있습니다. 예를 들어, httpx.AsyncClient는 많은 요청을 동시에 보내고 결과를 수집할 수 있습니다. 이 접근 방식은 스레드 오버헤드를 피하고 많은 수의 엔드포인트에 대해 매우 효율적일 수 있습니다. 그러나 asyncio를 Playwright(자체적으로 비동기식으로 사용 가능)와 혼합하면 복잡해질 수 있습니다. 실용적인 해결책은 HTTP 스캔 단계에 스레딩을 사용하는 것입니다(Playwright를 사용한 크롤링은 동기 모드에서 관리하기 더 쉬울 수 있음).
동시 크롤링: 사이트가 큰 경우 크롤링도 병렬화하는 것을 고려해야 합니다. Playwright는 비동기 컨텍스트를 사용하여 한 번에 여러 페이지를 열 수 있습니다. 크롤링에 제한된 동시성(예: 한 번에 2-3페이지)을 구현할 수 있습니다. 예를 들어, 새 URL을 추출하면서 asyncio를 사용하는 경우 각 URL에 대해 새 Page를 시작할 수 있습니다. 이는 필요한 경우 고급 최적화가 될 수 있습니다. 초기에는 단일 스레드 크롤링이 더 간단하고 중간 규모 사이트에 적합하지만, 설계에서는 이를 개선점으로 기록할 수 있습니다.
스레드 안전성: 공유 데이터의 스레드 안전 처리를 보장합니다. 스캔할 URL 목록은 단순성을 위해 ThreadPoolExecutor.map으로 처리하거나, 스레드 안전 큐(Python의 queue.Queue)를 사용하여 스레드가 비어 있을 때까지 가져오도록 할 수 있습니다. 크롤링을 위한 visited 집합은 크롤러에서만 접근합니다(동시 크롤링을 하지 않는 한 단일 스레드). 스캐너 스레드는 URL 목록에서만 읽습니다(로깅 결과를 제외하고 공유 구조를 수정하지 않으며, 로깅은 잠금으로 보호하거나 스레드 안전 목록에 수집할 수 있습니다).
속도 제한 및 예의: 이는 보안 테스트 도구이므로 속도가 우선이지만, 대상에 과부하를 주지 않도록 해야 합니다. 사용자에게 적절한 스레드 수를 설정하도록 조언할 수 있습니다. 필요한 경우 약간의 지연을 구현하거나 세마포어를 사용하여 동시성을 제한할 수 있습니다. 예를 들어, 사용자의 네트워크나 서버가 과부하될 수 있는 경우 모든 스레드를 한 번에 시작하지 않을 수 있습니다. 고급 시나리오에서는 비동기 방식이 세마포어를 사용하여 한 번에 5개의 동시 요청을 허용할 수 있습니다. 이러한 세부 사항은 스크립트 성능 테스트를 기반으로 조정할 수 있습니다.
요약하자면, 동시성은 주로 스캐닝 단계에 적용되어 여러 엔드포인트를 병렬로 테스트합니다. 이는 각 요청이 독립적이므로 정확성을 크게 희생하지 않으면서 스캐너를 훨씬 빠르게 만듭니다. 한 참고 자료에서 언급했듯이, "concurrent.futures를 사용한 멀티스레딩은 여기서 상당한 성능 향상을 제공할 수 있습니다. 여러 스레드에서 I/O 작업을 동시에 실행하면 큰 속도 향상을 볼 수 있습니다". 네트워크 바운드 작업은 Python에서도 멀티스레딩의 이점을 얻을 수 있으므로 여기에 적합합니다.
스크립트의 핵심은 스캐닝 모듈로, 발견된 엔드포인트(경로) 목록을 가져와 각각에 대해 CVE-2025-29927 취약점의 징후를 확인합니다. 각 엔드포인트에 대한 프로세스는 다음과 같습니다:
x-middleware-rewrite, x-middleware-next, 또는 x-middleware-redirect와 같은 Next.js의 미들웨어 헤더가 포함되어 있으면 이 경로가 미들웨어로 보호되고 있음을 시사합니다. 또한 상태가 200이 아닌 경우(접근이 거부되었거나 리디렉션되었음을 의미) 확인합니다. 이는 우회될 가능성이 있는 경로이기 때문입니다. (상태가 이미 200이고 콘텐츠가 정상적으로 로드되면 공개 페이지이거나 취약점이 적용되지 않습니다; 계속 테스트할 수는 있지만 실제 관심은 보호된 페이지에 있습니다.)X-Middleware-Subrequest 헤더를 포함합니다. Next.js 버전 간 탐지를 보장하기 위해 다양한 헤더 값을 시도합니다:"1" 또는 "true"와 같은 일반적인 값(일부 소스에서는 헤더를 어떤 값으로든 설정하기만 하면 건너뛰기가 트리거된다고 암시합니다)."middleware:middleware:middleware:middleware:middleware" (다섯 번 반복된 "middleware")). 이는 최신 버전(13+)에서 우회를 유도하는 것으로 알려져 있습니다. 이 값을 정확히 포함합니다."middleware" 또는 "src/middleware"와 같은 단일 세그먼트 값(이전 Next.js 버전은 pages 디렉토리에 _middleware 파일을 사용할 수 있으며, 필요한 페이로드가 약간 다를 수 있음, 그러나 위의 다중 세그먼트 페이로드가 알려진 사례를 대부분 포함합니다).이러한 각 요청은 사용자 정의 헤더 세트로 수행됩니다. 또한 동일한 메서드(GET)를 사용하고 기준 요청에서 필요할 수 있는 헤더(예: 로그인된 스캔을 위해 사용자가 제공한 경우 쿠키나 인증 토큰, 그러나 일반적으로 인증 없이 스캔합니다)를 포함하도록 합니다.
/admin이 일반적으로 403을 반환했지만 헤더와 함께 200을 반환하고 관리자 대시보드 HTML을 포함하는 경우 플래그를 지정합니다.if base_status_code != 200 and test_status_code == 200: (그리고 아마도 test_body_length > base_body_length 또는 인증된 키워드 포함 여부도 확인) 그런 다음 취약한 것으로 플래그 지정합니다. 기준이 리디렉션(예: 307 to /login)이고 테스트가 200을 반환하면 또한 플래그 지정합니다. 기본적으로 '이전에는 접근이 거부되었지만 지금은 허용되었습니까?'입니다.results.txt에 저장됩니다. 명확하게 형식을 지정해야 합니다. 예:[*] /admin -> baseline 403, with X-Middleware-Subrequest (payload X) got 200 [VULNERABLE]
또한 응답 길이나 응답의 일부를 출력하여 확인할 수 있습니다(간결성을 위해 길이만, 예: 'len: 0 -> 10240 bytes'). 여러 페이로드를 시도한 경우 어떤 것이 성공했는지 나열할 수 있습니다.
사이트가 전혀 Next.js 애플리케이션이 아닌 경우(예: 홈페이지에서 /_next/static/을 찾지 못한 경우, 이는 명백한 신호입니다), 다음과 같은 메모를 출력할 수 있습니다: 'Next.js 지표가 발견되지 않았습니다. 대상이 Next.js를 사용하지 않을 수 있습니다 – 취약할 가능성이 낮습니다.' 그러나 Next.js 확인은 필수가 아니라 최적화이므로 일반적인 방식으로 계속 진행할 수 있습니다.이 로직은 깔끔하게 캡슐화됩니다. 예를 들어, scan_endpoint(url, session, header_payloads) 함수가 있어 취약한지 여부와 세부 정보를 포함하는 결과 객체나 딕셔너리를 반환할 수 있습니다. 우리는 오탐을 피하기 위해 강력한 검사를 통합할 것입니다. 구체적으로, 상태 코드가 200으로 변경되는 것(또는 다른 명확한 증거)을 요구함으로써 실제 우회만 플래그 지정되도록 합니다. ProjectDiscovery의 분석에서 언급했듯이, 스캐너는 특수 헤더가 포함될 때 응답 상태 200을 확인하여 취약점을 확인합니다.
스크립트의 출력은 읽고 해석하기 쉬워야 하며, 선택적으로 파일에 저장할 수 있어야 합니다. 콘솔 출력을 적절한 위치에 명확한 제목과 들여쓰기로 형식화할 것입니다. 몇 가지 고려 사항:
스캔 후 결과 요약을 출력합니다. 예: “Scan Complete: 3 vulnerable endpoints found (out of 45 tested).” 그런 다음 취약한 엔드포인트를 세부 정보와 함께 나열합니다.
위에 표시된 대로 각 결과 줄에 일관된 형식을 사용하며, 주의를 끌기 위해 [VULNERABLE] 태그를 사용할 수도 있습니다. rich 같은 라이브러리를 사용하면 “VULNERABLE”을 빨간색이나 노란색으로 색상 코딩할 수도 있습니다. 추가 라이브러리가 없어도 colorama를 통해 ANSI 코드를 사용하거나 대문자 텍스트만 사용할 수 있습니다.
취약점이 발견되지 않으면 명시적으로 표시합니다: “No vulnerabilities detected for CVE-2025-29927.”
결과를 저장해야 하는 경우, 파일에 유사한 형식으로 작성되도록 합니다. 더 자세한 형식이나 프로그래밍 방식 사용을 위한 CSV일 수도 있지만, 사용자가 텍스트 파일을 명시적으로 언급했으므로 동일한 줄을 results.txt에 작성할 것입니다.
또한, 발생한 중요한 오류나 예외(예: 특정 페이지를 로드할 수 없는 경우)는 출력에서 우아한 방식으로 보고됩니다(스택 트레이스 대신). 예외를 잡아 실패한 URL당 한 줄 경고를 출력할 수 있습니다. 예: “Timeout loading /blog (skipped)”. 이렇게 하면 사용자가 어떤 경로가 테스트되지 않았는지 알 수 있습니다.
실행 전반에 걸쳐 스피너나 진행 상황을 표시하거나(긴 실행의 경우) 적어도 어떤 페이지가 크롤링 중인지 또는 어떤 엔드포인트가 테스트 중인지 출력할 수 있습니다(자세한 모드인 경우). 더 깔끔한 출력을 위해 마지막에 발견된 취약한 경우만 표시할 수 있지만, 투명성을 위해 실행 로그(별도 로그 파일에 기록)가 도움이 될 수 있습니다.
명확한 형식이 강조되었으므로 여러 결과를 출력할 때 글머리 기호 목록이나 테이블 레이아웃을 사용하면 도움이 될 수 있습니다:
다음과 같이 표로 표시할 수 있습니다: Endpoint | Base Status | Base Length | Bypass Status | Bypass Length | HeaderValueUsed | Result
그러나 간단한 문장 형태가 다양한 사용자에게 더 읽기 쉬울 수 있습니다. 각 결과가 새 줄에 있고 명확하게 레이블이 지정되도록 할 것입니다.
화면 출력과 선택적 파일 저장을 모두 제공함으로써 이 도구는 대화형 사용과 자동화된 스캐닝(사용자가 나중에 파일을 검토하거나 보고서에 통합할 수 있음) 모두에 유용합니다.
스크립트를 유지 관리 가능하고 전문적인 수준으로 만들기 위해, 각각 기능의 개별 측면을 처리하는 모듈로 코드를 구성할 것입니다. 가능한 프로젝트 구조:
crawler.py: Playwright를 사용한 크롤링 로직을 포함합니다. crawl_site(start_url, config) -> List[str]와 같은 함수를 가지며, 발견된 내부 경로 목록을 반환합니다. 이 모듈은 브라우저 시작, 페이지 검색, 링크 추출, 필터(도메인, 정적 파일 제외) 적용을 처리합니다. 또한 URL 정규화(예: urllib.parse.urljoin을 사용하여 URL 프래그먼트 제거, 상대 경로 처리)를 위한 도우미 로직을 포함할 수 있습니다.
scanner.py: 취약점 스캔 로직을 포함합니다. scan_paths(url_list, config) -> List[ScanResult]와 같은 함수를 포함합니다. 이 함수는 HTTP 요청(requests.Session 또는 httpx 클라이언트 사용) 생성, 헤더 적용, 응답 비교, 결과 수집을 관리합니다. 멀티스레딩을 사용하는 경우, 이 모듈은 ThreadPool을 생성하고 작업을 관리합니다. 각 경로에 대한 정보(경로, vulnerable: bool, details)를 저장하는 작은 ScanResult 데이터 클래스를 정의할 수 있습니다.
config.py (또는 settings.py): 사용자 메뉴 및 구성을 위한 코드를 포함합니다. 예를 들어, 사용자와 상호 작용하고 선택한 모든 설정(user_agent, timeout, proxy, output_file flag 등)이 포함된 구성 객체/딕셔너리를 반환하는 함수 get_user_config()가 있습니다. CLI 인수를 사용하는 경우, 이 모듈은 argparse.ArgumentParser를 대신 구문 분석할 수 있습니다. 기본적으로 이 부분은 모든 사용자 입력 및 구성 처리를 분리합니다.
utils.py: 유틸리티 함수, 예: 배너 출력, 출력 문자열 형식화, 색상 출력 처리, 또는 is_static_resource(url)(URL이 정적 파일을 가리키는지 확인)과 같은 일반 도우미. 또한, 정상 종료를 위한 함수(SIGINT 호출 시)를 포함할 수 있습니다.
main.py: 모든 것을 연결하는 진입점 스크립트입니다. 다음을 수행합니다:
config.py 사용).main은 한 파일의 하단에 있을 수 있지만, 명확성을 위해 분리하는 것이 좋습니다.각 모듈은 모듈식이며 재사용 가능하도록 설계됩니다. 예를 들어, crawler.py를 다른 목적으로 사이트 링크를 얻는 데 재사용하거나, scanner.py를 크롤링 없이 주어진 URL 목록에서 이 취약점을 테스트하는 데 재사용할 수 있습니다.
예외 처리 및 정상 종료: 강력한 예외 처리를 구현할 것입니다:
네트워크 작업을 try/except로 감쌉니다(시간 초과, 연결 오류 등 포착). 페이지 크롤링이 실패하면 기록하고 다른 페이지로 계속 진행합니다. 스캔 요청이 실패하면(예: 프록시 오류) 해당 엔드포인트를 오류로 표시하지만 나머지는 계속 스캔합니다.
finally 블록이나 컨텍스트 관리자를 사용하여 리소스가 정리되도록 합니다. 예를 들어, async_playwright() 컨텍스트를 사용하거나 크롤링 종료 시 browser.close()가 호출되도록 합니다. 마찬가지로 파일 쓰기 후 파일 핸들이 닫히도록 합니다.
KeyboardInterrupt (Ctrl+C) 처리: 메인 루프에서 KeyboardInterrupt를 트랩하여 정상 종료를 시작할 수 있습니다. 예: “Stopping, cleaning up…” 출력, 스레드 종료(아마도 ThreadPoolExecutor.shutdown(wait=False)를 사용하여 새 작업 실행 중지), 브라우저 닫기. 이렇게 하면 사용자가 중단할 경우 고아 프로세스나 잠긴 파일이 생기지 않습니다.
디버그 메시지에 로깅 사용(아마도 Python의 logging 라이브러리 사용). 전문 도구에서는 로깅 수준이 있습니다. 예: 디버그 로그는 각 요청을 포함할 수 있고, 정보 수준은 높은 수준의 진행 상황만 표시합니다. 사용자는 자세한 플래그를 설정하여 이를 전환할 수 있습니다. 기본적으로 출력이 넘치지 않도록 최소한의 정보만 기록할 수 있습니다.
코드 품질: 최상의 코딩 관행을 준수합니다:
가독성을 위해 PEP8 스타일 가이드를 따릅니다.
의미 있는 함수 및 변수 이름을 사용합니다.
함수에 docstring을 추가하여 목적과 사용법을 설명합니다.
함수 시그니처에 타입 힌트(Python 3 타입 어노테이션)를 사용하여 코드를 더 쉽게 이해하고 타입 문제를 조기에 포착합니다.
상수(헤더 페이로드 목록, 무시할 정적 파일 확장자 목록 등)를 모듈화하고 파일 상단이나 구성에 배치하여 쉽게 업데이트할 수 있도록 합니다. 예: HEADER_PAYLOADS = ["middleware:middleware:...","src/middleware:..."] 등을 한 곳에 정의합니다.
일부 도우미 함수에 대한 단위 테스트를 포함할 수 있습니다(더 큰 프로젝트의 경우, 단일 스크립트 도구의 경우 건너뛸 수 있지만, 테스트 가능성을 염두에 두고 설계하는 것이 유용합니다).
전문가 수준 향상: 스크립트를 더욱 강력하고 프로덕션 준비가 되도록 하기 위해 다음을 추가로 고려할 수 있습니다:
인증 지원: 사용자가 사이트의 인증된 섹션을 스캔하려는 경우 쿠키나 자격 증명을 제공할 수 있도록 합니다(취약점은 인증 우회에 관한 것이지만, 공개되지 않은 링크에 도달하기 위해 먼저 로그인해야 할 수 있습니다 – 우회는 유효한 인증 없이도 작동할 것으로 예상되지만, 공개되지 않은 딥 링크를 크롤링하는 데 도움이 될 수 있습니다).
구성 파일: 대화형 입력 대신(또는 추가로) 구성 파일이나 환경 변수에서 옵션을 읽을 수 있도록 하여 스캐너의 자동화된 배포에 유용합니다.
출력 형식: 다른 도구와의 통합을 위해 JSON이나 CSV와 같은 여러 형식으로 출력을 제공합니다. 예를 들어, --json 플래그는 결과를 기계가 읽을 수 있는 JSON으로 덤프할 수 있습니다.
기존 프레임워크와 통합: 로직을 더 큰 스캐닝 프레임워크에 통합할 수 있습니다(예: OWASP ZAP 모듈로 전환하거나, 호환되는 보고서를 출력하여 ProjectDiscovery의 Nuclei와 통합). 최소한 스크립트의 출력이 취약점과 영향을 받는 URL을 명확히 식별하여 보고서에 사용될 수 있도록 합니다.
병렬 브라우저 세션: 매우 큰 앱을 대상으로 하는 경우, 다른 섹션을 동시에 크롤링하기 위해 여러 브라우저 컨텍스트를 병렬로 실행하는 것을 고려합니다. Playwright는 여러 컨텍스트를 처리할 수 있습니다(각 컨텍스트는 격리되어 있으며, 별도의 브라우저 프로필과 유사함). 이는 리소스 사용량이 더 높지만 크롤링 속도를 크게 높일 수 있습니다.
정상적인 성능 저하: Playwright가 실패하는 경우(예: 환경에 디스플레이가 없거나 제대로 설치되지 않은 경우), 스크립트는 더 간단한 requests 기반 크롤링으로 대체될 수 있습니다(일부 링크를 놓칠 수 있지만 없는 것보다는 나음). 이렇게 하면 다양한 환경에서 도구가 더 강력해집니다. 마찬가지로 동시성이 너무 높게 설정되어 문제가 발생하면 이를 포착하고 사용자에게 스레드 수를 낮추도록 제안합니다.
깔끔한 구조와 이러한 모범 사례를 따르면 스크립트를 더 쉽게 유지 관리하고 확장할 수 있습니다. 각 구성 요소는 독립적으로 작업할 수 있습니다. 예를 들어, 크롤러가 JavaScript 중심 탐색을 구문 분석하는 기능을 개선하거나, 향후 연구에서 추가 익스플로잇 패턴이 발견될 경우 새로운 헤더 페이로드 변형으로 스캐너를 업데이트하는 등의 작업이 가능합니다.
결론적으로, 이 설계는 웹 애플리케이션에서 CVE-2025-29927을 탐지하기 위한 포괄적인 접근 방식을 설명합니다. 심층 크롤링을 위한 헤드리스 브라우저, 효율적인 스캐닝을 위한 멀티스레딩, 안정성을 위한 강력한 코딩 방식을 활용합니다. 특수 헤더가 있는 경우와 없는 경우의 응답을 비교함으로써 Next.js 미들웨어가 우회되는 취약한 엔드포인트를 안정적으로 식별할 수 있습니다. 그 결과는 보안 엔지니어와 개발자가 애플리케이션에서 이 중요한 취약점을 신속하게 찾고 해결하는 데 도움이 되는 전문가 수준의 도구입니다.