CSRF(クロスサイト・リクエスト・フォージェリ)攻撃は、ユーザーが意図しない操作を、ユーザーが信頼しているウェブサイト上で実行させる攻撃手法です。ユーザーがログインしている状態(セッション情報が有効な状態)を悪用し、攻撃者の仕掛けたリクエストが正規の操作として実行される可能性があります。
先に結論をお伝えすると、開発者側の対策の基本は「CSRFトークン(またはフレームワーク標準のCSRF保護)」で、SameSite属性付きクッキーやOrigin・Sec-Fetch-Siteヘッダーの確認を組み合わせて守りを固めるのが現在の定石です。
本記事では、CSRFの基本的な仕組みやXSSとの違い、実際の被害事例から、開発者側およびユーザー側で講じる対策まで、最新の知見に基づいて解説します。
CSRF(クロスサイト・リクエスト・フォージェリ)とは?
CSRFは「Cross-Site Request Forgery」の略で、日本語では「クロスサイト・リクエスト・フォージェリ」、直訳すると「サイトをまたいだリクエストの偽造」です。「シーサーフ」と読まれることもあります。
ひと言でいえば、「ログイン中のユーザー本人のふりをして、本人が望んでいない操作をサイトに送りつける攻撃」です。サイト側から見ると、リクエストは正規のユーザーのブラウザから、正しいクッキー付きで届くため、本人の操作なのか攻撃なのかを区別できません。ここに、CSRFの怖さがあります。
Webアプリケーションの代表的なリスクをまとめた「OWASP Top 10」の2025年版では、CSRF(CWE-352)は1位の「アクセス制御の不備(A01:2025 Broken Access Control)」に含まれる代表的な脆弱性として挙げられています。
CSRFとXSS(クロスサイト・スクリプティング)の違い
名前が似ているXSSと混同されやすいので、違いを整理しておきます。
| CSRF | XSS | |
|---|---|---|
| 攻撃の中身 | ユーザーに意図しないリクエストを送らせる | ターゲットサイト上で攻撃者のスクリプトを実行させる |
| 悪用するもの | ブラウザが自動でクッキーを送る仕組み | 入力値をそのまま表示してしまう出力処理 |
| 攻撃者ができること | あらかじめ用意した操作(送信・変更など)を実行させるだけ。画面の内容は読めない | 画面の内容を読む、クッキーを盗む、任意の操作をするなど、より広い |
| 主な対策 | CSRFトークン、SameSite属性、Origin確認 | 出力時のエスケープ、CSP |
なお、サイトにXSSの脆弱性があると、攻撃者のスクリプトはターゲットサイト自身のページ上で動くため、CSRFトークンを読み取って突破できてしまいます。CSRF対策はXSS対策ができていることが前提だと覚えておきましょう。
CSRF攻撃の仕組み
CSRF攻撃は、以下の流れで発生します。
- ユーザーの認証状態
ユーザーがウェブサイトにログインすると、ブラウザにはそのセッション情報(通常はクッキー)が保存され、以降のリクエストに自動的に付与されます。 - 攻撃者の仕掛け
攻撃者は、不正なリクエストを作成し、ユーザーがアクセスする悪意あるウェブページやメール、広告などにそのリクエストを埋め込みます。 - 不正リクエストの送信
ユーザーが悪意あるページを閲覧すると、そのページ内に埋め込まれた<form>要素や<iframe>を利用して、ユーザーがログイン中のターゲットサイトへリクエストが自動的に送信されます。
※Same-Origin Policy(SOP、同一オリジンポリシー)は、別のサイトからレスポンスを読み取ることは制限しますが、リクエストを送ること自体は止めません。フォーム送信と同じ形式のリクエストであれば、JavaScriptのfetch()からでも送信できてしまいます。攻撃者は結果を読めなくても、「送らせる」だけで目的を達成できるのです。
以下は、概念を示す簡単なフローチャートです。
ユーザーのブラウザ
│
▼
ログイン済みの認証情報(クッキー)
│
▼
悪意あるサイト(攻撃者)の仕掛け
│
▼
自動送信される不正なリクエスト
│
▼
ターゲットサイトで不正な操作が実行
具体例:罠ページに仕込まれた自動送信フォーム
たとえば、あるサイト(example.com)に「メールアドレス変更」の機能があり、トークンなどの対策がされていないとします。攻撃者は自分のサイトに次のようなHTMLを置くだけで攻撃できます。
<form action="https://example.com/account/email" method="POST">
<input type="hidden" name="email" value="attacker@evil.example">
</form>
<script>document.forms[0].submit();</script>
example.comにログインしたままのユーザーがこのページを開くと、フォームが自動送信され、登録メールアドレスが攻撃者のものに書き換わります。その後、攻撃者が「パスワードを忘れた」機能を使えば、アカウントを乗っ取れてしまいます。ユーザーの画面には何も起きていないように見えることも多く、気づくのが遅れがちです。
GETリクエストで状態を変更していると特に危険
「/delete?id=123 にアクセスすると記事が削除される」のように、GETリクエストでデータを変更する設計になっていると、<img src="https://example.com/delete?id=123"> のような画像タグを1つ埋め込むだけで攻撃が成立します。後述するSameSite=Laxでも、リンクをクリックした場合などのGETリクエストにはクッキーが送られるため防ぎきれません。データの登録・変更・削除にはPOSTなどを使い、GETは「表示」だけに使うのが原則です。
CSRF攻撃によるリスク
CSRF攻撃が成立すると、以下のような被害が発生する可能性があります。
- 不正なアカウント操作
ユーザーのアカウント情報(メールアドレス、パスワードなど)の変更や、プロフィール内容の不正な更新が行われる恐れがあります。前述の例のように、アカウントの乗っ取りにつながることもあります。 - 金銭の不正送金
銀行や決済サービスを対象とした場合、ユーザーの知らぬ間に送金処理が実行される可能性があります。 - 不適切な投稿・コメントの作成
SNSや掲示板において、ユーザー名義で不適切な内容が自動的に投稿されるリスクがあります。 - 管理画面を通じたサイトの改ざん
管理者がログインしたまま罠ページを開くと、ユーザーの追加や権限変更、設定の書き換えなど、サイト全体に影響する操作を実行される恐れがあります。CMSのプラグインなどで、この種のCSRF脆弱性は繰り返し報告されています。 - ログインCSRF
ログインフォームが狙われ、ユーザーが攻撃者のアカウントに気づかないままログインさせられる攻撃です。そのまま入力したクレジットカード情報や検索履歴などが、攻撃者のアカウントに記録されてしまいます。
これらの被害は、攻撃対象やサービスの重要性によっては甚大な影響を及ぼすことがあります。
日本で起きた事例:PC遠隔操作事件(2012年)
CSRFが社会問題として広く知られるきっかけになったのが、2012年の「PC遠隔操作事件」です。この事件では、他人のパソコンを踏み台にしてインターネット上に犯罪予告が書き込まれ、無関係の男性が相次いで誤認逮捕されました。踏み台にされた人の多くは遠隔操作ウイルスに感染させられていましたが、そのうち1人はCSRFを仕掛けられ、本人が知らないうちに掲示板へ犯罪予告を書き込まされていたと報じられています。
CSRFによる書き込みは、サイト側の記録上は「その人のパソコンから送られた正規のリクエスト」に見えます。この事件は、CSRF対策がされていないサイトが、利用者を犯罪の加害者に仕立て上げてしまう危険を示した事例といえます。
CSRF攻撃への対策(開発者向け)
ウェブサイトのセキュリティを高めるためには、複数の対策を組み合わせることが重要です。まず、主な対策を一覧で整理します。
| 対策 | 位置づけ | ポイント |
|---|---|---|
| CSRFトークン | 基本の対策 | 攻撃者が知り得ない値をリクエストに含めさせる |
| フレームワーク標準のCSRF保護 | 基本の対策 | 自作せず、まず標準機能を有効にする |
| Sec-Fetch-Site・Originヘッダーの確認 | 基本の対策/補強 | ブラウザが付けるヘッダーで送信元を判定する |
| SameSite属性付きクッキー | 補強 | クロスサイトのリクエストにクッキーを付けさせない |
| Refererチェック | 補強 | Originが取れない場合の予備として使う |
| パスワード再入力・二段階認証 | 重要操作の保護 | 送金・パスワード変更などの直前に本人確認する |
| 通知メール | 保険 | 攻撃自体は防げないが、早く気づける |
CSRFトークンの利用
各リクエストに対して、サーバー側で生成したユニークなトークンを付与し、受信時に一致を確認する方法です。トークンが一致しないリクエストは拒否され、不正な操作が防がれます。
攻撃者の罠ページからは、同一オリジンポリシーのためにターゲットサイトのページ内容を読み取れません。そのため、フォームに埋め込まれたトークンの値を知ることができず、正しいリクエストを組み立てられないという仕組みです。
<form action="/account/email" method="POST">
<input type="hidden" name="csrf_token" value="(サーバーが生成した推測できない値)">
<input type="email" name="email">
<button type="submit">変更する</button>
</form>
実装するときは、次の点に注意してください。
- トークンは暗号論的に安全な乱数で生成し、推測できないようにする
- トークンはユーザーのセッションと結び付けて保存し、セッションごと(またはリクエストごと)に発行する
- フォームのhiddenフィールドか、Ajaxならカスタムヘッダー(例:
X-CSRF-Token)で送る。URLのクエリ文字列には入れない(ログやRefererから漏れるため) - 登録・変更・削除など、状態を変えるすべてのリクエストで検証する。ログインフォームも対象に含める
フレームワーク標準のCSRF保護を使う
主要なWebフレームワークには、CSRF対策の仕組みが標準で用意されています。自分でトークン処理を書くより、まずこれらを有効にして正しく使うのが近道です。
| フレームワーク | 主な仕組み |
|---|---|
| Laravel(PHP) | フォームに @csrf を書くとトークンが埋め込まれ、ミドルウェアが自動で検証する |
| WordPress | wp_nonce_field() でトークン(nonce)を出力し、check_admin_referer() や wp_verify_nonce() で検証する |
| Ruby on Rails | protect_from_forgery が有効で、フォームヘルパーが authenticity_token を自動で埋め込む |
| Django(Python) | CSRFミドルウェアが標準で有効。テンプレートに {% csrf_token %} を書く |
| Go | Go 1.25(2025年8月)で、Sec-Fetch-Site・Originヘッダーを使う http.CrossOriginProtection が標準ライブラリに追加 |
よくある失敗は、「Ajax用のAPIだけ保護を外してしまう」「独自に作ったフォームでトークンの出力を忘れる」といったケースです。保護を無効にしている箇所がないか、定期的に確認しましょう。
Sec-Fetch-Site・Originヘッダーの確認
現在の主要ブラウザは、リクエストに送信元の情報を示すヘッダーを自動で付けます。これをサーバー側で確認する方法は、トークンを使わずに導入できるため、近年注目されています。OWASP(Webセキュリティの国際的なコミュニティ)のCSRF対策ガイドでも、主要な対策の1つとして挙げられています。
- Sec-Fetch-Site:リクエストが同じオリジン(
same-origin)、同じサイト(same-site)、別のサイト(cross-site)のどこから来たかを示します。cross-siteから届いた変更系のリクエストを拒否すれば、CSRFを防げます。 - Origin:リクエスト元のオリジン(例:
https://example.com)を示します。Sec-Fetch-Siteを送らない古いブラウザへの予備として、自サイトのオリジンと完全一致するかを確認します。example.com.attacker.exampleのような紛らわしいドメインをすり抜けさせないよう、前方一致などでの判定は避けましょう。
これらのヘッダーはHTTPS環境で正しく送られることが前提のため、サイト全体のHTTPS化とあわせて導入するのが安全です。
リファラ(Referer)チェック
リクエスト送信元のURLを検証して、信頼できるサイトからのリクエストのみを受け付ける手法です。ただし、Referrer-Policy の設定(例: no-referrer)やプライバシー保護機能によってリファラ情報が送信されない場合があるため、単独での対策は不十分です。一般的には、CSRFトークン等の他の手法と併用する必要があります。現在は、まずOriginヘッダーを確認し、Originがない場合の予備としてRefererを使う方法が推奨されています。
SameSite属性付きクッキーの設定
クッキーにSameSite属性を設定することで、クロスサイトリクエスト時に自動的にクッキーが送信されるのを防止できます。
- SameSite=Lax: ユーザー操作によるナビゲーション(例: リンククリック)でのGETリクエストではクッキーが送信されますが、CSRFで多用されるPOSTリクエストでは送信されません。
- SameSite=Strict: すべてのクロスサイトリクエストにおいてクッキーが送信されなくなり、より厳格な対策となります。ただし、外部サイトのリンクから訪れたときもログインしていない状態で表示されるため、使い勝手とのバランスに注意が必要です。
- SameSite=None: クロスサイトでクッキーを送信する際に使用されますが、この場合はSecureフラグが必須となります。ただし、CSRF対策としては推奨されません。特別な理由がない限り、
SameSite=LaxまたはStrictを使用するべきです。
Chrome(バージョン80以降)やEdgeでは、SameSite属性が指定されていないクッキーは Lax として扱われます。ただしChromeには、属性なしのクッキーが発行されてから2分間はクロスサイトのPOSTでも送信される一時的な例外(Lax+POST)が設けられてきました。また、ブラウザによって既定の動作は異なります。既定の動作に頼らず、セッションクッキーには明示的にSameSite属性を指定しましょう。
もう1つの注意点は、SameSiteの「サイト」がサブドメインを含むドメイン全体を指すことです。たとえば blog.example.com と shop.example.com は同じサイトとみなされるため、どちらかのサブドメインが乗っ取られると、SameSiteでは防げません。そのため、SameSiteはあくまで補強の対策と考え、CSRFトークンなどと組み合わせて使います。クッキーの属性については「HTTP/HTTPSとは?ステータスコード・ヘッダー・TLSの仕組み」もあわせて参考にしてください。
重要な操作の前にパスワード再入力・二段階認証を求める
重要な操作に対しては、パスワードに加えてSMSや認証アプリなどの二段階認証を導入することで、不正なリクエストによる被害拡大を防ぎます。
ポイントは、ログイン時だけでなく、送金・パスワード変更・メールアドレス変更などの操作の直前にパスワードの再入力や認証コードを求めることです。攻撃者は本人のパスワードや認証コードを知らないため、罠ページからのリクエストだけでは処理を完了できません。IPAの「安全なウェブサイトの作り方」でも、パスワードの再入力はCSRFの根本的な解決策の1つとして紹介されています。ただし、すべての操作で毎回求めると使い勝手が悪くなるため、重要な操作に絞って導入するのが現実的です。
重要な操作を行ったら通知メールを送る
パスワードやメールアドレスの変更、送金などが行われたときに、登録済みのメールアドレスへ通知を送る方法です。攻撃そのものは防げませんが、ユーザーが身に覚えのない操作にすぐ気づけるため、被害の拡大を抑えられます。IPAも「保険的対策」として挙げています。メールアドレスの変更時は、変更前のアドレスにも通知すると効果的です。
レバテックキャリアの評判は?ITエンジニア転職のメリット・注意点【2026年】ユーザー側でできるCSRF対策
開発者だけでなく、ユーザー自身ができる対策も存在します。以下の点に注意することで、CSRF攻撃のリスクを軽減できます。
- 不要なサイトへのログイン状態を避ける
CSRF攻撃はユーザーがログイン状態にあることを前提としています。特に重要なアカウント(銀行、決済サービスなど)は、利用後にログアウトする習慣をつけることが大切です。 - ブラウザのセキュリティ設定の見直し
定期的にブラウザの設定を確認し、不必要なクッキーの保存や、自動補完機能の管理を見直すことで、不要な認証情報が悪用されるリスクを減らします。 - ブラウザを最新の状態に保つ
SameSiteの既定動作やSec-Fetch-Siteヘッダーなど、CSRFを防ぐ仕組みの多くはブラウザ側の機能です。古いブラウザではこれらが働かないため、自動更新を有効にしておきましょう。 - 不審なリンクをクリックしない
メールやSNSで送られてくる怪しいリンク、または信用性の低いサイトからのリンクには十分に注意し、安易にクリックしないよう心がけましょう。 - サービスからの通知メールを確認する
「パスワードが変更されました」など、身に覚えのない通知が届いたら、すぐにサービスへログインして状況を確認し、パスワードの変更や問い合わせを行いましょう。
ただし、CSRFは「サイト側に脆弱性があるかどうか」で成否が決まる攻撃です。ユーザー側の対策はリスクを下げる補助的なものであり、根本的な対策はサイトの開発者・運営者が行う必要があります。
DNSキャッシュポイズニングとは?攻撃の仕組みから具体的対策まで徹底解説CSRFに関するよくある質問
Q. SameSite=Laxが既定になったので、CSRF対策はもう不要ですか?
A. 不要にはなりません。前述のとおり、既定の扱いはブラウザによって異なるうえ、GETで状態を変更している処理やサブドメイン経由の攻撃はSameSiteでは防げません。SameSiteは補強と位置づけ、CSRFトークンやOrigin・Sec-Fetch-Siteの確認と組み合わせましょう。
Q. CORSを設定すればCSRFは防げますか?
A. CORSだけでは防げません。CORSは「別のオリジンからレスポンスを読み取ってよいか」を制御する仕組みで、フォーム送信と同じ形式のリクエストは、CORSの設定に関係なくサーバーまで届いてしまいます。むしろ、すべてのオリジンを許可するような緩いCORS設定は、カスタムヘッダーを使ったCSRF対策を弱める原因になります。
Q. JSONで通信するAPIにもCSRF対策は必要ですか?
A. 認証にクッキーを使っているなら必要です。サーバー側が Content-Type を厳密に確認していないと、フォーム送信の形式でJSON風のデータを送り込まれることがあります。一方、クッキーではなく Authorization ヘッダーでトークンを送る方式のAPIは、ブラウザが自動で認証情報を付けないため、CSRFの影響を受けにくくなります。
Q. ログインしていないページ(ログインフォーム)にも対策は必要ですか?
A. 必要です。前述の「ログインCSRF」を防ぐため、ログインフォームにもトークンを入れましょう。あわせて、ログインに成功したらセッションIDを新しく発行し直すことで、セッション固定攻撃も防げます。
まとめ
CSRF(クロスサイト・リクエスト・フォージェリ)攻撃は、ユーザーのログイン状態に潜む脆弱性を突き、意図しない不正操作を引き起こす危険な手法です。開発者側は、CSRFトークン(フレームワーク標準のCSRF保護)を基本に、Sec-Fetch-Site・Originヘッダーの確認、SameSite属性付きクッキー、リファラチェック、重要な操作でのパスワード再入力や二段階認証など複数の対策を組み合わせ、堅牢なセキュリティ対策を講じる必要があります。状態を変える処理にGETを使わないことや、前提となるXSS対策も忘れないようにしましょう。
同時に、ユーザー側でも、ログイン状態の管理やブラウザ設定の見直し、ブラウザの更新、不審なリンクへの注意など、基本的なセキュリティ意識を高めることが重要です。
サニタイズとは?エスケープ・バリデーションとの違いと実装方法を解説








