>
>
公開日
最終更新日
CSRFとは、利用者がログインしているWebサービスに、本人の意図しないリクエストを送らせる攻撃です。ブラウザが条件に応じて認証Cookieを自動送信し、サーバーが本人の操作と攻撃者の誘導を区別できないときに起こります。
対策は、状態変更をGETで実装しないことと、サーバーが発行した照合用トークンや送信元をサーバー側で検証することです。XSSとの違いは、悪意あるスクリプトの実行か、正規セッションを使った操作の強制かにあります。CORS設定だけでは一般的なフォーム送信を防げません。419・403エラーが出た場合は、Cookie、トークン、送信元、サーバーログの順に調べます。
この記事は、Cookie認証を扱うWebアプリケーション・APIの開発者と、管理画面の安全性や診断結果を確認する情シス担当者を対象にしています。最短で確認する項目は、状態変更をGETで実装していないか、更新要求のトークン欠落・改ざんを更新前に拒否できるか、419・403の対応で保護を外していないかの3つです。開発者は「CSRF対策の選定とトークン実装」、情シス担当者は「委託先への受け入れ条件」、SPAやBFFを採用している場合は「SPA・REST API・BFFの構成別防御設計」の節から読み始めると、自社に関係する部分へ早く着けます。

CSRFとは
CSRFとは、認証情報を自動送信するブラウザを経由して、利用者が意図していない処理をWebサービスに実行させる攻撃です。この攻撃は、認証済みブラウザに意図しない要求を送らせ、サーバーがそれを正規の操作と区別できないときに成立します。攻撃者がレスポンスを直接読めなくても、状態変更は実行できます。対策の要否は、送信先、認証情報の送信条件、サーバー側の検証で判断します。
本記事のポイント
CSRFはシーサーフと読み、攻撃者がパスワードを知らなくても成立する場合があります。
XSSは悪意あるスクリプトの実行、CSRFは正規セッションを悪用したリクエストの強制です。
Cookie認証の状態変更処理には、照合用トークンの検証などのサーバー側の防御を適用します。
CSRFエラーが発生したら、保護を無効化せず、Cookieとトークンの対応から原因を切り分けます。
ブラウザの便利な仕組みを悪用する攻撃
CSRFは、Cross-Site Request Forgeryの略で、日本語ではクロスサイトリクエストフォージェリと呼びます。わかりやすく言えば、ログイン済みのブラウザを「本人の代わりに操作を届ける運び手」として悪用する攻撃です。
Webサービスでは、ログイン後に発行したセッションCookieをブラウザへ保存します。その後、ブラウザが対象サービスへアクセスすると、Cookieの属性や通信条件に応じてCookieが送信されます。サーバーがCookieだけを見て更新を受け付けると、利用者の正規操作と、外部ページから誘導された操作を区別できません。
悪意あるフォームから発生する不正操作
攻撃者は、悪意あるフォーム、つまりformタグやスクリプトを用意し、対象サービスへ更新リクエストを送らせます。利用者が攻撃ページを開いたとき、メールアドレス変更や送金先登録などが本人の操作として処理されるおそれがあります。
このとき攻撃者は、被害者のCookie値を知る必要がありません。通常、外部サイトから対象サービスの応答本文を自由には読めませんが、設定変更が完了すれば攻撃の目的を達成できます。「Cookieを盗まれていない」「画面を読み取られていない」という理由では、CSRFを除外できません。
対策対象となる認証方式
この攻撃の被害対象はCookie認証だけに限りません。IPAは「安全なウェブサイトの作り方」のCSRFの解説で、Cookieを用いたセッション管理、Basic認証、SSLクライアント認証を、影響を受ける可能性がある方式として挙げています。
設計時は、認証方式の名称よりも「外部ページから送られた要求にも、ブラウザが認証情報を自動で付けるか」で判定します。ブラウザがCookieを付けるAPIなら、画面を返さないJSON APIでも対策対象です。逆に、サーバー間だけで使うAPIでは、ブラウザ向けCSRF検証とは別にクライアント認証や署名検証を設計します。
対応の優先順位を決める判断材料
修正の優先順は、攻撃された場合に変更できるデータと権限から決めます。管理者追加、認証情報変更、決済設定変更のように影響が広がる処理から着手し、プロフィール表示などの参照処理と分けて扱います。
IPAは「安全なウェブサイトの作り方」で、CSRFやSQLインジェクション、XSSなど11種類の脆弱性を取り上げています。また、IPAが2026年10月22日に公表した2026年第3四半期の届出状況では、届出受付開始からの累計20,553件のうちウェブサイトに関するものが13,666件を占めています。この件数はCSRFだけの統計ではないため、自社のCSRF発生率には置き換えず、Web機能全体を継続的に点検する背景として読みます。
担当を決める際は、開発者が検証処理とテストを実装し、インフラ担当者がCookie・プロキシ・キャッシュの条件を整え、情シスが重要操作と例外経路を管理します。委託開発なら、診断報告の「対策済み」という記載だけで完了にせず、不正な要求を拒否したテスト結果まで受け取ります。
CSRF攻撃の仕組みと成立条件
リクエストを偽造する攻撃は、認証情報の自動送信、攻撃者が作成できるリクエスト、サーバー側の検証不足が重なったときに成立します。
ログインから不正更新までの流れ
攻撃者はログインを突破するのではなく、すでに認証された利用者のブラウザを操作の経路に使います。次の順序で見ると、どこで攻撃を止められるかを把握できます。
利用者が対象サービスへログインし、ブラウザがセッションCookieを保存します。
攻撃者が、対象サービスの更新URLと必要な項目を含む外部ページを用意します。
利用者が誘導リンクを開くなどして、そのページにアクセスします。
外部ページのフォームなどが対象サービスへリクエストを送ります。
CookieのSameSite属性などの条件が許す場合、ブラウザが認証Cookieを付けます。
サーバーがトークンや送信元を検証しなければ、利用者本人の更新として処理します。
Cookieが実際に送信されるかは、SameSite属性、遷移方法、HTTPメソッド、サイト間の関係などで変わります。「外部ページから送ったら必ずCookieが付く」と覚えるのではなく、送信条件とサーバー側の拒否条件を分けて調べます。
リクエストを再現できる条件
典型的な手口では、攻撃者が操作先URLと必要なパラメーターを組み立てられます。メールアドレスや操作対象IDだけで更新でき、利用者固有の秘密値を検証していなければ、外部フォームでも同様の要求を作れる可能性があります。
ここへ推測困難な照合用トークンを追加し、対象セッションと対応する値かをサーバー側で照合します。単に画面へhiddenフィールドを置くだけでは防げません。トークンが欠落した場合と、値を書き換えた場合の両方で、業務データを変更する前に拒否する実装にします。
狙われやすい状態変更処理
対策対象は、購入や送金など目立つ処理に限らず、サーバー上の状態を変える処理全般です。メールアドレス変更、二要素認証の無効化、配送先登録、権限付与、外部連携追加、Webhook変更、退会などを一覧化します。
HTTPメソッドだけで対象を抽出すると、GETで実装された削除や承認を見落とします。最初はURL一覧と実際の業務処理を突き合わせ、状態変更を行うGETを別途抽出します。参照画面の表示で更新が起こるなら、画面表示と更新処理を分離し、更新側へトークン検証を適用します。
ログインCSRFと認証連携の防御
ログインCSRFでは、攻撃者のアカウントへ被害者をログインさせるなど、認証結果を利用者の意図と入れ替えます。被害者がそのまま個人情報を入力すれば、攻撃者が自分のアカウントから後で閲覧できるおそれがあります。
OAuthやOpenID Connectによる認証連携では、認証開始時のブラウザセッションとコールバックを対応付けます。デジタル庁の認証サーバー仕様では、CSRF対策用のstateをリクエストごとに設定し、256ビットのエントロピーを持たせることを推奨しています。この数値は同仕様の推奨として扱い、すべてのOAuth実装に共通する固定の必須値とは混同しません。
実装では、認証開始時に生成したstateをサーバー側のセッションなどへ保存し、コールバックで返された値と照合します。デジタル庁のGビズID接続システム向けガイドラインは、stateが一致しない場合にTokenへのリクエストを実行しないよう規定しており、リクエスト時に保存していた値とコールバック時のstateが一致しない状態を、CSRFの可能性があるものとして扱っています。欠落・不一致・すでに使用した値は拒否し、コールバックにstateが存在するだけで成功扱いにしません。
通常のログインフォームと外部認証の区別
自社のID・パスワードを送るフォームと、外部認証サービスから戻るコールバックは、同じ防御を機械的に適用しません。通常のログインフォームにはフレームワークのCSRF保護を使い、外部認証にはプロトコルと採用ライブラリに沿ったトランザクションの照合を組み込みます。
外部から戻るという理由だけで認証URL一式を検証対象外にすると、ログイン開始やアカウント連携まで無防備になります。例外が必要なら対象コールバックを限定し、stateの不一致テストと、別ブラウザで開始した認証結果の拒否テストを追加します。

