16.

Laravel CSRF トークンを Ajax で送信する方法|meta タグ / X-CSRF-TOKEN ヘッダ

編集
この記事の要点
  • Laravel で Ajax リクエストに CSRF トークンを付与する方法
  • HTML の を埋め込む
  • JS 側で X-CSRF-TOKEN ヘッダにトークンを付ける(jQuery / axios / fetch)
  • 419 Page Expired エラーの主因 — フォームには @csrf ディレクティブ
  • API ルート (routes/api.php) は CSRF 不要 (Sanctum / Passport トークン認証)

CSRF とは

CSRF (Cross-Site Request Forgery) は悪意のあるサイトが別ドメインの認証セッションを乗っ取って勝手にリクエストを送る攻撃です。Laravel は自動で対策として CSRF トークンをセッションに紐付け、各 POST/PUT/PATCH/DELETE リクエストで検証します。

HTML フォームの場合(基本)

@csrf {{-- Blade ディレクティブが を出力 --}}

これで通常のフォーム送信は CSRF 検証に通ります。問題は Ajax 経由のリクエスト。

Ajax の場合: meta タグでトークンを公開

Laravel 公式推奨の方式。 内に でトークンを埋め込み、JS から読み取って送信:

{{-- resources/views/layouts/app.blade.php --}}



    
    {{-- 他の head 要素 --}}


    @yield('content')

JavaScript からの送信

jQuery

// グローバル設定: 全 Ajax リクエストに自動で付ける
$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
});

// あとは通常通り
$.ajax({
    url: '/posts',
    method: 'POST',
    data: { title: 'Hello' }
});

axios

// resources/js/bootstrap.js (Laravel デフォルト)
window.axios = require('axios');
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

// CSRF トークン自動付与
const token = document.head.querySelector('meta[name="csrf-token"]');
if (token) {
    window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
}

// 使う側
axios.post('/posts', { title: 'Hello' });

fetch API

const csrfToken = document.querySelector('meta[name="csrf-token"]').content;

fetch('/posts', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'X-CSRF-TOKEN': csrfToken,
        'X-Requested-With': 'XMLHttpRequest',
        'Accept': 'application/json'
    },
    body: JSON.stringify({ title: 'Hello' })
})
.then(res => res.json())
.then(data => console.log(data));

VerifyCsrfToken ミドルウェア

CSRF 検証は App\Http\Middleware\VerifyCsrfToken ミドルウェアが行います。検証されるリクエストメソッド:

  • POST / PUT / PATCH / DELETE: 検証対象
  • GET / HEAD / OPTIONS: 検証スキップ(仕様上、副作用なしのため)

検証順序: ① _token フィールド → ② X-CSRF-TOKEN ヘッダ → ③ X-XSRF-TOKEN ヘッダ(Cookie 由来、Sanctum SPA 用)

特定 URL を CSRF 検証から除外

外部 Webhook など、CSRF 検証ができない URL は除外:

// app/Http/Middleware/VerifyCsrfToken.php
namespace App\Http\Middleware;

use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;

class VerifyCsrfToken extends Middleware {
    protected $except = [
        'stripe/webhook/*',
        'api/external/*',
    ];
}

419 Page Expired エラー

Ajax を送信したら 419 が返るときの原因と対処:

原因対処
X-CSRF-TOKEN ヘッダを付けていない$.ajaxSetup または axios.defaults で自動付与
meta タグが Blade テンプレートにない を head に追加
セッションが切れたログインし直す。session.lifetime を延長
キャッシュされた古いトークンハードリロード (Ctrl + Shift + R)
サブドメイン跨ぎconfig('session.domain') = '.example.com' で共有

API ルートでは CSRF 不要

routes/api.php に書いたルートは api ミドルウェアグループに属し、CSRF 検証されません。代わりに API トークン認証を使います:

// routes/api.php (CSRF なし、Sanctum トークン認証)
Route::middleware('auth:sanctum')->post('/posts', function (Request $request) {
    return Post::create($request->all());
});

// クライアント側は Bearer トークンを送る
fetch('/api/posts', {
    method: 'POST',
    headers: {
        'Authorization': 'Bearer ' + apiToken,
        'Content-Type': 'application/json'
    },
    body: JSON.stringify(data)
});

SPA との連携(Laravel Sanctum + axios)

同一ドメインの Vue / React SPA からは Sanctum の Cookie 認証 + CSRF 自動処理が便利:

// 1. /sanctum/csrf-cookie を一度叩いて XSRF-TOKEN Cookie を取得
await axios.get('/sanctum/csrf-cookie');

// 2. axios は XSRF-TOKEN Cookie を読んで X-XSRF-TOKEN ヘッダに自動付与
await axios.post('/api/login', { email, password });

// 以降のリクエストもセッション Cookie で認証される
const user = await axios.get('/api/user');

セキュリティ補足

  • CSRF トークンは画面ごとに再生成されるものではない。セッションごとに 1 つ
  • トークンはセッション Cookie と紐付くため、Cookie が盗まれれば CSRF 対策は意味をなさない → HTTPS 必須
  • SameSite Cookie 属性(Lax/Strict)も併用すると守りが厚くなる(Laravel デフォルトで Lax)
  • CSRF と XSS は別の攻撃。両方対策する必要がある
編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. 環境構築とプロジェクト/アプリの作成
  2. MVC(MVT)のそれぞれの使い方と説明
  3. データベースへの接続と操作
  4. Django Administration
  5. git管理
  6. エラー一覧
  7. バージョンの確認方法
  8. ログ出力方法
  9. SQLのログ出力方法
  10. ログのローテート設定
  11. settings.pyの定数にアクセスする方法
  12. 本番環境へのインストールとアプリのデプロイ(apache編)
  13. 本番環境へのインストールとアプリのデプロイ(nginx編)
  14. djangoアプリの本番の開始URLを変更する
  15. 静的(static)ファイルの置き場所と読み込み(画像、css、js )
  16. CSRFトークンをAjaxで使用する方法
  17. ajaxの使用例(POST編)
  18. ファイルのアップロードとファイルの名前
  19. クイックスタート/チュートリアル
  20. ログイン機能
  21. テンプレート側のログイン判定
  22. ビュー側のログイン判定
  23. 管理者ユーザーの作成/判定と管理画面
  24. モデルのjson化とレスポンス
  25. runserverでポートを指定する方法
  26. cronによるバッチ実行
  27. テンプレートで利用する共通のcontextを定義する方法
  28. プログラムが本番サーバーで反映されない場合の対処法
  29. APIの作成
  30. cron用コマンド・ファイルの作成