security-review について
security-review は、リリース前の確認、大きな変更の再審査、監査準備に使うアプリケーションセキュリティ評価手順です。コードベース分析とブラウザテストを組み合わせ、証拠付きの指摘、修正案、YAML 回帰テストを作成します。
主な機能
- 01攻撃対象領域とデータフローの整理
- 02HTTP セキュリティヘッダーの確認
- 03認証・セッション・アクセス制御のテスト
- 04インジェクションとクライアント側セキュリティの確認
- 05依存関係とサプライチェーンのレビュー
- 06レポート、修正案、YAML テスト
活用シーン
- 01Web アプリのリリース前セキュリティ確認
- 02認証または認可の変更のレビュー
- 03セキュリティ監査向けの証拠と指摘の整理
- 04インシデント後に類似の弱点を調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ shiplightai/ agent-skills --skill security-reviewインストール後、Claude Code で/security-reviewを入力して読み込まれたか確認します。
詳細
セキュリティレビュー
業界標準に照らしてアプリケーションのセキュリティ態勢を評価し、ブラウザーを使ったペネトレーションテストで調査結果を検証します。このレビューでは、静的解析ツールでは見つけられない攻撃対象領域、つまり実行時の動作、ヘッダー設定、認証フロー、クライアント側の脆弱性を調べます。
使用するタイミング
次の場合は /security-review を使用します。
- 新しいアプリケーションや機能をリリースする前
- 認証または認可に関する変更を加えた後
- 機密データ(ユーザー認証情報、決済情報、PII)を扱う場合
- セキュリティ監査の準備をする場合
- セキュリティインシデントの後、同様の問題がないか確認する場合
- サードパーティ連携をレビューする場合
参照する標準
- OWASP Top 10 (2021) — Web アプリケーションの主なセキュリティリスク
- OWASP ASVS v4.0 — アプリケーションセキュリティ検証標準
- OWASP Session Management Cheat Sheet
- NIST 800-63B — デジタルアイデンティティガイドライン(認証)
- CWE/SANS Top 25 — 最も危険なソフトウェアの弱点
- Mozilla Observatory — HTTP セキュリティヘッダーのベストプラクティス
フェーズの概要
Phase 1: EDUCATE → Security context and what we check
Phase 2: SCOPE → Identify attack surface, auth mechanisms, data flows
Phase 3: ANALYZE → Automated checks + browser-based penetration testing
Phase 4: REPORT → Findings with evidence, CVE references, confidence scores
Phase 5: REMEDIATE → Fix guidance + YAML regression tests
フェーズ 1:理解を深める
重要な理由: データ侵害による平均損失額は 445 万ドルです(IBM 2023)。Web アプリケーションの 83% に、少なくとも 1 つの重大な脆弱性があります。多くのセキュリティ上の問題は、設定ミスのあるヘッダー、安全でないトークン保存、アクセス制御の不備など、実行時にしか検出できません。これらを検出できるのが、まさにブラウザーを使ったテストです。
このレビューでは、ブラウザーを使った検証により、客観的なセキュリティ基準に照らしてアプリを確認します。検出結果にはすべて、具体的な標準(OWASP、CWE、NIST)を記載します。
フェーズ 2:対象範囲
コンテキストを収集する
-
コードベースから自動検出する:
- 認証方式(JWT、セッション、OAuth、API キー)
- 使用中のフレームワークのセキュリティ機能(CSRF トークン、CORS 設定、CSP)
- 既知の脆弱性がある依存関係(
npm audit/pip audit) - API ルートとエンドポイント
- 環境変数の取り扱い
- ファイルアップロード機能
- サードパーティスクリプトと CDN の使用状況
-
ユーザーに一度に 1 つずつ質問する:
- 対象 URL:アプリはどこで実行されていますか?
- 認証方式:ユーザーはどのようにログインしますか?(自動検出した内容を確認)
- テスト用認証情報:テストに使用できるアカウントはありますか?(認証が必要なテストで使用します)
- 機密データ:アプリはどのような機密データを扱いますか?(PII、決済情報、健康記録)
- 既知の懸念事項:特に心配している領域はありますか?(任意)
-
攻撃対象領域をマッピングする:
- すべてのユーザー入力箇所(フォーム、URL パラメーター、ファイルアップロード、WebSocket メッセージ)を列挙する
- 認証要件を含むすべての API エンドポイントを列挙する
- すべてのサードパーティ連携を列挙する
- データフローを特定する:機密データはどこから入り、どこで処理・保存され、どこから出ていきますか?
フェーズ 3:分析する
record_evidence: true を指定して new_session でブラウザーセッションを開き、該当するすべてのチェックカテゴリを実行します。
カテゴリー A:HTTP セキュリティヘッダー(HDR)
| チェック ID | チェック項目 | 標準 | 方法 |
|---|---|---|---|
| HDR-01 | Content-Security-Policy ヘッダーが存在し、制限的に設定されている | OWASP A05 | レスポンスヘッダーを確認 |
| HDR-02 | Strict-Transport-Security(HSTS)の max-age が長く設定されている | OWASP Transport | ヘッダーの有無と値を確認 |
| HDR-03 | X-Content-Type-Options: nosniff | Mozilla Observatory | ヘッダーを確認 |
| HDR-04 | X-Frame-Options または CSP frame-ancestors が設定されている | OWASP Clickjacking | ヘッダーを確認 |
| HDR-05 | Referrer-Policy が適切に設定されている | プライバシー/セキュリティ | ヘッダー値を確認 |
| HDR-06 | Permissions-Policy により機密性の高い API が制限されている | ブラウザーセキュリティ | カメラ、マイク、位置情報のポリシーを確認 |
| HDR-07 | Server/X-Powered-By によるバージョン情報の開示がない | 情報漏えい | ヘッダーにバージョン文字列が含まれていないか確認 |
| HDR-08 | 機密性の高いページに Cache-Control が設定されている | OWASP Session | 認証済みコンテンツに no-store が設定されているか確認 |
| HDR-09 | CORS の許可範囲が広すぎない | OWASP A05 | Access-Control-Allow-Origin を確認 |
| HDR-10 | 混在コンテンツ(HTTPS ページ上の HTTP リソース)がない | 通信セキュリティ | すべてのリソース URL を確認 |
ブラウザーでの検証: act を使って JavaScript から document.querySelector('meta[http-equiv]') を調べ、同一オリジンのリクエストを使ってレスポンスヘッダーを取得します。get_browser_console_logs を使い、混在コンテンツの警告がないか確認します。
カテゴリー B:認証とセッション管理(AUTH)
| チェック ID | チェック項目 | 標準 | 方法 |
|---|---|---|---|
| AUTH-01 | トークンが localStorage に保存されていない | OWASP ASVS 3.3.2 | localStorage/sessionStorage にトークンがないか確認 |
| AUTH-02 | セッション Cookie に HttpOnly フラグが設定されている | OWASP Session | Set-Cookie ヘッダーを調べる |
| AUTH-03 | セッション Cookie に Secure フラグが設定されている | OWASP Session | Set-Cookie ヘッダーを調べる |
| AUTH-04 | セッション Cookie に SameSite 属性が設定されている | OWASP CSRF | Set-Cookie ヘッダーを調べる |
| AUTH-05 | アイドルタイムアウト後にセッションが失効する | OWASP ASVS 3.3.1 | 待機してセッションが無効化されることを確認 |
| AUTH-06 | ログアウトによりサーバー側のセッションが無効化される | OWASP ASVS 3.3.1 | ログアウトし、古いトークンを再送してレスポンスを確認 |
| AUTH-07 | パスワードリセットトークンが一度しか使えない | OWASP Auth | リセットリンクを 2 回使い、2 回目が失敗することを確認 |
| AUTH-08 | URL パラメーターに認証情報が含まれていない | OWASP Transport | URL にトークンやパスワードが含まれていないか確認 |
| AUTH-09 | ログイン時にブルートフォース攻撃への保護がある | OWASP Auth | ログインに複数回失敗し、ロックアウト/レート制限を確認 |
| AUTH-10 | 状態を変更するリクエストに CSRF 保護がある | OWASP A01 | CSRF トークンなしでフォームを送信 |
| AUTH-11 | JWT の署名が検証される(該当する場合) | OWASP Auth | 改変した JWT を送信し、拒否されることを確認 |
| AUTH-12 | OAuth の state パラメーターが使用される(該当する場合) | OWASP Auth | OAuth フローに state パラメーターがあるか確認 |
ブラウザーでの検証: act でログインし、JavaScript(document.cookie — HttpOnly Cookie が表示されないのは正しい動作です)を使って Cookie を調べます。localStorage を確認します。ログアウト後にリクエストを再送します。ブルートフォース攻撃を試します(誤ったパスワードを 5 回入力)。JWT トークンを改変してテストします。
カテゴリ C:入力検証とインジェクション(INJ)
| チェック ID | チェック項目 | 標準 | 方法 |
|---|---|---|---|
| INJ-01 | XSS:ページに反映される入力 | OWASP A03 / CWE-79 | すべての入力欄に <script>alert(1)</script> を送信し、表示されるか確認します |
| INJ-02 | XSS:データベースに保存される入力 | OWASP A03 / CWE-79 | フォームからスクリプトを送信し、後続のページ読み込み時に表示されるか確認します |
| INJ-03 | フォーム入力での SQL インジェクション | OWASP A03 / CWE-89 | ' OR '1'='1 パターンを送信し、エラーが発生するか確認します |
| INJ-04 | URL パラメーター経由のオープンリダイレクト | CWE-601 | 外部 URL を指定したリダイレクトパラメーターをテストします |
| INJ-05 | ファイル操作でのパストラバーサル | CWE-22 | ファイル関連のパラメーターに ../../etc/passwd を指定してテストします |
| INJ-06 | 入力フィールドでのコマンドインジェクション | CWE-78 | 入力がシェルに渡される可能性のある箇所で、; ls または ` |
| INJ-07 | ユーザーコンテンツでの HTML インジェクション | CWE-79 | HTML タグを送信し、表示されるか確認します |
| INJ-08 | URL スキームの検証(javascript:) | CWE-79 | URL 入力欄に javascript:alert(1) を指定してテストします |
| INJ-09 | ファイルアップロードの検証 | OWASP A04 | 拡張子が不正なファイル、サイズが大きすぎるファイル、実行可能なコンテンツを含むファイルをアップロードします |
| INJ-10 | API 入力の検証 | OWASP A03 | API エンドポイントに不正な JSON、必須フィールドの欠落、誤った型の値を送信します |
ブラウザーでの検証: act を使用して、フォームフィールドにテスト用ペイロードを入力します。送信後のページ状態を記録します。スクリプトの実行、エラーメッセージ、予期しない動作がないか確認します。インジェクションの経路を示す JavaScript エラーを確認するには、get_browser_console_logs を使用します。
重要: これらは検出のみを目的とした、非破壊のテスト用ペイロードです。実際の悪用は試みないでください。アラートを使った XSS テストでは、無害な alert(1) を使用します。
カテゴリ D:アクセス制御(AC)
| チェック ID | チェック項目 | 標準 | 方法 |
|---|---|---|---|
| AC-01 | 認証がない場合、認証が必要なページは 401/403 を返す | OWASP A01 | 認証せずに保護された URL にアクセスします |
| AC-02 | IDOR(安全でない直接オブジェクト参照)がない | OWASP A01 / CWE-639 | URL 内のリソース ID を変更し、不正なアクセスが可能か確認します |
| AC-03 | API エンドポイントで認可が適用される | OWASP A01 | 誤った認証情報または認証情報なしで API エンドポイントを呼び出します |
| AC-04 | 管理者用ページに一般ユーザーがアクセスできない | OWASP A01 | 一般ユーザーのセッションで管理者用ルートに移動します |
| AC-05 | クライアント側のソースに機密データが含まれていない | 情報漏えい | JavaScript バンドルに API キーやシークレットが含まれていないか確認します |
| AC-06 | ディレクトリー一覧が無効になっている | 情報漏えい | ディレクトリー URL(例:/api/、/static/)にアクセスします |
| AC-07 | デバッグ用エンドポイントが本番環境で公開されていない | OWASP A05 | 一般的なデバッグ用パス(/debug、/trace、/graphql playground)を確認します |
| AC-08 | エラーメッセージから内部の詳細が漏えいしない | OWASP A05 | エラーを発生させ、スタックトレースやデータベースの詳細が表示されないか確認します |
ブラウザーでの検証: 認証なしで保護されたページに移動します。他のユーザーに属するリソースへのアクセスを試みます。JavaScript を使用する act でスクリプトの内容をスキャンし、JavaScript ソースにハードコードされたシークレットがないか確認します。
カテゴリ E:クライアント側のセキュリティ(CLI)
| チェック ID | チェック項目 | 基準 | 方法 |
|---|---|---|---|
| CLI-01 | クライアント側ストレージに機密データがない | OWASP Storage | localStorage、sessionStorage、IndexedDB を検査 |
| CLI-02 | CDN リソースにサブリソース完全性(SRI)が設定されている | サプライチェーン | 外部スクリプト/スタイルの integrity 属性を確認 |
| CLI-03 | サードパーティスクリプトの一覧 | サプライチェーン | すべての外部スクリプトのソースを一覧表示 |
| CLI-04 | ユーザー入力に対して eval() や innerHTML を使用していない | CWE-79 | JavaScript をスキャンし、危険なパターンを検出 |
| CLI-05 | サービスワーカーのスコープが制限されている | クライアントセキュリティ | SW の登録スコープを確認 |
| CLI-06 | WebSocket 接続で WSS を使用している | トランスポート | WS 接続 URL を確認 |
| CLI-07 | コンソールログに機密データがない | 情報漏えい | get_browser_console_logs の出力を確認 |
| CLI-08 | クリックジャッキング対策が機能している | OWASP Clickjacking | ページを iframe に埋め込んでテスト |
ブラウザーでの検証: act を使って JavaScript から localStorage のキーを列挙し、SRI が設定されているかスクリプトタグを確認し、外部ドメインへのすべてのネットワークリクエストを一覧表示します。漏えいデータがないか、get_browser_console_logs を使って確認します。
カテゴリ F:依存関係とサプライチェーン(DEP)
| チェック ID | チェック項目 | 基準 | 方法 |
|---|---|---|---|
| DEP-01 | 既知の脆弱性を持つ依存関係がない | OWASP A06 / CWE-1035 | npm audit / pip audit を実行 |
| DEP-02 | ロックファイルが存在し、コミットされている | サプライチェーン | package-lock.json / yarn.lock / pnpm-lock.yaml があるか確認 |
| DEP-03 | 不要な依存関係がない | 攻撃対象領域 | 未使用のパッケージがないか確認 |
| DEP-04 | CDN リソースで SRI を使用している | サプライチェーン | integrity 属性を確認(CLI-02 と同じ) |
| DEP-05 | 依存関係にタイポスクワッティングのリスクがない | サプライチェーン | パッケージ名を既知のパッケージと照合 |
検証: 依存関係の監査コマンドを実行します。フェーズ 2 のコードベーススキャン結果と相互参照します。
フェーズ 4:レポート
以下に保存する、構造化されたレポートを生成します:shiplight/reports/security-review-{date}.md
# Security Review Report
**Date:** {date}
**URL:** {url}
**Auth mechanism:** {type}
**Attack surface:** {summary}
## Overall Score: {X}/10 | Confidence: {X}%
## Score Breakdown
| Category | Score | Findings |
|----------|-------|----------|
| HTTP Headers (HDR) | 6/10 | 1 critical, 2 high |
| Auth & Sessions (AUTH) | 4/10 | 2 critical, 1 high |
| Input Validation (INJ) | 7/10 | 1 high, 2 medium |
| Access Control (AC) | 8/10 | 1 medium |
| Client-Side (CLI) | 5/10 | 1 critical, 1 high |
| Dependencies (DEP) | 9/10 | 1 low |
## Findings
### CRITICAL
#### AUTH-01: JWT stored in localStorage — XSS leads to full account takeover
- **Standard:** OWASP ASVS 3.3.2 / CWE-922
- **Finding:** Access token stored in `localStorage` under key `auth_token`, accessible to any XSS payload
- **Evidence:** [screenshot of Application > Storage showing JWT]
- **Attack scenario:** Any XSS vulnerability (even via third-party script) can exfiltrate all user tokens
- **CVSS estimate:** 8.1 (High)
- **Confidence:** 95%
...
確信度スコア
- 90-100%:ブラウザーで悪用し、検証済み(例:XSS ペイロードの実行、権限のないアクセスを確認)
- 70-89%:検査で強い証拠を確認(例:ヘッダーの欠落、セキュリティ設定が不適切な Cookie フラグを確認)
- 50-69%:コードレベルの証拠はあるが、実行時に十分な検証ができていない
- 50% 未満:報告しないでください。推測の域を出ません
フェーズ 5:修正
各検出事項について、以下を提示します。
1. 修正方法
#### AUTH-01: JWT stored in localStorage
**Risk:** Any XSS → full account takeover
**File:** src/lib/auth.ts:47
**Current:** `localStorage.setItem('auth_token', jwt)`
**Fix:** Move to HttpOnly cookie set by the server
- Server: `Set-Cookie: token=<jwt>; HttpOnly; Secure; SameSite=Strict; Path=/`
- Client: Remove all localStorage token operations
- API calls: Cookies sent automatically (remove Authorization header)
**Migration steps:**
1. Add cookie-setting endpoint on server
2. Update API middleware to read from cookie
3. Remove client-side token storage
4. Update CORS to allow credentials
2. YAML 回帰テスト
- name: auth-01-no-tokens-in-localstorage
description: Verify authentication tokens are not stored in localStorage
severity: critical
standard: OWASP-ASVS-3.3.2
steps:
- URL: /login
- intent: Enter test username
action: fill
locator: "getByLabel('Email')"
value: "[email protected]"
- intent: Enter test password
action: fill
locator: "getByLabel('Password')"
value: "testpass123"
- intent: Click login button
action: click
locator: "getByRole('button', { name: 'Sign in' })"
- WAIT_UNTIL: User is logged in and dashboard is visible
timeout_seconds: 15
- description: Assert no auth tokens are stored in localStorage
js: |
const keys = Object.keys(localStorage);
const tokenKeys = keys.filter(k =>
/token|jwt|auth|session|access/i.test(k)
);
if (tokenKeys.length > 0) {
throw new Error(
`Auth tokens found in localStorage: ${tokenKeys.join(', ')}`
);
}
- VERIFY: No authentication tokens are stored in browser localStorage
すべての YAML テストを shiplight/tests/security-review.test.yaml に保存します。
ペネトレーションテストの深度レベル
--quick:ヘッダー(HDR)+ Cookie フラグ(AUTH-02/03/04)+ localStorage の確認(AUTH-01)+依存関係の監査(DEP-01)。約 2 分。- デフォルト:すべてのカテゴリ、標準ペイロード。約 10 分。
--thorough:すべてのカテゴリ+拡張インジェクションペイロード+ IDOR の列挙+ブルートフォーステスト+サードパーティスクリプトの完全な分析。約 20~30 分。
ヒント
- 常にテスト用の認証情報を使用し、本番環境の認証情報は使用しないでください
- XSS テストペイロードは非破壊的(
alert(1))で、ステージング環境で安全に使用できます - 認証済みのテストでは、ログイン後に
save_storage_stateでセッションを保存します - ブラウザーベースのレビューを行う前に
npm auditを実行し、既知の CVE を早期に検出します get_browser_console_logsを使用してください。多くのセキュリティ問題はコンソール警告を出力しますclose_sessionでセッションを閉じ、証拠にはgenerate_html_reportを使用します