▲ 正規セッションを持つ利用者のブラウザを経由してCSRF攻撃が成立するまでの流れ。
XSSとの違いとCORSの防御範囲
XSSは悪意あるスクリプトの実行、CSRFは正規セッションを悪用したリクエストの強制です。
両者は利用者のブラウザを利用しますが、攻撃者が越える境界は異なります。XSS対策として出力をエスケープしても、トークンによる送信元の検証の代わりにはならず、偽リクエスト対策を実装しても不正なスクリプトの実行は防げません。
比較項目 | CSRF | XSS |
|---|---|---|
分類 | CWE-352 | CWE-79 |
攻撃の中心 | 認証済みブラウザから意図しない要求を送らせます。 | 対象サイトの権限で悪意あるスクリプトを実行させます。 |
攻撃者の目的 | 設定変更、購入、権限付与などを本人の操作として成立させます。 | 情報取得、画面改ざん、操作の監視、不正なAPI呼び出しなどを行います。 |
主な弱点 | 認証Cookieなどを信用し、操作の正当性を検証していません。 | 信頼できない値を、実行可能なHTMLやJavaScriptとして扱っています。 |
応答の読み取り | 典型的な外部フォーム型では、攻撃者は応答本文を自由に読めません。 | 同一オリジンで実行されると、ページやAPIの情報を読める場合があります。 |
中心となる対策 | CSRFトークン、送信元検証、SameSiteなどを組み合わせます。 | 出力先に応じたエスケープ、安全なDOM操作、必要に応じたHTMLサニタイズを行います。 |
補助的な対策 | Fetch Metadata、重要操作時の再認証などを加えます。 | CSPやHttpOnlyで、実行経路や被害を制限します。 |
Cookieの窃取とCookieの悪用の違い
偽リクエスト型の攻撃では、Cookieを盗まずにブラウザの自動送信を悪用します。一方、XSSでCookieを直接読み取れるかはHttpOnlyなどの設定で変わりますが、読めない場合も不正な操作を実行できる可能性があります。
そのため、HttpOnly付きCookieを採用しただけで、XSSとCSRFの双方へ対応したとは判断しません。HttpOnlyは認証CookieのJavaScriptからの読み取りを制限し、CSRFトークンは外部からの偽リクエストを判定します。担当者は、診断結果を「Cookieが盗めるか」だけで分類せず、対象サイトの権限で何を実行できるかまで確認します。
CORSとCSRFの決定的な役割の違い
CORSは、別オリジンのJavaScriptにレスポンスの読み取りを許可するかを制御する仕組みであり、一般的なHTMLフォームの送信を一律に遮断する仕組みではありません。一方、偽リクエスト型の攻撃は、攻撃者が応答を読めなくても更新できれば成立します。
たとえばフォームで送信可能な形式のPOSTは、CORSでレスポンスを読めなくてもサーバーへ届き得ます。一方、カスタムヘッダーなどが必要なクロスオリジン通信では、ブラウザがプリフライトで送信可否を判断します。サーバーがそのヘッダーを必須とし、CORSの許可先を限定するなら防御に利用できますが、同じ更新を通常フォームでも受け付ける抜け道を残さない設計にします。
Bearerトークンと保存先のトレードオフ
JavaScriptが明示的にAuthorizationヘッダーへBearerトークンを付ける方式では、外部フォームに認証情報が自動付与されないため、典型的なCookie型CSRFの条件から外れます。AeyeScanのCSRFの技術解説も、認証情報をヘッダーへ明示的に載せる方式とCookieの自動送信を区別しています。
ただし、localStorageやsessionStorageへ保存したトークンは、同じオリジンのJavaScriptから読み取れます。XSSが起きると持ち出される可能性があるため、CSRF回避だけを理由に保存先を移しません。Cookie認証を選ぶならCSRF対策を実装し、JavaScriptでトークンを扱うならXSS対策と漏えい時の失効手順を整えます。
複合攻撃の被害範囲
XSSが同一オリジンで成立すると、攻撃コードがCSRFトークンを取得し、正規の更新要求を送れる場合があります。照合用トークンは外部サイトからの偽造に備える仕組みなので、サイト内で実行される不正スクリプトまで同じ条件では拒否できません。
診断報告では、まず正規セッションを使った操作の強制かどうかを切り分けます。XSSによる情報取得や認可不備による権限逸脱は、別の問題として記録します。管理者追加をCSRFで強制でき、その後に攻撃者がログインできるなら、直接の更新操作とアカウント乗っ取りへの連鎖をそれぞれ修正対象にします。

