高校倫理1440106 views
中学理科1630641 views
高校化学2924392 views
英語613639 views
MathPython497343 views
りんご209490 views
Computer368106 views
高校生物551766 views
いろは3010814 views
数学講師2886227 views
Help
Tools
NewsSpreadsheetCalendarSlidesTier ListPen ToolIllustrationCrayonPixel ArtASCII ArtPerspectiveEndless StairsGraphMind MapER DiagramFamily TreeMemeCurved TextImage EditorMosaicRetro FilterPencil SketchOCR/HighlighterMakeup EditorFaviconVideo TrimmerScrolling VideoVideo TitleColor PickerColor ExtractorBonfireFireworksWater RippleWater SplashBreaking GlassWood GrainMarble TextureCSS ButtonIcon MakerBar ChartGrouped Bar ChartStacked Bar ChartPie ChartLine ChartArea ChartStacked Area ChartScatter Plot3D Bar Chart3D Pie ChartBar Chart RaceBubble ChartPopulation PyramidPictogramEarningsCandlestick ChartInvestment RiskMortgage SimulatorCalculatorMatrix CalculatorFunction GraphPolynomial ExpansionVenn DiagramField VisualizerRubik's Cube Group TheoryTraveling SalesmanVoronoi and DelaunayFractalColumn ArithmeticDraw Math FiguresArithmetic AnimationArithmetic Word ProblemsCounting with Tree DiagramsCube NetsCross SectionsMotion PathMechanicsWavesLight and LensesThermodynamicsHow Semiconductors WorkMolecular StructuresAtomic OrbitalsElectrochemical CellsChemical EquilibriumCrystal LatticesBuffer pHComplex IonsDNA Double HelixCell DivisionMembrane ChannelsNerve ImpulseRock ClassificationWeatherConstellationsSolar and Lunar Eclipses3D ModelingFloor PlanSeismic StructuresIntersection TurnMaglevCooking AnimationOrigamiLive Viewer CountGeoJSON MapRailway MapPopulation MapCrime MapLand Price MapSchool MapShrine and Castle MapHouse of Representatives MapWord MapSolitaireReversiHakoiri MusumeChessHamburgerRippleSlide Puzzle MakerNeon PinballNovel MakerJapanese Typing PracticePiano Score EditorMusic Theory

English

Django の CSRF 対策の仕組みと csrf_token タグ

CSRF(Cross-Site Request Forgery)は、ユーザーが意図しないリクエストを別サイトから送信させる攻撃手法です。Django はこの攻撃をフレームワークレベルで防御しており、開発者は {% csrf_token %} をテンプレートに書くだけで対策が完了します。

CSRF 攻撃とは

CSRF 攻撃のシナリオを簡単に整理します。

ユーザーが銀行サイトにログイン済みの状態で、攻撃者のサイトを訪問する
攻撃者のサイトに埋め込まれたフォームが、銀行サイトへの送金リクエストを自動送信する
銀行サイトはユーザーのセッションクッキーを受け取るため、正規のリクエストとして処理してしまう

ユーザー自身はボタンを押した覚えがないのに、ログイン済みのセッションを悪用されてしまうわけです。

ユーザーが正規サイトにログイン中

攻撃者サイトが裏でリクエストを送信

セッションクッキーが自動送信される

正規サイトが正当なリクエストと誤認

Django の CSRF 防御の仕組み

Django は「トークンベース」の防御を採用しています。仕組みは次のとおりです。

フォームを表示するとき、Django はランダムなトークン(CSRF トークン)を生成し、フォームの hidden フィールドとクッキーの両方に埋め込みます。POST リクエストを受け取ったとき、Django はフォームから送信されたトークンとクッキーのトークンを比較し、一致しなければ 403 エラーを返します。

攻撃者はユーザーのクッキーを読み取れないため、正しいトークンをフォームに埋め込むことができません。これにより、外部サイトからの不正なリクエストがブロックされます。

csrf_token タグの使い方

テンプレートの <form> タグ内に {% csrf_token %} を記述するだけで、hidden フィールドが自動生成されます。

<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">送信</button>
</form>

レンダリングされた HTML を見ると、次のような hidden フィールドが挿入されていることがわかります。

<input type="hidden" name="csrfmiddlewaretoken"
       value="Ek8Qx7...(ランダムなトークン)">

この 1 行を忘れるだけで、POST リクエストはすべて 403 Forbidden になります。Django を使い始めた直後に最もよく遭遇するエラーの 1 つが、この {% csrf_token %} の書き忘れです。

CsrfViewMiddleware

CSRF 防御を担当しているのは django.middleware.csrf.CsrfViewMiddleware です。settings.pyMIDDLEWARE にデフォルトで含まれています。

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

このミドルウェアは以下のルールで動作します。

GET・HEAD・OPTIONS・TRACE

安全なメソッドとみなし、CSRF 検証をスキップする。データを変更しないリクエストにはトークンは不要。

POST・PUT・PATCH・DELETE

データを変更する可能性があるため、CSRF トークンを検証する。トークンが不一致または欠落していれば 403 エラーを返す。

AJAX リクエストでの CSRF 対策

JavaScript から POST リクエストを送る場合は、クッキーからトークンを取得してリクエストヘッダーに含めます。

function getCookie(name) {
    const value = `; ${document.cookie}`;
    const parts = value.split(`; ${name}=`);
    if (parts.length === 2) return parts.pop().split(';').shift();
}

fetch('/api/articles/', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'X-CSRFToken': getCookie('csrftoken')
    },
    body: JSON.stringify({ title: 'Hello' })
});

Django は X-CSRFToken ヘッダーも CSRF トークンとして受け入れます。フォームの hidden フィールドを使えない AJAX 通信では、この方法が標準的なアプローチになります。

csrf_exempt で特定のビューを除外する

外部 API からの Webhook 受信など、CSRF トークンを送れないケースでは @csrf_exempt デコレータで特定のビューだけ CSRF 検証を無効化できます。

from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def webhook(request):
    # 外部サービスからの POST を受け付ける
    ...

ただし、@csrf_exempt はそのビューの CSRF 防御を完全に無効化するため、代わりに API キーの検証やシグネチャの照合など、別の認証手段を必ず用意してください。

csrf_token タグ

フォーム送信時の標準的な CSRF 対策。テンプレートに 1 行追加するだけ

X-CSRFToken ヘッダー

AJAX 通信での CSRF 対策。クッキーからトークンを取得してヘッダーに設定する

なぜ GET にはトークンが不要なのか

HTTP の仕様では、GET リクエストは「安全なメソッド」に分類されています。GET はデータの取得のみを行い、サーバーの状態を変更しないことが前提です。そのため Django は GET リクエストに対して CSRF 検証を行いません。

逆に言えば、GET リクエストでデータベースの変更や削除を行う設計は避けるべきです。「データを変更する操作は POST で」という HTTP の基本原則を守ることが、CSRF 対策の前提条件になっています。

CSRF 対策は Django が自動で処理してくれますが、その仕組みを理解しておくことで、403 エラーの原因特定や AJAX 通信での適切な対応が素早くできるようになります。