「なぜログインしたままWebサイトを見るだけで不正送金されるの?」「CSRFトークンって何をしているの?」「XSSとCSRFはどう違う?」——Webアプリケーションセキュリティの重要な脆弱性のひとつが「CSRF(クロスサイトリクエストフォージェリ)」です。
クロスサイトリクエストフォージェリ(CSRF:Cross-Site Request Forgery)とは、ログイン済みのユーザーを罠サイトに誘導して、ユーザーが意図しないリクエスト(送金・設定変更・退会等)を、ユーザー本人になりすまして標的Webサービスに送信させる攻撃手法です。
ユーザーのブラウザが持つ認証情報(Cookie等)を悪用するため、標的サービス側から見ると、正規のユーザーからのリクエストと見分けにくい点が特徴です。CSRFは、OWASPのCSRF Prevention Cheat SheetやASVSなどでも対策が整理されている、Webアプリケーション開発者・セキュリティ担当者が押さえておくべき重要な攻撃手法です。
クロスサイトリクエストフォージェリ(CSRF)とは?
CSRF(Cross-Site Request Forgery)とは、ユーザーが意図していないHTTPリクエストを、ユーザーのブラウザに強制的に送信させてWebアプリケーションに不正な操作を実行させる攻撃です。「クロスサイト」は「別のサイト(攻撃者のサイト)から」、「リクエストフォージェリ」は「リクエストの偽造」を意味します。

CSRFが成立する条件
- ユーザーが標的サービスにログイン済みである(セッションCookieが有効な状態)
- 標的サービスがリクエストの正当性をCookieのみで確認している(CSRFトークン等がない)
- 状態変更操作がCSRF対策なしで実行できる(送金・設定変更・メールアドレス変更・退会等)
- ユーザーが攻撃者の罠サイト・コンテンツにアクセスする(メールリンク・悪意ある広告・フォーラムへの投稿等)
CSRFの攻撃フロー
具体的な銀行の不正送金を例に、CSRFの攻撃フローを説明します。
- ユーザーが銀行サイトにログインする:ブラウザにセッションCookieが保存される
- 攻撃者がユーザーに罠サイトのURLを送る:メール・SNS等で「お得な情報はこちら」などの罠リンクを送信する
- ユーザーが罠サイトにアクセスする:銀行サイトにログインした状態のまま、別タブで罠サイトを開く
- 罠サイトが銀行サイトへのリクエストを送信する:画像読み込みや非表示フォームの自動送信などにより、ユーザーの操作なしにリクエストが発生する
- ブラウザが銀行サイトのCookieを自動付与して送信する:ブラウザは対象ドメインへのリクエストに自動でCookieを付加する仕様のため、銀行側は正規ユーザーからのリクエストと判断しやすい
- 不正操作が実行される:送金・設定変更・退会などの操作が、ユーザーの意図しない形で実行される可能性がある
CSRFで悪用されるリクエストの例
攻撃者の罠ページを開いたときに、ブラウザが自動的に標的サイトへリクエストを送信してしまうケースです。たとえば、画像読み込みの仕組みを悪用して、ログイン済みサービスに対して意図しないリクエストを送らせることがあります。ただし、本来は送金・設定変更・削除などの状態変更操作をGETリクエストで実装してはいけません。GETは情報取得に使い、状態変更操作はPOST・PUT・DELETEなどで実装し、CSRFトークンやOriginヘッダー検証を組み合わせる必要があります。
攻撃者の罠ページに非表示フォームを仕込み、ページ表示時に自動送信させる手口です。ユーザーが標的サービスにログイン済みの場合、ブラウザがCookieを自動的に付与するため、標的サービス側では正規ユーザーから送られたリクエストのように見えることがあります。そのため、状態変更を伴うPOSTリクエストには、CSRFトークンやOrigin/Refererヘッダー検証などの対策が必要です。
CSRFとXSS(クロスサイトスクリプティング)の違い
CSRFとXSSは名前が似ており混同されやすいですが、攻撃の仕組みと目的が異なります。
| 比較項目 | CSRF | XSS |
|---|---|---|
| 攻撃の起点 | 別のサイト(攻撃者の罠サイト)からリクエストを送る | 標的サイト自体に悪意あるスクリプトを埋め込む |
| 悪用する仕組み | ブラウザのCookieの自動送信 | ブラウザでのスクリプト実行 |
| 攻撃者が狙うこと | 標的ユーザーに意図しない操作(送金・設定変更等)をさせる | セッション情報の悪用・フィッシング・キーロギング・画面改ざんなど |
| ユーザーへの影響 | ユーザーが気づかないまま操作が実行される | 情報漏洩・アカウント乗っ取り・不正操作 |
| 主な対策 | CSRFトークン・SameSite Cookie・Originヘッダー検証 | 入力値のエスケープ・サニタイズ・CSP(Content Security Policy) |
| 関係性 | XSSがあると、ページ内のCSRFトークンを読み取られたり、正規画面上で不正リクエストを実行されたりする可能性があるため、CSRF対策とXSS対策は組み合わせて行う必要がある | |
CSRFの対策方法