▲ CSRFとXSSの攻撃手法、目的、応答可否および防御策の比較。
CSRFエラーの原因特定と419・403の対処
トークン検証まわりのエラーは、失敗した要求のCookie、トークン、送信元、拒否ログを順に照合すると、保護を無効化せずに原因を絞れます。
画面に「CSRF error」と表示されても、原因がトークン不一致とは限りません。Laravelなどで見られる419 Page Expiredと、Spring Securityなどで見られる403 Forbiddenを入口にしつつ、最終的にはサーバー側の拒否理由で判定します。403には認可やWAFによる拒否も含まれるため、ステータスコードだけで偽リクエスト対策による拒否と断定しません。
障害発生直後の切り分けフロー
最初に、ブラウザの開発者ツールで失敗した要求を1件特定し、その時刻とリクエストIDでサーバーログを追います。画面の再読み込みを繰り返す前に、入力内容と失敗条件を保存します。
順序 | 調べる対象 | 結果による次の行動 |
|---|---|---|
1 | 失敗したURL、HTTPメソッド、応答コード | 更新要求を特定できたら、その要求の認証とトークン検証を追います。OPTIONSの失敗なら先にCORSのプリフライトを調べます。 |
2 | セッションCookieの送信有無 | 未送信ならCookie属性やcredentials設定を調べ、送信済みならセッションがサーバー側に残っているかを調べます。 |
3 | CSRFトークンの送信先と値の対応 | 欠落ならフォームやヘッダー付与を修正し、不一致なら画面生成時と送信時のセッションを照合します。 |
4 | Origin、Referer、Fetch Metadataと許可設定 | 正規要求を拒否しているなら許可オリジンやプロキシ設定を修正し、不審な送信元なら拒否を維持します。 |
5 | キャッシュ、セッション保存先、サーバー間の設定差 | 古い画面や一部サーバーだけで再現するなら、配信経路とセッション共有を修正します。 |
419 Page Expiredとセッションの不整合
419を返す構成では、トークンと現在のセッションの対応が切れていないかを調べます。長時間開いたフォーム、別タブでのログアウト、ログインによるセッション更新、デプロイ後の設定差を再現条件に含めます。
トークンには、独立した有効期限を持つ実装と、セッションの寿命に連動する実装があります。「トークン期限切れ」と決めつけず、セッション自体が失効したのか、トークンだけ更新されたのかをログで分けます。セッションが失効した場合は再ログインへ誘導し、認証が有効なままトークンだけ古い場合は、新しいトークンを取得して入力画面を復元する処理へ進みます。
403 Forbiddenと拒否主体の特定
403では、アプリケーション、認可処理、リバースプロキシ、WAFのどこが応答を返したかを先に特定します。アプリケーションログに要求がなければ、その手前のアクセスログを調べます。
トークン不一致なら取得・送信処理を修正し、権限不足なら対象ユーザーと操作対象の認可条件を見直します。Origin不一致なら、正規のスキーム・ホスト・ポートを許可リストへ登録します。修正の対象は拒否した層の条件に絞ります。保護全体を外してはいけない理由は、後述の失敗パターンの節で扱います。
Cookie未送信時のチェックリスト
Cookieが送られていない場合は、ブラウザのCookie保存状況と、対象要求への付与条件を別々に調べます。保存されていないCookieは、フロントエンドのトークン処理を直しても送信されません。
Cookieがブラウザへ保存されているかを調べ、なければログイン応答のSet-Cookieとブラウザの拒否理由を追います。
DomainとPathが要求先に一致するかを調べ、不一致ならアプリケーションが実際に使う範囲へ修正します。
Secure付きCookieをHTTPで使っていないかを調べ、開発環境も含めて通信経路と設定をそろえます。
クロスサイト通信ならSameSiteの条件を調べ、Cookie認証を継続する場合は別途トークン検証を維持したうえで属性を調整します。
クロスオリジンのfetchならcredentials設定を調べ、資格情報付き通信を許すCORS応答と対にして修正します。
ブラウザの第三者Cookie制限が原因なら、属性変更を繰り返すより同一オリジン配信やBFFへの集約を検討します。
キャッシュ起因のトークン不一致
セッション固有のトークンを含むHTMLが共有キャッシュから配信されると、別のセッション用の値や古い値が送られます。CDNのキャッシュ状態と、画面表示後にログイン・ログアウトを行ったかを照合します。
認証済み画面を共有配信していた場合は、まず対象ページを共有キャッシュから外します。SPAが静的HTMLを使うなら、セッション固有のトークンを静的ファイルへ埋め込まず、認証済みの初期化APIなどから取得します。ブラウザの「戻る」で復元された画面もテストし、古いトークンを送った場合は更新済み画面へ戻せるようにします。
Origin・Referer欠落時の扱い
送信元ヘッダーがない要求は、無条件に許可するのではなく、採用した防御方式に沿って判定します。トークン方式を併用しているなら、有効なトークンを検証できる経路を残し、欠落だけを理由に保護全体を解除しません。
リバースプロキシ配下では、アプリケーションが認識するホストやHTTPSの状態が外部公開先と食い違う場合があります。信頼するプロキシを限定したうえで転送ヘッダーの取り扱いを修正します。要求のHostや転送ヘッダーから無条件に「正規Origin」を作ると、攻撃者の入力を許可基準へ取り込むため、公開オリジンは管理された設定から決めます。
安全な再送とログの記録
エラー後の自動再送は、元の更新が実行されていないと判定できる場合に限ります。送金や注文で成否が不明なままPOSTを再送すると、CSRFとは別に二重処理を起こすおそれがあります。
決済などでは、処理結果の照会や冪等性キーを使って重複を防ぎます。ログには拒否理由、要求ID、認証状態、検証したルール名を残し、セッションCookieやトークンの生値は保存しません。問い合わせ票へ貼る場合も値を伏せ、成功要求と失敗要求の差だけを共有します。

