laravel-owasp-security について
Laravel 13 アプリ向けのセキュリティ監査・コーディングガイドのスキルです。コードベースを OWASP Top 10 に照らして確認し、React + Inertia.js が検出された場合は追加チェックも行います。
主な機能
- 01OWASP Top 10 のコード監査
- 02React + Inertia.js のセキュリティ確認
- 03ファイルや機能単位の監査範囲指定
- 04問題箇所と修正案の提示
- 05Laravel の安全なコーディング規則
活用シーン
- 01リリース前の Laravel アプリ監査
- 02特定のコントローラーや機能の確認
- 03認証・決済・アップロード機能の開発
- 04Inertia ページのデータ露出確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ asyrafhussin/ agent-skills --skill laravel-owasp-securityインストール後、Claude Code で/laravel-owasp-securityを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
AGENTS.mdmetadata.jsonREADME.mdrules/_sections.md_template.mdsec-authentication-rate-limiting.mdsec-broken-access-control.mdsec-cryptographic-failures.mdsec-csrf-protection.mdsec-inertia-data-exposure.mdsec-injection-prevention.mdsec-security-misconfiguration.mdsec-xss-react-inertia.md詳細
Laravel OWASP セキュリティ
Laravel 13 + React/Inertia.js アプリケーション向けの、セキュリティ監査とセキュアコーディングの両方に使えるスキルです。コードベース全体に対して OWASP Top 10 の監査を実行するか、機能の構築時にセキュアコーディングのリファレンスとして使用します。
監査方法
ステップ 1:スタックを検出する
次の項目を確認し、プロジェクトで React + Inertia.js が使用されているか調べます。
app/Http/Middleware/HandleInertiaRequests.phpが存在するresources/js/に.tsxまたは.jsxファイルが含まれているcomposer.jsonにinertiajs/inertia-laravelが含まれているpackage.jsonに@inertiajs/reactが含まれている
検出された場合、レポートの先頭に次のように記載します。
"React + Inertia.js が検出されました — Laravel OWASP チェックリストと React/Inertia セキュリティチェックの両方を適用します。"
検出されなかった場合、次のように記載します。
"React/Inertia.js は検出されませんでした — Laravel OWASP チェックリストのみを適用します。"
ステップ 2:対象範囲を決定する
- 引数が指定されている場合(
$ARGUMENTS):指定されたファイルまたは機能のみを確認します - 引数が指定されていない場合:コードベース全体を確認します
ステップ 3:チェックリストを実行する
以下のすべての項目を確認します。それぞれについて、次のいずれかを出力します。
- PASS — 検証した内容を簡潔に確認します
- FAIL — 正確な
file:line、脆弱性の説明(ファイル内のコード、値、API キー、トークン、または .env の内容を再掲しないでください)、および修正の推奨事項 - N/A — このプロジェクトに該当しない場合
OWASP Top 10 チェックリスト
1. アクセス制御の不備(A01:2021)
- すべてのルートグループがロール別のミドルウェア(
auth、role:adminなど)で保護されている - リソースクエリが認証済みユーザーに限定されている —
->where('user_id', auth()->id()) - 所有権チェックのない直接的なオブジェクト参照がない
- リソースへのアクセス認可に Gates と Policies が使用されている
- フロントエンドのロールチェックがサーバー側でも適用されている — React UI のチェックだけに決して依存しない
2. 暗号化の失敗(A02:2021)
- パスワードが
Hash::make()または'hashed'Eloquent キャストでハッシュ化されている — 平文で保存しない - パスワードのハッシュ化に MD5 または SHA1 が使用されていない
- 機密フィールド(API キー、シークレット)が
Crypt::encryptString()または'encrypted'Eloquent キャストで暗号化されている -
APP_KEYが長く、ランダムで、環境ごとに固有である - 機密性の高い単発操作(パスワードリセット、メール認証)に署名付き URL(
URL::signedRoute())が使用されている
3. インジェクション(A03:2021)
SQL と一括代入:
-
whereRaw()、selectRaw()、orderByRaw()に文字列連結がない —?バインディングを使用する - ホワイトリストなしに、ユーザー入力からカラム名を決定していない
-
$request->all()をcreate()、fill()、またはupdate()に直接渡していない - 未検証のユーザー入力を使って
forceFill()またはforceCreate()を呼び出していない - モデルで
$fillableが明示的に定義されている —$guarded = []を使用していない - コントローラーで一括操作に
$request->validated()を使用している
XSS — Blade と React:
- 信頼できないデータを含む Blade テンプレートで
{!! $userInput !!}を使用していない - ユーザーが指定した Blade 出力にはすべて
{{ }}を使用している - 事前に
DOMPurify.sanitize()を適用せずに、React でdangerouslySetInnerHTMLを使用していない - 未検証のユーザー入力から
hrefおよびsrc属性を設定していない - ユーザーが制御できる文字列を使って
eval()、new Function()、またはsetTimeout(string)を使用していない - 外部 CDN のスクリプトで Subresource Integrity(
integrity="sha384-...")を使用している
4. 安全でない設計(A04:2021)
- ビジネスロジックがサーバー側で強制されている — 価格、合計額、割引をクライアント入力から信頼していない
- 機密性の高い操作に追加の確認(アカウント削除時のパスワード再入力など)を求めている
- アイテムごとの認可チェックを行わない一括操作エンドポイントがない
- 管理者限定機能が独立したミドルウェアで保護されている — UI で非表示にするだけではない
- 支払い金額と登録状態がサーバー側で計算されており、フォーム入力として渡されていない
5. セキュリティ設定の不備(A05:2021)
- 本番環境で
APP_DEBUG=falseに設定されている -
.envが.gitignoreに含まれており、コミットされていない - 本番環境のデータベースでは、root/admin ではなく権限を制限したユーザーを使用している
-
storage/とbootstrap/cache/の権限が適切に設定されている(全ユーザーが書き込み可能な状態ではない) -
APP_KEYが設定されており、環境ごとに一意である - 認証が必要な API ルートで、CORS の
allowed_originsが['*']になっていない
6. 脆弱で古いコンポーネント(A06:2021)
-
composer auditで既知の CVE が検出されない -
npm auditで既知の CVE が検出されない - Laravel フレームワークがサポート対象のバージョンである
7. 識別および認証の失敗(A07:2021)
認証:
- 独自実装の認証ではなく、Laravel Breeze、Fortify、または Jetstream を使用している
- パスワードが bcrypt または argon2(Laravel のデフォルト)でハッシュ化されている
- ログインルートにレート制限が設定されている —
throttleミドルウェア、またはLoginRequestのRateLimiterを使用 - パスワードリセットとメール認証のルートにレート制限が設定されている
- 決済ルートと機密性の高い操作ルートに適切なレート制限が設定されている
- ログイン成功後に
session()->regenerate()が呼び出されている
Cookie とセッション:
-
config/session.phpでhttp_only = trueに設定されている -
config/session.phpでsame_site = laxまたはstrictに設定されている -
config/session.phpでsecure = trueまたはnull(HTTPS の場合は自動設定)に設定されている -
lifetimeが妥当な値に設定されている(ほとんどのアプリでは 15〜30 分を推奨) - サブドメインが必要な場合を除き、
domain = nullに設定されている -
EncryptCookiesミドルウェアが web グループに含まれている
8. ソフトウェアとデータの完全性に関する失敗(A08:2021)
CSRF:
-
VerifyCsrfTokenミドルウェアが web グループで有効になっている - CSRF の対象外は、ステートレスなルート(Webhook、外部コールバック)のみである
- Inertia を使用しないすべての POST フォームで
@csrfディレクティブを使用している -
validateCsrfTokens(except: [...])で対象外にしているルートに正当な理由がある
デシリアライズ:
-
unserialize($request->input(...))を使用していない -
eval($request->input(...))を使用していない -
extract($request->all())を使用していない
9. セキュリティログ記録と監視の失敗(A09:2021)
- ログイン失敗が IP アドレスと識別子とともに記録されている
- 決済の失敗と例外が記録されている
- ログエントリにパスワードやシークレットがそのまま含まれていない
- 監視が導入されている(Laravel Telescope、Sentry など)
10. サーバーサイドリクエストフォージェリ — SSRF(A10:2021)
- URL を検証せずに
Http::get($request->input('url'))を使用していない - ユーザーが指定した URL を許可リストまたはスキームチェックで検証している
- ユーザーが指定した URL から内部ネットワークアドレスへのアクセスをブロックしている
追加のチェック項目
OWASP Top 10 には含まれませんが、Laravel アプリケーションでは重要です。
コマンドインジェクションと危険な関数
- ユーザー入力を使って
exec()、shell_exec()、system()、passthru()を呼び出していない - オープンリダイレクトがない — URL を検証せずに
redirect($request->input('url'))を使用していない - ファイルアップロードで
mimes:とmax:を検証している — ファイル名をユーザー入力から直接生成していない
セキュリティヘッダー
-
Content-Security-Policyが設定されている — 可能であれば nonce(Vite::useCspNonce())を使用 -
X-Frame-Optionsが設定されている -
X-Content-Type-Optionsが設定されている - HTTPS 用に
Strict-Transport-Securityが設定されている -
Referrer-Policyが設定されている -
Permissions-Policyが設定されている
React + Inertia.js のチェック項目
ステップ 1 で React + Inertia.js が検出された場合にのみ実行してください。
R1. React コンポーネントの XSS
- 先に
DOMPurify.sanitize()を実行せずにdangerouslySetInnerHTML={{ __html: userInput }}を使用していない -
hrefおよびsrc属性に未検証のユーザー入力を設定していない —javascript:URL はスクリプトを実行します - ユーザーが制御する文字列を使って
eval()、new Function()、またはsetTimeout(string)を呼び出していない - ユーザー入力のリンクでスキームを検証している(
https://またはhttp://のみ)
R2. Inertia.js のデータ漏えい(重大)
-
HandleInertiaRequests::share()でパスワード、トークン、内部専用フラグが公開されない - コントローラーでは
->only([...])または API リソースを使用し、モデルのtoArray()をそのまま使用しない - すべての Inertia props は公開情報として扱う — 初回読み込み時に
data-pageHTML 属性で表示されます - 決済のシークレットキーや管理者専用の認証情報を Inertia props として渡さない
- 機密データを含むページでは Inertia v2 の履歴暗号化を有効にする
R3. Inertia.js の CSRF
- Inertia の
X-XSRF-TOKENヘッダーを無効にしない - Inertia のルーターを経由しないカスタムの
fetchまたはaxios呼び出しでは、CSRF トークンを手動で含める - CSRF の除外対象とするのは、Webhook/コールバックルートのみ
R4. React での認証状態
- Inertia prop の
auth.userから、パスワードハッシュ、remember トークン、2FA シークレットを除外する - ロール/権限のチェックはサーバー側で適用する — React 側のチェックは UI 専用です
-
auth.userには UI が実際に必要とするフィールドのみを含める
R5. ブラウザー内の機密データ
- React コンポーネントや TypeScript ファイルに API キーやシークレットをハードコードしない
-
localStorageやsessionStorageに機密データを保存しない — HttpOnly Cookie を使用する -
VITE_*環境変数にシークレットを含めない — 設計上、公開されています
R6. 依存関係のセキュリティ
-
npm auditを実行し、React または Inertia パッケージに高または重大な CVE がないことを確認する - サポート対象のバージョンの React を使用する
- サードパーティのコンポーネントライブラリに既知の CVE がないか確認する
出力形式
監査レポートは次の形式で構成してください。
## Laravel OWASP Security Audit Report
> React + Inertia.js detected — Laravel OWASP checklist AND React/Inertia security checks will both be applied.
### 1. Broken Access Control (A01:2021)
- **PASS** `app/Http/Middleware/RoleMiddleware.php` — role middleware applied to all route groups
- **FAIL** `app/Http/Controllers/PaymentController.php:42` — Payment model fetched without ownership check (direct object reference exposure). Fix: scope the query to the authenticated user.
[Continue for all 10 OWASP checks + Additional Checks + R1–R6 React/Inertia checks]
---
## Summary
### Critical Issues (fix immediately)
1. ...
### Warnings (fix soon)
1. ...
### Passed
X checks passed.
### Recommended Commands
composer audit
npm audit
ガイダンスを参照するタイミング
次の場合はルールファイルを参照してください。
- 認証またはパスワード処理を実装するとき
- 決済または Webhook 連携を構築するとき
- ファイルのアップロードまたはダウンロードのロジックを記述するとき
- 管理者向けまたはロールベースのアクセス制御を設計するとき
- ユーザー入力を受け取る API エンドポイントを構築するとき
- React コンポーネントで
dangerouslySetInnerHTMLを使用するとき - Laravel コントローラーから Inertia props にデータを渡すとき
優先度別のルールカテゴリ
| 優先度 | カテゴリ | 影響度 | ルールファイル |
|---|---|---|---|
| 1 | アクセス制御の不備 | CRITICAL | sec-broken-access-control |
| 2 | 暗号化の失敗 | CRITICAL | sec-cryptographic-failures |
| 3 | インジェクションの防止 | CRITICAL | sec-injection-prevention |
| 4 | XSS と React/Inertia | HIGH | sec-xss-react-inertia |
| 5 | CSRF の保護 | HIGH | sec-csrf-protection |
| 6 | セキュリティ設定の不備 | HIGH | sec-security-misconfiguration |
| 7 | 認証とレート制限 | HIGH | sec-authentication-rate-limiting |
| 8 | Inertia のデータ漏えい | HIGH | sec-inertia-data-exposure |
クイックリファレンス
1. アクセス制御の不備(CRITICAL)
sec-broken-access-control— ミドルウェア、所有権チェック、ポリシー、スコープ付きクエリ
2. 暗号化の失敗(CRITICAL)
sec-cryptographic-failures— パスワードのハッシュ化、暗号化キャスト、署名付き URL
3. インジェクションの防止(CRITICAL)
sec-injection-prevention— SQL インジェクション、一括代入、raw クエリのバインディング
4. XSS と React/Inertia(HIGH)
sec-xss-react-inertia— dangerouslySetInnerHTML、DOMPurify、href/src の検証
5. CSRF の保護(HIGH)
sec-csrf-protection— VerifyCsrfToken、Webhook の除外、Inertia の CSRF
6. セキュリティ設定の不備(HIGH)
sec-security-misconfiguration— APP_DEBUG、APP_KEY、セキュリティヘッダー、CORS
7. 認証とレート制限(HIGH)
sec-authentication-rate-limiting— スロットリング、セッションの再生成、ブルートフォース攻撃の防止
8. Inertia のデータ漏えい(HIGH)
sec-inertia-data-exposure— data-page 属性の露出、シークレットを含む props、API リソース
使用方法
詳しい説明とコード例については、個々のルールファイルを読んでください。
rules/sec-broken-access-control.md
rules/sec-cryptographic-failures.md
rules/sec-injection-prevention.md
rules/sec-xss-react-inertia.md
rules/sec-csrf-protection.md
rules/sec-security-misconfiguration.md
rules/sec-authentication-rate-limiting.md
rules/sec-inertia-data-exposure.md
各ルールファイルには次の内容が含まれています。
- メタデータ(タイトル、影響度、タグ)を含む YAML frontmatter
- Laravel/React のコンテキストで重要となる理由
- 説明付きの誤ったコード例
- 修正を示す正しいコード例
- Laravel 13 および PHP 8.3+ 固有のコンテキスト
コンパイル済みドキュメント全体
すべてのルールを展開した完全なガイドについては、AGENTS.md をご覧ください。