CSRFトークン(最も一般的な対策)
CSRFトークンとは、サーバーがセッションごとに生成するランダムな文字列(トークン)をフォームに埋め込み、リクエスト送信時にサーバー側でトークンを検証する対策です。
- 仕組み:サーバーがフォームページを生成する際に、ランダムなトークンをhiddenフィールドに埋め込む
- 送信時:ユーザーがフォームを送信すると、入力内容と一緒にCSRFトークンも送信される
- 検証:サーバー側で、セッションに保存されたトークンと送信されたトークンが一致するか確認する
- 効果:攻撃者は別のオリジンからトークン値を読み取りにくいため、正しいトークンを含むリクエストを作りにくい
- 注意点:XSS脆弱性があると、ページ内のトークンを読み取られたり、正規画面上で不正リクエストを送信されたりする可能性がある
1. サーバーがランダムなCSRFトークンを生成する
2. フォーム内にhidden項目としてトークンを埋め込む
3. ユーザーがフォームを送信する
4. サーバーが「送信されたトークン」と「セッションに保存されたトークン」を比較する
5. 一致すれば処理を実行し、一致しなければ不正なリクエストとして拒否する
SameSite Cookie属性
SameSite属性とは、Cookieを送信するリクエストのサイト文脈を制限するCookieの属性です。現在の主要ブラウザでは、SameSite属性未設定のCookieを「Lax」として扱う実装が一般的です。ただし、ブラウザやWebView、古い環境では挙動が異なる場合があるため、重要なCookieには明示的にSameSite属性を設定することが推奨されます。
| SameSite値 | 動作 | CSRFへの効果 |
|---|---|---|
| Strict | 同一サイトからのリクエストにのみCookieを送信する。外部リンクからの遷移でもCookieが送信されない場合がある | ◎ 強力。ただし外部リンクからのログイン維持などで不便になる場合がある |
| Lax | 同一サイトのリクエストには送信する。クロスサイトでもトップレベルナビゲーションのGETなど、安全なメソッドでは送信される場合がある | ○ 多くのPOST型CSRFを抑制できる。ただし、GETで状態変更を行う設計や古いブラウザでは注意が必要 |
| None | クロスサイトリクエストでも送信する。Secure属性が必須 | × これだけではCSRF対策にならない |
セッションCookieには、原則としてSecure属性とHttpOnly属性を付け、用途に応じてSameSite=LaxまたはSameSite=Strictを検討します。外部サービスからの決済通知やログイン連携など、クロスサイトでCookie送信が必要な場合は、SameSite=Noneを使うこともありますが、その場合はSecure属性が必須です。
Originヘッダー・Refererヘッダーの検証
ブラウザは多くのクロスオリジンPOSTリクエストでOriginヘッダーを付与します。サーバー側ではOriginヘッダーを優先して確認し、Originがない場合はRefererヘッダーを確認するなど、実装方針を決めて検証します。
許可したオリジンからのリクエストのみ処理することで、別のオリジンから送信されたCSRFリクエストを拒否しやすくなります。
状態変更を伴うPOST・PUT・DELETEなどのリクエストでは、送信元のOriginやRefererを確認し、自社サイトからのリクエストかどうかを検証します。許可していない外部サイトからのリクエストは拒否することで、CSRFのリスクを下げられます。
ダブルサブミットCookieパターン
ダブルサブミットCookieパターンとは、CSRFトークンをCookieとリクエストパラメーター(またはカスタムヘッダー)の両方に含めて、サーバーが両者の一致を確認する方法です。サーバー側でセッションを管理せずにCSRFトークン検証ができるため、ステートレスなAPIサーバー向けに使われることがあります。
- クライアントが最初のリクエスト時にCSRFトークンCookieを受け取る
- JavaScriptがCookieからトークンを読み取り、リクエストヘッダーなどに付与する
- サーバーがCookieのトークンとヘッダーのトークンを比較して一致を確認する
- 別オリジンからは同一オリジンポリシーによりCookieの内容を読み取りにくいため、攻撃者は正しいヘッダーを付与しにくい
ダブルサブミットCookieパターンを使う場合は、単純にCookie値とリクエスト値を一致確認するだけでなく、セッションIDなどに紐づけた署名付きトークンを使う方法が推奨されます。
カスタムリクエストヘッダー(APIの場合)
JavaScriptのfetch・XMLHttpRequestで送信するAPIリクエストには、標準ブラウザフォームでは送れないカスタムヘッダーを付与し、サーバーがヘッダーの存在や値を確認することでCSRFを防ぐ方法があります。
ただし、カスタムヘッダーだけに頼るのではなく、CORS設定、SameSite Cookie属性、Origin/Refererヘッダー検証と組み合わせることが重要です。
フレームワーク別のCSRF対策の実装
| フレームワーク | CSRF対策の方法 |
|---|---|
| Django(Python) | CsrfViewMiddlewareが利用される。テンプレートではCSRFトークン用のタグを使用する |
| Laravel(PHP) | VerifyCsrfTokenミドルウェアが利用される。BladeテンプレートではCSRFトークン用のディレクティブを使用する |
| Ruby on Rails | protect_from_forgeryによりCSRF対策を行う。フォームヘルパーがCSRFトークンを付与する |
| Spring(Java) | Spring SecurityのCSRF保護を利用できる。テンプレートエンジンとの連携でトークンを付与する |
| Next.js / Nuxt.js | 構成や認証方式により対策が異なる。Cookieベース認証で状態変更APIを扱う場合は、CSRFトークン、SameSite属性、Originヘッダー検証などを実装する |
DjangoやLaravelなどのフレームワークでは、CSRF保護を無効化できる設定が用意されています。しかし、開発の便宜のためにCSRF保護を無効にしたままリリースすると、重大な脆弱性につながる可能性があります。フレームワークのCSRF保護は、特別な理由がない限り有効のままにしてください。APIエンドポイントの場合でも、Cookieベース認証を使うなら、SameSite属性、Originヘッダー検証、カスタムヘッダーなどを組み合わせて対策する必要があります。
CSRFに関連する被害・注意事例2選
事例1:送金・設定変更など状態変更操作にCSRF対策がないケース
CSRFで特に問題になるのは、送金、メールアドレス変更、パスワード変更、退会、配送先変更など、ユーザーの状態や権限に影響する操作です。これらの操作がCookie認証だけで実行でき、CSRFトークンやOriginヘッダー検証がない場合、攻撃者の罠サイトから意図しないリクエストを送信される可能性があります。
たとえば、ログイン済みユーザーが攻撃者の用意したページを開いたとき、非表示フォームが自動送信され、ユーザー本人のCookie付きで標的サイトへリクエストが送られることがあります。標的サイト側がCookieだけで本人確認を行っていると、ユーザーが意図していない操作でも正規の操作として処理されるおそれがあります。
このようなリスクを防ぐには、すべての状態変更操作にCSRFトークンを付与し、サーバー側で検証することが重要です。加えて、SameSite Cookie属性、Origin/Refererヘッダー検証、再認証、重要操作の確認画面などを組み合わせることで、被害を抑えやすくなります。
事例2:XSSとCSRFが組み合わさるケース
CSRF対策を実装していても、標的サイトにXSS脆弱性がある場合は注意が必要です。XSSによって標的サイト上で悪意あるJavaScriptが実行されると、ページ内のCSRFトークンを読み取られたり、正規画面上で不正なリクエストを送信されたりする可能性があります。
そのため、CSRFトークンを導入しているだけでは十分とは限りません。入力値のエスケープ、HTMLサニタイズ、CSP(Content Security Policy)、HttpOnly/Secure属性付きCookie、適切なセッション管理など、XSS対策と組み合わせて防御する必要があります。
この事例は、CSRF対策とXSS対策を別々に考えるのではなく、Webアプリケーション全体の防御として組み合わせる重要性を示しています。特に管理画面、アカウント設定、決済、退会、権限変更などの機能では、CSRFとXSSの両方を前提にした多層防御が必要です。
よくある質問(FAQ)
Q. HTTPSを使えばCSRFは防げますか?
防げません。CSRFはHTTPS・HTTPに関係なく成立する攻撃です。CSRFはCookieの自動送信という仕組みを悪用するため、通信が暗号化されているかどうかとは別の問題です。HTTPSは通信の盗聴・改ざんを防ぐために重要ですが、CSRF対策にはCSRFトークン、SameSite Cookie属性、Origin/Refererヘッダー検証などを実装する必要があります。
Q. GETリクエストはCSRFトークンで保護する必要がありますか?
GETリクエストは、情報の取得のみに使用し、データの変更・送信・削除など副作用のある操作には使わないことが原則です。GETリクエスト自体を副作用のない設計にすることが前提です。もしGETリクエストで状態変更操作を行っている場合は、設計を見直し、POST・PUT・DELETEなどに変更したうえで、CSRFトークンやOriginヘッダー検証などの対策を実装する必要があります。
Q. CSRFとCORS(クロスオリジンリソースシェアリング)の関係は?
CORSは、ブラウザがクロスオリジンのレスポンスを読み取れるかどうかを制御する仕組みです。CORSとCSRFは別物で、CORSを設定してもCSRFを完全に防げるわけではありません。CORSは主にレスポンスの読み取り制御に関係しますが、CSRFはリクエスト自体を偽造する攻撃です。そのため、CSRFトークン、SameSite Cookie属性、Origin/Refererヘッダー検証などの対策が別途必要です。
Q. SameSite=Laxでは不十分なケースはありますか?
あります。SameSite=Laxは多くのCSRFリスクを抑制できますが、万能ではありません。たとえば、GETリクエストで状態変更操作を行っている場合、古いブラウザや一部のWebViewでSameSite属性が期待通りに動作しない場合、外部サービスからのコールバックなどクロスサイトPOSTが必要な場合には注意が必要です。
SameSite属性は単独で使うのではなく、CSRFトークン、Origin/Refererヘッダー検証、重要操作時の再認証などと組み合わせて多層防御することが推奨されます。
Q. ログアウトしていればCSRFは関係ありませんか?
基本的には、ログアウト状態ではCSRFは成立しにくくなります。CSRFはログイン済みのセッションCookieを悪用する攻撃だからです。
しかし、現実にはWebサービスを使い終わった後にログアウトしないユーザーも多く、「ログイン状態を保持する」機能を使っている場合は長期間セッションが有効になることがあります。ユーザー側の対策としてログアウトは有効ですが、根本的にはサービス側がCSRF対策を実装する必要があります。
まとめ
CSRF(クロスサイトリクエストフォージェリ)とは、ログイン済みのユーザーを罠サイトに誘導し、ユーザーが意図しないリクエストを標的Webサービスに送信させる攻撃です。ブラウザが対象ドメインへのリクエストに自動でCookieを付与する仕組みを悪用するため、標的サービスには正規ユーザーからのリクエストとして届いてしまう可能性があります。
XSSが標的サイト内でのスクリプト実行であるのに対して、CSRFは別サイトからのリクエスト偽造という点が異なります。ただし、XSSがあるとCSRFトークンを読み取られたり、正規画面上で不正リクエストを実行されたりする可能性があるため、両方の対策を組み合わせることが重要です。
主な対策は、CSRFトークン、SameSite Cookie属性、Origin/Refererヘッダー検証、ダブルサブミットCookieパターン、カスタムリクエストヘッダーなどです。Django、Laravel、Ruby on Rails、Springなどの主要フレームワークにはCSRF保護機能が用意されているため、安易に無効化しないようにしましょう。
HTTPSの使用やCORSの設定だけでは、CSRFは防げません。すべての状態変更操作にCSRF対策を実装し、SameSite属性やOriginヘッダー検証、XSS対策と組み合わせた多層防御を徹底することが重要です。























![中小企業の情報瀬キィリティ相談窓口[30分無料]](/wp-content/uploads/2023/07/bnr_footer04.png)



CSRFは「攻撃者がAさんの手を使って、Aさんの署名(Cookie)が入った不正な手紙(リクエスト)を銀行(Webサービス)に送りつける」ようなものです。銀行はAさんの本物の署名を見るため、正規の手紙だと信じてしまいます。Aさんは手紙を送ったつもりはなく、気づいたときには送金が完了している、というイメージです。ブラウザが自動的にCookieを送信する仕組みを悪用した攻撃です。