▲ CSRFエラー発生時にCookieやセッション状態から原因を切り分けるフロー。
CSRF対策の選定とトークン実装
Cookie認証の更新処理はフレームワークの標準保護を起点にし、照合用トークンの検証へCookie属性と送信元検証を重ねます。
先に独自の防御コードを書くと、トークン生成や失効、例外処理まで保守する範囲が広がります。既存アプリケーションでは、利用中の標準機能が有効か、どのURLが対象外かを調べ、更新処理の実行前に拒否される状態へ整えます。WAFは改修までの緩和に使えても、業務上の正当な操作を識別するサーバー側検証の代替にはなりません。
対策方式の比較マトリクス
防御方式は、セッションを保持する場所と、ブラウザからの呼び出し方に合わせて選びます。次の表では、根本的な検証と補助的な制限を分けています。
方式 | 役割 | 主な適用先 | 実装上の注意点 |
|---|---|---|---|
Synchronizer Token Pattern | セッションに対応する秘密値をサーバー側で照合します。 | セッションを保持するWebアプリ、管理画面、フォーム | 欠落と不一致を拒否し、トークン入り画面を共有キャッシュしません。 |
署名付きDouble Submit Cookie Pattern | Cookieと要求内の値を照合し、署名とセッションへの結び付きも検証します。 | 採用基盤が同方式を備える構成 | 単純な一致確認で済ませず、Cookie注入とセッション間流用に備えます。 |
Origin・Referer検証 | 許可した送信元からの要求かを判定します。 | ブラウザ向け更新API、既存アプリへの追加防御 | 完全一致で比較し、ヘッダー欠落時の代替検証を決めます。 |
SameSite属性 | クロスサイトでCookieを送る条件を制限します。 | Cookie認証全般 | GETの状態変更や、信頼できない同一サイトのサブドメインには別の対策を施します。 |
Fetch Metadata | ブラウザが示す要求の文脈から、不審なクロスサイト要求を拒否します。 | 対応ブラウザ向けの追加防御 | ヘッダー不在時の扱いと、正規の外部連携を定義します。 |
再認証・取引確認 | 高リスク操作に追加の本人確認を行います。 | 認証情報、送金先、権限、重要設定の変更 | 確認を対象取引へ結び付け、トークン検証と併用します。 |
セッションに対応するトークンの検証
セッション方式では、サーバーが推測困難なCSRFトークンを発行し、フォームやヘッダーから返された値を照合します。IPAは確認画面のhiddenパラメータに、暗号論的擬似乱数生成器で生成した第2セッションIDなどの秘密情報を出力する方法を示しています。
実装では認証用のセッションIDをそのまま露出させず、専用のトークンを使います。生成・比較・更新はフレームワークへ委ね、アプリケーション側は全更新経路で検証されるかをテストします。確認画面を表示するだけでは防げないため、最終実行要求にもトークンを含め、実行直前に検証します。
この例のフィールド名は説明用です。実装では採用フレームワークが期待する名前を使い、トークン欠落時も空文字同士の一致として通過させません。トークンをクエリ文字列へ入れるとアクセスログなどへ残りやすいため、フォーム本文か専用ヘッダーで送ります。
Double Submit Cookie Patternの安全条件
Double Submit Cookie Patternでは、照合用Cookieの値と、フォーム本文またはカスタムヘッダーの値をサーバー側で照合します。ただし、署名のない単純な一致確認は、攻撃者がサブドメインなどからCookieを注入できる構成で破られる可能性があります。
採用するなら、HMACなどの署名で改ざんを検知し、トークンを現在のセッションにも結び付けます。無関係な署名付き乱数を置くだけでなく、別セッションへの流用を検証で拒否します。認証用セッションID自体をブラウザ向けトークンへ露出させず、署名の生成や比較には基盤が用意した実装を使います。
Cookieのスコープとサブドメイン管理
認証Cookieやトークン用Cookieは、必要以上に広いDomainを指定しない設計にします。親ドメイン配下のすべてを信頼すると、委託先が管理するサブドメインや放置したホストまで防御の前提へ入り込みます。
Cookie共有が不要ならDomainを省略してホストに限定し、HTTPSを前提にSecureを設定します。対応条件を満たせるなら、Secure、Path=/、Domainなしを要求する__Host-接頭辞も検討します。同名Cookieが複数届く場合にどちらを採用するかを独自に推測せず、重複を含む要求で基盤の挙動をテストし、想定外の値を受け入れない状態にします。
Laravelの@csrfによるフォーム保護
Laravelでは、webミドルウェアグループのCSRF検証が有効な構成を前提に、Bladeフォームの@csrfディレクティブで照合用トークンのhiddenフィールドを出力します。検証ミドルウェアの名称や除外設定の書き方はバージョンで異なるため、利用中のバージョンの公式ドキュメントに合わせます。GMOインターネットグループのCSRF解説は、Laravel、Django、Ruby on Rails、Spring Securityを、CSRF対策機能を備える主要フレームワークとして挙げています。
ディレクティブを置くのはサーバーで処理するBladeテンプレートです。静的HTMLやJavaScriptの文字列へ@csrfと書いても、テンプレート処理がなければトークンは生成されません。SPAから送る場合はフォーム用の例をそのまま使わず、採用した認証構成のトークン取得とヘッダー付与に合わせます。
Spring Securityのトークン受け渡し
Spring Security(6系・7系)では、セッションCookie認証のブラウザ向けSecurityFilterChain設定でCSRF保護を維持し、テンプレートやJavaScriptが取得したトークンを更新要求へ返します。認証方式が混在する場合は、Cookie認証の画面と、ブラウザのCookieを使わないAPIの設定を分けます。
テンプレート上では、リクエストへ公開されたCSRF情報を使う構成があります。次の例はThymeleafでhiddenフィールドへ出力する例です。実際の公開属性やトークン保存方式に合わせ、独自の固定値へ差し替えません。
SPAでトークン用Cookieを採用するなら、認証Cookieと読み取り用途を分けます。ログインやログアウト後にトークンの再取得が必要になる構成では、その遷移をテスト対象へ含めます。403を避けるために全体のCSRF保護を無効化するのではなく、画面から期待する名前と形式で値が届いているかを調べます。
RailsのフォームとJavaScript通信の保護
Railsでは、新規アプリで既定で有効なCSRF保護(config.action_controller.default_protect_from_forgery、または手動で記述するprotect_from_forgery)と標準のフォーム生成を組み合わせ、JavaScriptから更新する経路にもトークンを渡します。HTMLフォームだけをテストすると、後から追加したfetchや独自アップロード処理に保護漏れが残ります。
JavaScript側では、メタタグから読み取ったトークンをヘッダーへ付けて送ります。
この例は同一オリジンでの更新を想定しています。API専用構成へ画面用の保護が自動で入るとは限らないため、実際のミドルウェアと認証方式を対応させます。欠落・改ざんした要求を拒否できれば次の更新経路へ進み、通過した場合はその経路の保護設定から修正します。
重要操作に追加する本人確認
送金先変更や二要素認証の無効化には、CSRFトークンに加えて再認証や取引内容の確認を加えます。トークンの検証を通過した要求でも、利用者が対象操作を意図したかを追加で確かめます。
再認証後に別の送金先へ差し替えられると、確認画面の意味が失われます。対象ID、変更内容、有効時間を確認結果へ結び付け、確定時に同じ取引かを検証します。情シスが承認フローを設ける場合も、承認者の権限と申請内容の固定を合わせて実装します。
SPA・REST API・BFFの構成別防御設計
SPAやREST APIの偽リクエスト対策は、画面の分離方法ではなく、ブラウザからAPIへ認証情報がどう届くかで決めます。
RESTか別ドメインかでは判断しません。Cookieが送られる更新APIは、トークンや送信元の検証が必要です。ブラウザ、認証Cookie、APIの境界を図にし、トークンの発行元・受け取り元・検証元を決めます。
構成と認証方式の対応表
同じSPAでも、Cookie認証と明示的なBearer認証では防御の前提が変わります。混在構成では、APIのURLだけでなく認証経路も一覧へ記録します。
構成 | 認証情報の経路 | 実装する防御 | 受け入れテスト |
|---|---|---|---|
同一オリジンの画面とAPI | ブラウザがセッションCookieを送ります。 | 初期化時にトークンを取得し、更新要求のヘッダーへ付けて検証します。 | 正規更新の成功と、トークン欠落・改ざんの拒否を試します。 |
別オリジンのSPAとCookie認証API | 許可した条件でCookieを伴う通信を行います。 | トークン検証、限定したCORS許可、送信元検証を組み合わせます。 | 正規Originと未許可Origin、プリフライト、フォーム型POSTを分けて試します。 |
BFFを介したSPA | ブラウザはBFFへCookieを送り、BFFが内部APIへ接続します。 | ブラウザとBFFの境界でトークンを検証し、内部APIでも認可を行います。 | BFFの更新URL全体と、操作対象IDを書き換えた要求を試します。 |
明示的なBearer認証API | クライアントがAuthorizationへトークンを付けます。 | Cookieによる代替認証を混在させず、XSS・認可・トークン管理へ対応します。 | Authorizationなしの要求がCookieだけで成功しないかを試します。 |
同一オリジンSPAのトークン受け渡し
同一オリジンのSPAでは、初期HTMLまたは専用の初期化APIで照合用トークンを渡し、状態変更の要求へ付与します。認証CookieはHttpOnlyを維持し、JavaScriptが扱う照合用トークンと分離します。
このURLと応答形式は設計例であり、フレームワーク共通のエンドポイントではありません。トークン取得APIは現在のセッションへ対応する値を返し、共有キャッシュしません。認証が切れた場合は更新へ進まず再ログインへ誘導し、ログイン後に新しいセッション用のトークンを取得します。
クロスオリジンとクロスサイトの区別
オリジンはスキーム・ホスト・ポートの組み合わせで、SameSiteが扱うサイトの単位とは異なります。たとえばHTTPSのapp.example.comとapi.example.comは別オリジンですが、同一サイトとして扱われる構成です。
したがって、別オリジンという理由だけでSameSite=Noneへ変更しません。同一サイト内のCookie認証なら、必要なCORS設定とCookieの範囲を整えます。異なるサイトをまたぐCookie認証ならSameSite=None; Secureが必要になる場合がありますが、第三者Cookie制限も考慮し、ブラウザ条件によって成立しない場合はBFFや同一オリジン構成へ寄せます。
クロスオリジンAPIの許可条件
クロスオリジンのCookie認証APIでは、資格情報付き通信を許可するOriginを具体的に列挙します。Originの値をそのまま応答へ反射せず、環境ごとの許可リストと照合します。
これは許可済みOriginへ返す応答ヘッダーの構成例です。未許可Originには同じ許可応答を返さず、アプリケーション側でもトークンや送信元を検証します。資格情報付き通信でAccess-Control-Allow-Origin: *を使う構成にはしません。カスタムヘッダーを必須とするなら、同じ処理へヘッダーなしで到達する互換ルートも閉じます。
Fetch Metadataを追加する境界
Fetch Metadataは、Sec-Fetch-Siteなどのブラウザ付与ヘッダーから、要求が同一オリジン、同一サイト、クロスサイトのどこから来たかを判定する追加防御です。ブラウザ専用の更新APIでは、正当な外部連携を除き、cross-siteの更新を拒否する設計に使えます。
ただし、same-siteという値だけで信頼すると、侵害されたサブドメインからの要求を通すおそれがあります。ヘッダーがないWebViewや非ブラウザクライアントも想定し、トークン検証へ回す経路と、別のクライアント認証を使う経路を分けます。ヘッダーの有無だけを認証済みクライアントの識別には使いません。
BFFで保護するブラウザ側の境界
BFFを採用しても、ブラウザがBFFへ認証Cookieを送る部分にはCSRF対策を残します。内部APIのアクセストークンをJavaScriptへ露出させない構成と、外部ページからの更新強制を防ぐ構成は別々に実装します。
BFFでは更新URLごとにトークンや送信元を検証し、内部APIではユーザーと操作対象の権限を再判定します。BFFへ届いたIDを無条件に内部APIへ渡すと、CSRFを防いでも認可不備が残ります。セッション終了時にはBFF側の認証状態とトークンを失効させ、ブラウザが古い画面から更新した場合も拒否します。
Webhookとモバイル通信の例外設計
ブラウザ以外の通信は、CSRF検証を外す代わりに、その経路専用の認証を適用します。Webhookなら署名と時刻、モバイルAPIならクライアントが明示的に送るトークンなど、送信者を検証できる方式へ分離します。
User-Agentや「モバイルから来た」という任意ヘッダーだけで例外にしません。同じURLがCookieでも認証される場合は、ブラウザ経路が例外へ入り込むため、認証方式ごとの処理を明確に分けます。例外一覧には所有者、用途、代替認証、テストを記録し、利用終了時に経路ごと閉じます。
CSRF対策の失敗パターンとSameSiteの注意点
偽リクエスト対策の失敗は、Cookie属性やCORSを過信し、更新処理の検証を省略したときに起こります。
419・403を解消する設定変更と、偽リクエストを防ぐ設計変更は別に扱います。正規の更新が成功しても、それだけでは防御を確認できません。拒否すべき要求が失敗し、業務データも変化しないところまで試します。
SameSite属性の選択ミス
SameSiteはStrict、Lax、Noneの用途を分け、外部遷移と認証連携を含めて選びます。クロスサイトCookie送信が必要な構成では、NoneとSecureを対にして扱い、サーバー側のトークン検証を残します。
属性 | 主な性質 | 設計上の注意点 |
|---|---|---|
Strict | クロスサイトの文脈でCookieの送信を厳しく制限します。 | 外部リンクからの初回遷移や認証連携に支障が出る場合があるため、正規の導線をテストします。 |
Lax | クロスサイト要求を制限しつつ、トップレベルのGET遷移などでは送信を許します。 | GETで状態変更を行う設計は保護できません。 |
None; Secure | HTTPSを前提にクロスサイト送信を許容する設定です。 | トークンや送信元の検証を必ず別に用意し、ブラウザの第三者Cookie制限も考慮します。 |
Cookieを発行する際の構成例は、Set-Cookie: session=...; Path=/; Secure; HttpOnly; SameSite=Laxです。これはすべての構成にそのまま適用する固定値ではありません。外部認証からの戻り方や、画面とAPIのサイト関係に合わせて調整し、Domainを広げる前にCookie共有が本当に必要かを判断します。
Laxに依存したGETの状態変更
SameSite=Laxでも、外部サイトからのトップレベルGET遷移にCookieが付く条件があります。そのため、削除や設定変更をGETで実装すると、リンクを開かせるだけで処理が動く危険が残ります。
「POSTへ変更したから完了」とも判断しません。GETを参照専用に変更したうえで、POSTなどの更新要求へトークン検証を適用します。URLを変更できない既存システムなら、GETでは確認画面だけを表示し、実際の状態変更は検証付きのPOSTへ分離します。
既定値といわゆる2分ルールの混同
SameSite未指定時の扱いと、明示したSameSite=Laxは区別します。属性未指定Cookieに対する短時間の緩和、いわゆる2分ルールはブラウザ実装に依存するため、過去だけの挙動とも、現在の全ブラウザ共通仕様とも決めつけません。
設計書へ「2分を過ぎれば安全」と書かず、Cookie属性を明示し、更新要求の検証で防ぎます。ブラウザ差を調べる試験では、属性未指定と明示指定、Cookie発行直後と時間経過後を分けます。試験結果が違っても、トークン欠落の更新を拒否する設計は変更しません。
トークンの存在だけを見る検証
トークンが付いているかだけを確認しても、攻撃者は任意の文字列を送れます。サーバー側で期待値との対応を検証し、別ユーザーのトークンも拒否する実装にします。
署名付き方式でも、署名の正しさだけでは対象セッションへの結び付きが不十分な場合があります。欠落、空文字、改ざん、別セッション、複数の同名パラメーターをテストへ含め、想定外の入力を成功扱いにしません。検証処理の後に業務処理が実行される順序も、テストで固定します。
フレームワーク保護の一括解除
419や403を解消するため、CSRFミドルウェアやフィルターを全体で無効化しません。原因がトークン未送信なら、解除しても認証・セッションの不整合を隠しただけになります。
Webhookなどの例外が必要なら、該当経路を限定し、代替の署名検証やクライアント認証を追加します。コードレビューでは保護設定の変更を独立した確認項目にし、「管理画面全体」「API全体」を対象外にする差分は、認証方式と拒否テストがそろうまで本番へ入れません。
再現テストによる二次被害
偽リクエストの再現は、本番の送金・削除・権限変更を使わず、隔離したテスト環境と専用アカウントで行います。外部フォームを用意する場合も、操作対象と後処理を固定します。
検証用ページを共有スペースへ放置すると、別の担当者が開いて更新を実行するおそれがあります。試験開始前に対象URL、変更内容、実施者、終了後の削除手順を決めます。本番でしか再現しない場合は、先にログと通信条件を採取し、更新を起こす検証の可否を運用責任者が判断します。
CSRFの被害事例と国内企業の診断運用
偽リクエストによる被害事例は不正な操作が起きる仕組みを学ぶために使い、診断ツールの導入成果とは分けて評価します。
被害事例からは守るべき業務処理を抽出し、導入事例からは検査を継続する担当と工程を考えます。診断工数の削減率を、そのまま偽リクエスト攻撃の防御率へ置き換えないようにします。
mixiのはまちちゃん事件
2005年のSNS「mixi」で起きた「はまちちゃん事件」は、本人の意図しない投稿を行わせた、偽リクエスト攻撃の歴史的な事例です。サイバー保険ガイド(保険代理店ファーストプレイス運営)のCSRF解説は、悪意あるリンクを開いた利用者がSNSでスパム投稿を行う事件として取り上げています。GMOインターネットグループのCSRF解説も、2005年4月にmixiで特定のURLをクリックすると日記が勝手に投稿される現象が起きたと説明しています。
この事例は2005年当時のもので、現在のブラウザやサービスの防御条件は当時から変化しています。学ぶべき点は、パスワードを奪わなくても、ログイン状態を利用して投稿を強制できるという構造です。社内ワークフローの承認コメント、レビュー、問い合わせなど、本人の発言として記録される機能も更新処理として保護します。
EC-CUBE関連の情報流出との区別
EC-CUBEをめぐる情報流出と、偽リクエストによる直接の操作強制は、同じ出来事としてまとめません。AeyeScanのCSRF解説は、EC-CUBEの脆弱性悪用によるクレジットカード情報流出にも言及していますが、情報流出という結果だけでCSRF単独の被害範囲は判断しません。
自社が同製品や関連プラグインを使う場合は、利用バージョンに対応する脆弱性報告の操作範囲と修正内容を管理します。偽リクエスト対策の担当は管理操作の偽造を防ぎ、XSS、認可不備、管理者認証の担当はそれぞれの侵入・流出経路を閉じます。更新プログラムの適用とアプリケーション独自機能の検査を分けて進めます。
TOPPANデジタルの出荷前診断
TOPPANデジタルの導入事例は、診断の工数削減と、出荷前の検査工程を考える材料になります。AeyeScanの導入事例では、2024年1月にAeyeScanを正式導入したTOPPANデジタルが診断結果をTOPPANホールディングスと共有し、ホールディングス側の出荷前診断の工数が75%ほど削減できたとしています。
項目 | 公開事例の内容 |
|---|---|
対象組織・範囲 | TOPPANデジタルの診断結果を共有したTOPPANホールディングスの出荷前診断です。 |
時期 | 2024年1月に正式導入した事例です。 |
課題と施策 | 出荷前診断の工数に対し、AI型Web脆弱性診断ツールAeyeScanを導入しています。 |
成果 | ホールディングス側の出荷前診断の工数が75%ほど削減されています。偽リクエストによる被害の削減率を表す数値ではありません。 |
自社で診断を自動化するなら、ログイン状態の維持、更新画面への到達、検査用データの準備を先に行います。自動巡回できない権限変更や決済確定は、人手による操作確認へ残します。診断結果には、到達できなかった画面を「未検査」と明記します。未検査画面を「問題なし」に含めません。
診断を継続運用する体制づくり
自動診断を運用に組み込む場合は、自動診断の対象と、人手による権限確認の範囲を分けて考えます。権限周りなど人手での確認が必要な脆弱性は残るため、自動診断を外部診断サービスの完全な代替にはしません。
診断を自社で継続するには、ツール名を選ぶ前に、実行担当、検査環境、手動確認の対象、検出後の修正担当を決めます。共有の検査環境と夜間の自動実行を組み合わせると、担当者の作業時間を圧迫せずに回せます。
診断統計から決める回帰テスト
GMO Flatt Securityは、2023年1月1日から2024年12月31日に実施した診断で検出した1,000個以上の脆弱性について、CSRFが3%を占め、第9位だったと公表しています。これは同社の診断対象における構成比であり、国内全サイトの被害率ではありません。
自社では比率の大小より、重要更新処理に保護漏れが残っていないかを回帰テストへ落とし込みます。最低限、トークン欠落・改ざん、別セッションのトークン、外部フォーム型POSTを試します。拒否されたという応答だけでなく、データベース、操作履歴、外部送信のいずれにも更新が起きていない状態を合格条件にします。
よくある質問
実装時の疑問は、トークンの受け渡し、Cookieの送信条件、例外経路の認証方式を分けると整理できます。
@csrfの役割
Q:Laravelの@csrfとは何ですか?
A:BladeテンプレートでCSRFトークン用のhiddenフィールドを出力するディレクティブです。フォームへ記載したうえでサーバー側のCSRF保護を有効にし、トークンが欠落・改ざんした要求を拒否します。
SameSiteだけで防ぐ設計
Q:SameSite属性だけで偽リクエストを防げますか?
A:SameSiteだけに依存する設計にはしません。Laxで許可されるGET遷移や同一サイト内の攻撃経路があるため、状態変更をGETから分離し、トークン検証などを組み合わせます。
CORS設定とトークン検証の関係
Q:CORSを設定すれば偽リクエスト対策は不要ですか?
A:不要にはなりません。一般的なフォーム送信はCORSだけでは止められないため、サーバーで照合用トークンや送信元を検証し、カスタムヘッダーを防御に使う場合は未許可Originとヘッダーなし要求の両方を拒否します。
403とCSRFの関係
Q:403 Forbiddenは必ずCSRFエラーですか?
A:403は認可、WAF、送信元検証などでも発生するため、必ずしもトークン検証の失敗とは限りません。応答を返した層と拒否理由をログで特定し、トークン不一致なら受け渡しを、権限不足なら認可条件を修正します。
トークンの更新頻度
Q:CSRFトークンはリクエストごとに変更すべきですか?
A:更新頻度は採用方式に従い、独自に毎回変更する必要はありません。操作単位で更新するなら戻る操作や複数タブの失敗も扱い、セッション単位ならセッション終了後の失効と別セッションからの流用拒否をテストします。
ブラウザ以外のAPIの例外
Q:WebhookにもCSRFトークンが必要ですか?
A:ブラウザの認証Cookieを使わないWebhookでは、通常は送信元の署名など別の認証で保護します。Cookie認証の画面と同じ例外にせず、専用経路へ分離して署名、再送、期限の検証を行います。
着手前の優先度チェックリスト
改修範囲が広い場合は、最低限の修正、構成別の追加防御、重要操作の保護の順に進めます。各項目に担当者とテスト結果をひも付け、設定変更だけで完了扱いにしません。
優先度 | 実施内容 | 完了条件 |
|---|---|---|
最初に実施 | 状態変更URLを抽出し、GETによる更新を分離します。 | 参照要求では業務状態が変わらず、更新要求には検証が適用されています。 |
標準保護の復旧 | フレームワークのCSRF保護と例外設定を点検します。 | 欠落・改ざんトークンを更新前に拒否し、正規要求は成功します。 |
構成に応じて追加 | SPAのトークン取得、CORS、Cookie、送信元検証を整えます。 | 正規画面の更新と、未許可Originからの拒否を再現できます。 |
重要操作へ追加 | 再認証、承認、操作ログ、権限分離を適用します。 | 確認した内容と確定処理が一致し、不正操作を追跡できます。 |
リリース前と変更後 | 不正要求の回帰テストと診断を実施します。 | 応答だけでなく業務データが変更されていないことも検証できています。 |
委託先への受け入れ条件
委託開発の成果物には、保護対象URL、例外URL、代替認証、拒否テストを含めます。情シスは画面の見た目ではなく、更新処理の前に検証が実行された証拠で受け入れます。
テスト結果に成功ケースしかない場合は、不正要求の拒否結果を追加します。例外経路の所有者や認証方式が不明な場合は、その経路を公開したまま保留せず、用途を特定して閉鎖するか、認証を追加してから提供します。運用開始後は管理画面や認証設定を変更したタイミングで、同じ受け入れ条件を再実行します。
まとめ
CSRF対策を進める実践ステップ
明日は、管理画面の重要な更新処理を1本選び、GETで状態変更していないか、トークン欠落・改ざん時に更新前の拒否が働くかを試します。拒否されなければ標準保護と例外設定を修正し、拒否できれば他の更新URLへ検査を広げます。
419・403が出た場合は保護を外さず、Cookie、トークン、送信元、拒否ログの順に切り分けます。SPAやBFFでもブラウザ側のCookie認証を守り、権限変更や決済設定には再認証と操作記録を加えます。
参考資料
本記事の内容に誤り等がございましたら、こちらからご連絡ください。
監修
Admina Team
情シス業務に関するお役立ち情報をマネーフォワード Adminaが提供します。
SaaS・アカウント・デバイスの管理を自動化し、IT資産の可視化とセキュリティ統制を実現。
従業員の入退社対応や棚卸し作業の工数を削減し、情報システム部門の運用負荷を大幅に軽減します。
中小企業から大企業まで、情シス・管理部門・経営層のすべてに頼れるIT管理プラットフォームです。




