
これはCVE-2025-29927スキャナーです。
これは、Next.js アプリケーションにおける CVE-2025-29927 ミドルウェアバイパス脆弱性を検出するために設計された、プロフェッショナルグレードのスキャナーです。
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
| オプション | 説明 |
|----------------|--------------------------------------------|
| `--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 に影響し、管理者はアプリケーションを保護するためにパッチ適用または緩和策(プロキシでこのヘッダーを除去するなど)を実施するよう求められています。
Web アプリケーションでこの脆弱性を検出するには、内部エンドポイントを発見し、悪意のあるヘッダーを付与してテストし、不正アクセスが可能かどうかを確認する必要があります。以下は、ターゲット Web サイトをクロールし(JavaScript フルサポート付き)、CVE-2025-29927 をスキャンして、指定されたすべての要件を満たす高度な Python スクリプトの設計プランです。
JavaScript レンダリングコンテンツを含むディープクロールの要件を満たすために、Playwright を使用します(速度とモダンな API の点で Selenium よりも推奨されます)。Playwright は、動的 Web アプリやモダンな 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 を使用します(追加インストール不要)。非同期アプローチを使用する場合は、Python の asyncio を httpx と組み合わせて並行リクエストを実行できます。
– インタラクティブメニューの代わりに CLI インターフェースを希望する場合、コマンドライン引数の解析用。(組み込みモジュール)
根拠: Playwright は、複雑さを伴わずに動的コンテンツをスクレイピングできるため選択されました。「Playwright を使用すると、ヘッドレスブラウザを自動化して...人間と同じようにウェブを操作できるため、動的な JavaScript 駆動の Web サイトのスクレイピングに最適です」。これにより、スクリプトによって生成されたリンクや 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>) を使用してページを読み込みます(タイムアウトは設定可能)。必要に応じて、動的コンテンツの読み込みを待つためにネットワークアイドル状態または短い遅延を待機します。その後、リンクを抽出します。リンク抽出は以下のいずれかの方法で行えます:
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 テンプレートに着想を得たもの)は、最初のスラッシュの後に「ドット」を含むパスを無視することです。彼らは正規表現パターン href=['"](https://github.com/houmanpashaei/cve-2025-29927/blob/HEAD/%5C/%5B%5E.%5C%22%27%5D+)['"] でエンドポイントを抽出しました – これはピリオドを含まない内部パスをキャプチャするため、アセットをスキップします。コード内でも同様のロジックを実装し、静的リソースや外部リンクをキューに入れないようにします。
追跡と深さの制御: 無限ループや繰り返しを避けるために、訪問済み URL のセットを維持します。サイトのリンクグラフを BFS で走査するためにキュー(FIFO)を使用します。必要に応じて、ユーザーがクロール深さの制限や訪問する最大ページ数を指定できるようにし、大規模サイトで無限に実行されるのを防ぎます。
JavaScript レンダリングコンテンツ: 実際のブラウザを使用するため、スクリプトによって DOM に追加されたリンク(例えば、データ取得後にメニューをレンダリングする React アプリなど)もクローラーに表示されます。必要に応じてクリックや操作を検討する必要があります(例:特定のページがユーザーアクション後にのみ読み込まれる場合)。ただし、シンプルかつ高速にするため、初期設計では各読み込みページの href の収集に焦点を当てます。ターゲットアプリケーションが求める場合には、後で無限スクロールやクリックの背後にあるコンテンツの処理に拡張できます。
効率性: Playwright は非同期 API を使用した複数ページ/タブの並列実行をサポートしています。asyncio.gather で複数のページをインスタンス化し、複数のリンクを同時に取得できます。初期実装では、順次クロール(実装が簡単)の方がシンプルで、パフォーマンスはマルチスレッドスキャンに依存する方が良いでしょう。必要に応じて、高度な最適化として非同期クロール(async with async_playwright() を使用し、複数の page.goto 呼び出しを await)が考えられます。ただし、ブラウザ自動化はリソースを多く消費するため、システムに過負荷をかけないよう、一度に 1 つまたは数個のブラウザページに抑える慎重なアプローチが適切です。
スクリプトは起動時にユーザーフレンドリーな設定メニューを表示し、ユーザーがスキャンパラメータをカスタマイズしたりデフォルトを受け入れたりできるようにします。これは、インタラクティブなコンソールメニュー(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": "..."}) の例のように)。同様に、requests では、それに応じて proxies パラメータ(または環境変数)を設定します。
(任意) rich または colorama – 可読性を高めるためのカラーまたはフォーマット済みコンソール出力用。(インストール: pip install rich または pip install colorama)。
ファイルへの出力: メニューは、結果をファイル(例:results.txt)に保存するかどうかを尋ねます。「はい」の場合、スクリプトは発見された脆弱なエンドポイントと詳細を画面への表示に加えてこのファイルに書き込みます。そうでない場合、結果は stdout にのみ出力されます。(必要に応じてスキャンされたすべてのパスを詳細ログに記録することはありますが、ファイルはユーザーの好みに応じて陽性結果または完全なレポートを具体的に記録します。)
その他のオプション: デバッグログ用の「Verbose モード」や「最大クロール深さ/ページ数」などのトグルを含めることができます。これらはユーザーがスキャンを微調整するのに役立ちます。初期スコープでは、上記の 4 つの主要オプションで十分です。
メニューシステムは専用の設定/セットアップモジュールに実装されます。これは単にプロンプトを表示して入力を受け取り、ユーザーが Enter を押した場合は適切なデフォルト値(例:標準的な User-Agent、デフォルトタイムアウト = 10 秒、プロキシなし、ファイル出力なし)を使用する関数です。これにより、対話が明確になり、スクリプトを非対話的に実行することもできます(後でコマンドライン引数を追加する場合、すべての必要な設定を引数で提供することでインタラクティブプロンプトをバイパスできます)。
パフォーマンスはスキャナーにとって重要であり、特に多数のエンドポイントが見つかった場合に重要です。スクリプトは速度のために並行処理を採用します。マルチスレッドまたは asyncio(またはその組み合わせ)を通じて:
マルチスレッドスキャン: 発見されたパス(ヘッダー付き HTTP リクエストの送信)のスキャンは I/O バウンドタスクであるため、Python スレッドを使用して並列化しても安全です。I/O 操作はグローバルインタプリタロックを解放するため、複数のスレッドがネットワークリクエストで同時に進行できます。concurrent.futures.ThreadPoolExecutor を使用すると、各ワーカースレッドがスキャンタスクのサブセットを処理するスレッドプールを持つことができます。これにより処理が大幅に高速化されます。例えば、5 スレッドを並列実行すると、他の Web スクレイピングコンテキストで示されているように、スキャン時間を約 5 分の 1 に短縮できます。スレッド数は設定可能にするか、速度とサーバー負荷のバランスを取った適切なデフォルト(10 スレッドなど)を選択します。各スレッドは、テスト対象のエンドポイントの共有キューから URL を取得します。
Asyncio の代替案: あるいは、特に Playwright を非同期モードで使用する場合や HTTP リクエストに httpx を使用する場合は、非同期アプローチを使用できます。複数のリクエストを同時に await できます。例えば、httpx.AsyncClient は多くのリクエストを並行して送信し、結果を収集できます。このアプローチはスレッドのオーバーヘッドを回避し、多数のエンドポイントに対して非常に効率的です。ただし、asyncio と Playwright(それ自体を非同期で使用できます)を混在させると複雑になる可能性があります。実際的な解決策は、HTTP スキャン段階にはスレッドを使用することです(Playwright によるクロールは同期モードで管理する方が簡単な場合があるため)。
並行クロール: サイトが大きい場合、クロールの並列化も検討すべきです。Playwright は非同期コンテキストを使用して複数のページを同時に開くことができます。クロールのための制限付き並行性(例:一度に 2〜3 ページ)を実装するかもしれません。例えば、新しい URL を抽出する際に、asyncio を使用している場合はそれぞれに新しい 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" を5回繰り返す)。これは最新バージョン(13+)でバイパスを誘発することが知られています。この値を正確に含めます。
/src ディレクトリを使用するプロジェクト用の代替ペイロード。例:"src/middleware:src/middleware:src/middleware:src/middleware:src/middleware"
任意で、完全を期すために "middleware" や "src/middleware" などの単一セグメント値(古い Next.js バージョンでは pages ディレクトリに _middleware ファイルを使用する場合があり、必要なペイロードが若干異なりますが、上記のマルチセグメントペイロードで既知のケースをほぼカバーできます)。
各リクエストはカスタムヘッダーを設定して実行されます。また、同じメソッド(GET)を使用し、ベースラインから必要なヘッダー(ログイン済みスキャンのためにユーザーが提供したクッキーや認証トークンなど。通常は未認証でスキャンしますが)を含めるようにします。
ベースラインがエラーまたはリダイレクト(例:401 Unauthorized、403 Forbidden、またはログインへのリダイレクト)であり、ヘッダー注入レスポンスのいずれかが 200 OK でボディが大幅に大きい(またはページが読み込まれたことを示す)場合、それは脆弱性の強い指標です。例えば、/admin が通常 403 を返すが、ヘッダー付きでは 200 を返し、管理ダッシュボードの HTML が含まれている場合、フラグを立てます。
場合によっては、違いは 302 対 200、または 404 対 200 かもしれません。非 200 から 200 へのステータスコード変更を可能性の高い兆候と見なします。また、ステータスが 200 のままでもコンテンツの長さが劇的に変化する場合、ヘッダーが動作を変更したことを示す可能性があります(この特定のバグではあまり一般的ではありませんが、ページが通常とは異なるものを配信した場合の可能性です)。
次のようなチェックを実装します:if base_status_code != 200 and test_status_code == 200:(そして、test_body_length > base_body_length または認証されたキーワードが含まれていることも確認します)の場合、脆弱性としてフラグを立てます。ベースラインがリダイレクト(例:/login への 307)で、テストが 200 を返す場合もフラグを立てます。基本的には、「以前はアクセスが拒否されていたが、今は許可されているか?」ということです。
ヘッダー付きのレスポンスステータスが 404 または 500 で、ベースラインがリダイレクトだった場合、これはキャッシュポイズニングシナリオ(ミドルウェアのリダイレクトをバイパスしてオリジンで 404 を引き起こす)の可能性があります。このシナリオは単一のリクエストだけでは検出が少し難しいですが、ベースラインがリダイレクトだった場合にヘッダー付きで 404 が存在することにも注目するかもしれません(認証バイパスではありませんが、それでも脆弱性の影響です)。ただし、私たちの焦点は認証バイパス(200 OK アクセス)の検出にあります。
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) 関数があって、それが脆弱かどうかと詳細を含む結果オブジェクトまたはdictを返すかもしれません。誤検知を避けるための堅牢なチェックを組み込みます。具体的には、ステータスコードが200に変わること(または他の明確な証拠)を要求することで、実際のバイパスのみをフラグ付けするようにします。ProjectDiscoveryの分析で述べられているように、スキャナは特別なヘッダーが含まれるときにレスポンスステータス200をチェックして脆弱性を確認します。
スクリプトの出力は読みやすく解釈しやすいものであるべきで、必要に応じてファイルに保存することも可能です。コンソール出力は、適切な場所に明確な見出しとインデントを使って整形します。いくつかの考慮点:
スキャン後、結果のサマリーを出力します。例:「Scan Complete: 3 vulnerable endpoints found (out of 45 tested).」 その後、脆弱なエンドポイントを詳細とともにリストアップします。
各行の結果には、上記のように一貫した形式を使い、注意を引くために [VULNERABLE] タグを付けるとよいでしょう。rich のようなライブラリを使う場合は、“VULNERABLE” を赤や黄色に色分けすることもできます。追加ライブラリがなくても、colorama 経由のANSIコードで強調表示するか、単に大文字テキストにするだけでも構いません。
脆弱性が見つからない場合は、その旨を明示的に伝えます:「CVE-2025-29927の脆弱性は検出されませんでした。」
結果を保存する場合は、ファイルにも同様の形式で書き込むようにします。やや冗長な形式や、プログラムで使うためのCSVにする場合もありますが、ユーザーがテキストファイルを明示的に指定しているため、おそらく同じ行を results.txt に書き込むだけになるでしょう。
また、遭遇した重大なエラーや例外(特定のページを読み込めない場合など)は、スタックトレースの代わりに、出力で丁寧に報告できます。例外をキャッチして、失敗したURLごとに1行の警告を表示します。例:「/blog の読み込みがタイムアウトしました(スキップ)」。こうすることで、一部のパスがテストされなかったことをユーザーが把握できます。
実行中は、スピナーや進捗表示(長時間の実行の場合)を出すか、少なくともverboseモードが有効な場合は、どのページをクロールしているか、どのエンドポイントをテストしているかを出力するかもしれません。よりすっきりした出力にするため、最後に発見された脆弱なケースだけを表示することもありますが、実行ログ(おそらく別のログファイルに書き込む)は透明性の向上に役立ちます。
明確な形式が重視されているため、複数の結果を出力する際は箇条書きやテーブルレイアウトを使うと役立つかもしれません:
次のように表にできます:Endpoint | Base Status | Base Length | Bypass Status | Bypass Length | HeaderValueUsed | Result
ただし、シンプルな文章形式の方が幅広いユーザーにとって読みやすいかもしれません。各結果が新しい行にあり、明確にラベル付けされるようにします。
画面出力とオプションのファイル保存の両方を提供することで、このツールはインタラクティブな使用と自動スキャン(後でファイルを確認したりレポートに統合したりできる)の両方に役立ちます。
スクリプトを保守しやすくプロフェッショナルグレードにするために、コードをモジュールに分割し、各モジュールが機能の異なる側面を担当するようにします。考えられるプロジェクト構造:
crawler.py: Playwrightを使ったクロールロジックを含みます。発見された内部パスのリストを返す crawl_site(start_url, config) -> List[str] のような関数を持つでしょう。このモジュールは、ブラウザの起動、ページの取得、リンクの抽出、フィルターの適用(ドメイン、静的ファイルの除外)を処理します。また、URLを正規化するヘルパーロジック(例:URLフラグメントの削除、urllib.parse.urljoin を使った相対パスの処理)を置くこともできます。
scanner.py: 脆弱性のスキャンロジックを含みます。scan_paths(url_list, config) -> List[ScanResult] のような関数を含むでしょう。HTTPリクエストの作成(requests.Session またはhttpxクライアントを使用)、ヘッダーの適用、レスポンスの比較、結果の収集を管理します。マルチスレッドを使用する場合、このモジュールがThreadPoolを作成してタスクを管理します。各パス(path、vulnerable: bool、details)の情報を保持する小さな ScanResult データクラスを定義するかもしれません。
config.py(または settings.py):ユーザーメニューと設定のためのコードを含みます。例えば、ユーザーと対話し、選択されたすべての設定(user_agent、timeout、proxy、output_fileフラグなど)を含む設定オブジェクト/辞書を返す get_user_config() 関数など。CLI引数を使う場合、このモジュールは代わりに argparse.ArgumentParser を解析しても構いません。基本的に、この部分はすべてのユーザー入力と設定処理を分離します。
utils.py: ユーティリティ関数。例:バナーの表示、出力文字列のフォーマット、カラー出力の処理、is_static_resource(url) のような一般的なヘルパー(URLが静的ファイルを示す可能性が高いかどうかを確認する)。また、SIGINT時に呼び出されるグレースフルシャットダウン用の関数も含められます。
main.py: すべてを結び付けるエントリーポイントのスクリプト。次のことを行います:
config.py を使って)ユーザー設定を解析または収集する。main は1つのファイルの下部に置くだけでもよいですが、きれいにするには分離する方がよいでしょう。各モジュールはモジュール化され再利用可能になるように設計されます。例えば、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 ライブラリ経由)。プロフェッショナルなツールでは、ログレベルがあります。例えば、デバッグログには各リクエストを含め、infoレベルでは高レベルの進捗のみを表示します。ユーザーはverboseフラグを設定してこれを切り替えられます。デフォルトでは、出力を圧迫しないように最小限の情報をログに記録するかもしれません。
コード品質: ベストコーディングプラクティスに従います:
読みやすさのためにPEP8スタイルガイドラインに従います。
意味のある関数名と変数名を使用します。
関数にdocstringを追加して、その目的と使用方法を説明します。
関数シグネチャに型ヒント(Python 3の型アノテーション)を使用して、コードを理解しやすくし、型の問題を早期に発見できるようにします。
定数(ヘッダーペイロードのリスト、無視する静的ファイル拡張子のリストなど)をファイルの先頭または設定にモジュール化し、簡単に更新できるようにします。例えば、HEADER_PAYLOADS = ["middleware:middleware:...","src/middleware:..."] などを1か所で定義します。
一部のヘルパー関数のユニットテストを含める可能性があります(これが大規模プロジェクトであれば、単一スクリプトのツールでは省略されるかもしれませんが、それでもテスト容易性を考慮した設計は有益です)。
プロフェッショナルグレードの拡張: スクリプトをより堅牢で本番環境対応にするために、次の点をさらに検討できます:
認証サポート: サイトの認証されたセクションをスキャンしたい場合に、ユーザーがCookieまたは資格情報を提供できるようにします(この脆弱性は認証バイパスに関するものですが、特定のリンクに到達してからバイパスをテストするために最初にログインする必要があるシナリオもあります – ただしバイパスはおそらく有効な認証なしで機能しますが、公開されていないディープリンクのクロールに役立つ可能性があります)。
設定ファイル: インタラクティブな入力の代わりに(またはそれに加えて)、設定ファイルまたは環境変数からオプションを読み取れるようにします。これはスキャナーの自動デプロイに役立ちます。
出力形式: 他のツールとの統合のために、JSONやCSVなどの複数の形式で出力を提供します。例えば、--json フラグで結果を機械可読なJSONとしてダンプできます。
既存フレームワークとの統合: このロジックは、より大規模なスキャンフレームワークに統合できます(例えば、OWASP ZAPのモジュールにしたり、互換性のあるレポートを出力してProjectDiscoveryのNucleiと統合したり)。最低限、スクリプトの出力が脆弱性と影響を受けるURLを明確に識別して、レポートで使用できるようにします。
並列ブラウザセッション: 非常に大規模なアプリを対象とする場合、異なるセクションを並行してクロールするために、複数のブラウザコンテキストを並列に起動することを検討します。Playwrightは複数のコンテキストを処理できます(各コンテキストは分離されており、別々のブラウザプロファイルに似ています)。これにより、リソース使用量は増えますが、クロールを大幅に高速化できます。
グレースフルデグラデーション(段階的な機能低下): Playwrightが失敗した場合(例えば、環境にディスプレイがない、または適切にインストールされていない)、スクリプトはよりシンプルなrequestsベースのクロールにフォールバックできます(一部のリンクを見逃すかもしれませんが、何もしないよりはましです)。これにより、さまざまな環境でツールがより堅牢になります。同様に、並行性が高すぎて問題が発生した場合は、それを捕捉してユーザーにスレッド数を減らすよう提案します。
クリーンな構造とこれらのベストプラクティスに従うことで、スクリプトの保守と拡張が容易になります。各コンポーネントは独立して作業できます – 例えば、JavaScriptを多用するナビゲーションを解析するクローラーの機能を改善したり、将来の研究で追加の悪用パターンが見つかった場合に、新しいヘッダーペイロードバリエーションでスキャナーを更新したりできます。
結論として、この設計はWebアプリケーションにおけるCVE-2025-29927を検出するための包括的なアプローチを示しています。ヘッドレスブラウザを利用したディープクロール、効率的なスキャンのためのマルチスレッド、信頼性のための堅牢なコーディングプラクティスを活用します。特別なヘッダーがある場合とない場合のレスポンスを比較することで、Next.jsミドルウェアがバイパスされている脆弱なエンドポイントを確実に特定できます。その結果、セキュリティエンジニアや開発者がこの重大な脆弱性をアプリケーションで迅速に見つけて対処するのに役立つプロフェッショナルグレードのツールが生まれます。