メインコンテンツへスキップ

イントロダクション

CSRF(Cross-Site Request Forgery)は、ログイン済みユーザーになりすまして意図しないリクエストを送らせる攻撃です。 例えば、あなたのアプリに POST /user/email があり、メールアドレス変更を受け付けているとします。攻撃者が別サイトでこのURLに自動送信するフォームを仕込むと、ユーザーが気づかないうちにメールアドレスが変更される可能性があります。 Laravel 13では、web ミドルウェアグループに含まれる仕組みにより、CSRF保護がデフォルトで有効です。

CSRF攻撃の防止

Laravelの PreventRequestForgery ミドルウェアは、次の2層でCSRFを防ぎます。
  1. Origin検証Sec-Fetch-Site ヘッダー)
  2. トークン検証(セッション単位のCSRFトークン)
まずOriginを確認し、判定できない場合や失敗した場合はトークン検証にフォールバックします。

Origin検証

Laravelは最初に Sec-Fetch-Site を確認し、同一Originからのリクエストかどうかを判定します。これはHTTPS環境で特に有効です。 Origin検証が通れば、その時点でリクエストは許可されます。通らない場合は、従来どおりCSRFトークン検証が実行されます。
Sec-Fetch-Site はHTTPS接続で利用されるのが前提です。HTTP環境ではOrigin検証が機能せず、トークン検証が主な防御になります。

Origin-onlyモード

トークン検証へのフォールバックを無効化し、Origin検証のみで判定することもできます。
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Middleware;

return Application::configure(basePath: dirname(__DIR__))
    ->withMiddleware(function (Middleware $middleware): void {
        $middleware->preventRequestForgery(originOnly: true);
    });
Origin-onlyモードでは、Origin検証に失敗したリクエストは 419 ではなく 403 を返します。 サブドメイン間リクエストなどでsame-siteを許可したい場合は、allowSameSite を設定します。
$middleware->preventRequestForgery(allowSameSite: true);

トークン検証

LaravelはセッションごとにCSRFトークンを生成します。csrf_token() またはセッションから取得できます。
use Illuminate\Http\Request;

Route::get('/token', function (Request $request) {
    $tokenFromSession = $request->session()->token();
    $tokenFromHelper = csrf_token();
});
web ルートで POSTPUTPATCHDELETE のフォームを作る場合は、必ず @csrf を含めます。
<form method="POST" action="/profile">
    @csrf

    <!-- 同等のhidden input -->
    <input type="hidden" name="_token" value="{{ csrf_token() }}" />
</form>

URIの除外

StripeのWebhookのように外部サービスから送られるリクエストでは、特定URIをCSRF保護から除外することがあります。
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Middleware;

return Application::configure(basePath: dirname(__DIR__))
    ->withMiddleware(function (Middleware $middleware): void {
        $middleware->preventRequestForgery(except: [
            'stripe/*',
            'http://example.com/foo/bar',
            'http://example.com/foo/*',
        ]);
    });
可能であればWebhookルートは web ミドルウェアグループの外に配置し、除外設定は最小限にしてください。

X-CSRF-TOKEN ヘッダー

Laravelはフォームの _token だけでなく、X-CSRF-TOKEN ヘッダーも検証します。 まずトークンをmetaタグに出力します。
<meta name="csrf-token" content="{{ csrf_token() }}">
その値をAJAXリクエストヘッダーに付与します。
$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': document
            .querySelector('meta[name="csrf-token"]')
            .getAttribute('content'),
    },
});

X-XSRF-TOKEN ヘッダー

Laravelは暗号化された XSRF-TOKEN Cookieも送信します。AxiosやAngularは、同一Originリクエスト時にこの値を X-XSRF-TOKEN ヘッダーへ自動設定できます。 そのため、SPAやAJAXの実装ではヘッダー設定を手動で書かなくてもCSRF対策が有効になるケースがあります。

SPAでの考慮事項

SPAでLaravelをAPIバックエンドとして使う場合、まずCSRF Cookieを取得してからログインリクエストを送ります。
await axios.get('/sanctum/csrf-cookie');
await axios.post('/login', {
    email: '[email protected]',
    password: 'password',
});
詳細は Sanctum を参照してください。
最終更新日 2026年5月26日