【Python】DjangoのCSRFエラー「403 Forbidden」解決方法
DjangoでフォームやAPIリクエストを送信したとき、403 Forbidden - CSRF verification failed. Request aborted.
というエラーに遭遇したことはありませんか?
これはDjangoのCSRF(Cross Site Request Forgery)保護機構によって、セキュリティ上の問題が検出されたときに表示されるエラーです。
この記事では、CSRFエラーの意味とその対処方法を、わかりやすくチェックリスト形式で対処します。
Djangoで「CSRF verification failed」が出る理由とは?
Djangoには、悪意あるクロスサイト攻撃を防ぐための「CSRF保護機構」が標準搭載されています。
ユーザーの意図しないPOSTリクエストによってデータ改ざんや情報漏洩が起こらないよう、CSRFトークンという仕組みを使ってリクエストの正当性を確認しています。
このチェックに失敗すると、403 Forbiddenエラーが返されます。
開発中に頻出するため、正しい原因を突き止めて適切に対応することが重要です。
エラーメッセージの読み解き方
DjangoでDEBUG = True
の設定時、以下のような詳細なエラー画面が表示されます。
Forbidden (403)
CSRF verification failed. Request aborted.
Reason given for failure:
Origin checking failed - https://example.com does not match any trusted origins.
この例では、リクエストのOrigin
が信頼されていないことが原因でブロックされています。
DEBUG = False
の場合は、簡素なエラー画面のみ表示され、詳細情報は省略されます。
本番環境ではセキュリティ上の理由から、詳細な情報は非表示になる仕様です。
原因と解決策チェックリスト
CSRFトークンがフォームに含まれていない
テンプレート内でPOSTフォームを作る際は、必ず{% csrf_token %}
をフォームタグの中に含めましょう。
|
|
トークンが埋め込まれていないと、リクエストはすべて拒否されます。
ブラウザがCookieをブロックしている
CSRFトークンはDjangoがCookieと連動して管理しています。
ブラウザの設定や拡張機能がCookieをブロックしている場合、エラーが発生します。
とくにSafariやChromeのプライバシー設定は要注意です。開発中はCookieの保存が有効になっているか確認しましょう。
JavaScriptによる非同期POSTでトークンが付与されていない
JavaScriptからAJAXやfetch APIでPOSTリクエストを送信する場合、ヘッダーにCSRFトークンを明示的に含める必要があります。
例(JavaScript):
|
|
Django公式ドキュメントにもあるように、csrftoken
はクッキーから取得し、X-CSRFToken
ヘッダーにセットします。
ALLOWED_HOSTS
または CSRF_TRUSTED_ORIGINS
の不備
Django 4.0以降では、クロスオリジンからのPOSTリクエストを許可するために CSRF_TRUSTED_ORIGINS
を正しく設定する必要があります。
例(settings.py
):
|
|
また、ALLOWED_HOSTS
に対象ドメインを追加することも忘れずに。
HTTPSとHTTPが混在している
HTTPSで配信されているページから、HTTPで送信されたリクエストは「安全でない」と判断されてブロックされます。
とくにフロントエンドとAPIが別ドメイン・別プロトコルで動いている場合に起こりやすいです。
→ 全体をHTTPSに統一するのが基本です。
セッションが切れてトークンが無効になった
ログイン後に時間が経過してからPOST操作をすると、セッショントークンの期限切れでエラーが発生することがあります。
→ ページをリロードしてトークンを更新することで解消できます。
よくあるケース別の対処法
ログイン後にエラーが出る
ログイン処理後はCSRFトークンが再生成されるため、ブラウザの「戻る」ボタンでフォームを開いた場合、トークンが古い状態になります。
→ ログイン後は必ずリダイレクトさせ、新しいトークンを生成させるのが安全です。
フロントエンド(React/Vueなど)からAPIを叩いたとき
SPA構成では、CSRFトークンの取得・保持をJavaScript側で行う必要があります。
→ Djangoテンプレートからトークンを埋め込む、あるいは /api/csrf/
のような専用エンドポイントを作って取得させましょう。
管理画面にログインできないとき
管理画面ログインでCSRFエラーが出る場合、ブラウザのCookie設定やプロキシ構成が影響していることがあります。
→ Cookie制限やX-Forwarded-Proto
ヘッダーを見直してください。
セキュリティを損なわない対処のポイント
CSRFチェックを無効化するのは推奨されません。
開発中にどうしてもチェックを外す必要がある場合は、以下のようにビュー関数単位で一時的に無効化します。
|
|
しかし、本番環境ではCSRF保護を常に有効にし、安全な実装を徹底しましょう。
まとめ:CSRFエラーは「疑ってチェック」から始めよう
CSRFエラーはDjangoが安全に動作している証拠でもあります。
焦らず以下のチェックリストを辿って確認しましょう。
- フォームに
{% csrf_token %}
を含めたか - Cookieがブロックされていないか
- JavaScript経由のリクエストにトークンを付与したか
CSRF_TRUSTED_ORIGINS
に正しいドメインを設定したか- HTTPとHTTPSの混在がないか
- セッションやログイン直後の動作に問題がないか
これらを確認するだけで、大半の403エラーは解決できます。