MeWrite Docs

CSRF Token Mismatch

CSRFトークンの検証に失敗しフォーム送信やAPIリクエストが拒否されるエラー

概要

CSRF Token Mismatch は、Cross-Site Request Forgery(CSRF)対策のトークン検証に失敗した際に発生するエラーです。フォーム送信やAPIリクエストに含まれるトークンがサーバー側の期待値と一致しない場合に拒否されます。

エラーメッセージ

419 | Page Expired (Laravel)
Forbidden (403): CSRF verification failed. Request aborted. (Django)
ActionController::InvalidAuthenticityToken (Rails)
Error: CSRF token mismatch (Express/csurf)

原因

  1. トークンの欠落: フォームやリクエストにCSRFトークンが含まれていない
  2. セッション切れ: セッションが期限切れになりトークンが無効化
  3. キャッシュされたページ: CDNやブラウザキャッシュにより古いトークンが使われている
  4. 複数タブの操作: 別タブでログアウト後に元のタブで送信
  5. SPA での設定不備: Ajax/fetchリクエストにトークンが付与されていない

解決策

1. Laravel

1
2
3
4
5
6
{{-- Blade テンプレートでフォームにトークンを含める --}}
<form method="POST" action="/submit">
    @csrf
    <input type="text" name="name">
    <button type="submit">送信</button>
</form>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// Ajax リクエストの場合
// meta タグからトークンを取得
const token = document.querySelector('meta[name="csrf-token"]').getAttribute('content');

fetch('/api/submit', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'X-CSRF-TOKEN': token
    },
    body: JSON.stringify({ name: 'test' })
});

// axios の場合(Laravel はデフォルトで設定済み)
// resources/js/bootstrap.js
axios.defaults.headers.common['X-CSRF-TOKEN'] =
    document.querySelector('meta[name="csrf-token"]').getAttribute('content');
1
2
3
4
5
6
7
8
9
// 特定のルートでCSRF検証を除外(Webhook等)
// app/Http/Middleware/VerifyCsrfToken.php
class VerifyCsrfToken extends Middleware
{
    protected $except = [
        'api/webhook/*',
        'stripe/webhook',
    ];
}

2. Django

1
2
3
4
5
6
<!-- テンプレートでトークンを含める -->
<form method="POST">
    {% csrf_token %}
    <input type="text" name="name">
    <button type="submit">送信</button>
</form>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Ajax リクエストの場合
function getCookie(name) {
    let cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        const cookies = document.cookie.split(';');
        for (let i = 0; i < cookies.length; i++) {
            const cookie = cookies[i].trim();
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}

fetch('/api/submit/', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'X-CSRFToken': getCookie('csrftoken')
    },
    body: JSON.stringify({ name: 'test' })
});
1
2
3
4
5
6
7
# 特定のビューでCSRF検証を除外
from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def webhook_view(request):
    # Webhook など外部からのリクエスト
    pass

3. Rails

<%# フォームヘルパーは自動でトークンを含める %>
<%= form_with url: '/submit', method: :post do |f| %>
  <%= f.text_field :name %>
  <%= f.submit '送信' %>
<% end %>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// Ajax リクエストの場合
const token = document.querySelector('meta[name="csrf-token"]').getAttribute('content');

fetch('/api/submit', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'X-CSRF-Token': token
    },
    body: JSON.stringify({ name: 'test' })
});
1
2
3
4
5
6
7
8
# 特定のアクションでCSRF検証をスキップ
class WebhooksController < ApplicationController
  skip_before_action :verify_authenticity_token, only: [:create]

  def create
    # Webhook 処理
  end
end

4. Express.js(csurf / csrf-csrf)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
const { doubleCsrf } = require('csrf-csrf');

const { generateToken, doubleCsrfProtection } = doubleCsrf({
  getSecret: () => process.env.CSRF_SECRET,
  cookieName: '_csrf',
  cookieOptions: {
    httpOnly: true,
    sameSite: 'lax',
    secure: process.env.NODE_ENV === 'production'
  }
});

app.use(doubleCsrfProtection);

// トークンをテンプレートに渡す
app.get('/form', (req, res) => {
  res.render('form', { csrfToken: generateToken(req, res) });
});

5. SPA(React/Vue)でのCSRF対策

1
2
3
4
5
6
7
// Cookie-to-Header パターン
// サーバーがCSRFトークンをCookieに設定 → フロントエンドがヘッダーに付与

// axios のグローバル設定
axios.defaults.xsrfCookieName = 'csrftoken';    // Cookie名
axios.defaults.xsrfHeaderName = 'X-CSRFToken';   // ヘッダー名
axios.defaults.withCredentials = true;

関連エラー

Security の他のエラー

最終更新: 2026-02-03