TL

CSRF(クロスサイトリクエストフォージェリ)

ログイン中のあなたのブラウザを“代理人”にして、罠サイトが本物サイトへ勝手にリクエストを送らせる攻撃。Cookie が自動で付く性質を悪用される。

中級セキュリティCSRFCookieWebアプリ最終更新: 2026-06-04
TL;DR要点だけ先に
  • 1.CSRF は「ログイン済みの利用者」を踏み台に、本人の意図しないリクエスト(送金・設定変更など)を本物サイトに送らせる攻撃。
  • 2.原因は Cookie が“別サイト発のリクエストにも自動で付く”こと。盗む(XSS)のではなく、本人の権限で勝手に実行させるのが本質。
  • 3.本命の対策は CSRF トークン。これに SameSite Cookie と Origin/Referer 確認を重ねる多層防御が定石。

どう攻撃されるのか(仕組み)

ポイントは「被害者がすでに本物サイトにログイン済み」であることです。たとえば銀行サイト bank.examplesession_id の Cookie でログインしているとします。この状態で、攻撃者の罠ページ evil.example を開いてしまうと――

<!-- evil.example に置かれた罠。被害者が開いた瞬間に勝手に送信される -->
<form action="https://bank.example/transfer" method="POST" id="f">
  <input type="hidden" name="to" value="attacker-account">
  <input type="hidden" name="amount" value="1000000">
</form>
<script>document.getElementById('f').submit();</script>

このフォームの送信先は bank.example です。ブラウザは「bank.example 宛のリクエストだから」と、保存済みの session_id Cookie を自動的に付けて送ります。サーバから見れば「正しいセッションを持った本人からの正規の送金依頼」と区別がつかず、処理してしまう。これが CSRF の核心です。

リクエストは <img src>fetch でも仕掛けられ、被害者の画面には何も起きていないように見えるのが厄介な点です。攻撃の成立条件を整理します。

成立条件内容崩せば防げる
ログイン状態の悪用被害者が対象サイトにログイン済み(Cookieが有効)Cookieの自動送信を絞る(SameSite)
リクエストの予測可能性送信パラメータを攻撃者が組み立てられる推測不能なCSRFトークンを必須にする
送信元の無検証サーバが「どのサイトから来たか」を見ていないOrigin / Referer を検証する

何が危険か

CSRF は情報を盗む攻撃ではなく、本人になりすまして「操作させる」攻撃です。だからレスポンスの中身(残高表示など)は攻撃者には見えません。それでも危険なのは、状態を変える操作(書き込み系)を本人の権限で実行できてしまうから。

  • 送金・購入などの金銭被害
  • メールアドレスやパスワードの変更によるアカウント乗っ取り(変更後に本人を締め出せる)
  • 退会・データ削除などの取り返しのつかない操作
  • 管理者が踏めば権限昇格や設定改ざんに直結

つまり「読めないから無害」ではありません。副作用のある操作を勝手に走らせられる点で、十分に致命的です。

XSS との違い

CSRF と XSS は名前が似ていて混同されがちですが、攻撃の方向がまったく逆です。ここを取り違えると対策もズレます。

観点CSRFXSS(クロスサイトスクリプティング)
やること本人の権限で“操作を実行させる”ページ内で攻撃者の“JSを実行する”
スクリプト実行不要(攻撃者の罠サイト上で完結)必要(被害サイト上で任意コードが走る)
盗めるか原則盗めない(レスポンスは見えない)盗める(Cookie・トークン・入力値)
悪用する性質Cookieが自動送信されること出力のエスケープ漏れ(注入を許すこと)
主な対策CSRFトークン / SameSite / Origin確認出力のエスケープ / CSP / HttpOnly
XSS があると CSRF 対策は無力化される

両者は別物ですが、XSS は CSRF 対策の“前提”を壊します。攻撃者の JS が被害サイト上で動けば、ページ内の CSRF トークンを読み取って正規リクエストに同梱できてしまうからです。同様に HttpOnly Cookie も、XSS 下では「読めなくても、ブラウザに送らせる」操作は可能。CSRF 対策の大前提として、まず XSS を出さないことが欠かせません。

対策:本命は CSRF トークン

最も確実なのは**CSRF トークン(同期トークン)**です。考え方はシンプルで、「攻撃者には推測も入手もできない秘密の値」をリクエストに要求し、それが無い/合わないものを弾きます。Cookie は自動で付けられても、この秘密の値までは攻撃者のページから埋め込めません。

// 1) フォーム表示時:セッションに紐づくランダムなトークンを発行し、画面に埋め込む
app.get('/transfer', (req, res) => {
  const token = issueCsrfToken(req.session); // 例: crypto.randomBytes(32) を保存
  res.render('transfer', { csrfToken: token }); // <input type="hidden" name="_csrf"> に出力
});

// 2) 送信時:届いたトークンとセッション側の値を突き合わせる
app.post('/transfer', (req, res) => {
  if (req.body._csrf !== req.session.csrfToken) {
    return res.status(403).send('Forbidden'); // 403 = 本人だが許可しない
  }
  doTransfer(req.body); // ここで初めて実行
});

罠ページからの送信には _csrf が無い(または推測値で外れる)ため、403 で止まります。

SPA / API なら “Double Submit Cookie” も定番

サーバ側にトークンを保存したくないステートレスな構成では、Double Submit Cookie がよく使われます。トークンを「Cookie」と「リクエストヘッダ(例 X-CSRF-Token)」の両方に同じ値で載せ、サーバで一致を確認する方式です。攻撃者は被害者の Cookie の値を読めないためヘッダ側を一致させられません。React/Vue などでは Axios の xsrfCookieName / xsrfHeaderName がこの仕組みを前提にしています。

対策:SameSite Cookie で“自動送信”を絞る

そもそもの原因は「Cookie が別サイト発でも付く」ことでした。これをブラウザ側で制御するのが SameSite 属性です。

SameSite の値別サイトからの送信使いどころ
Strict一切付けない最も安全。ただし外部リンク遷移でも未ログイン扱いになる
LaxGETのトップレベル遷移のみ付ける現代ブラウザの既定。POST等の書き込みはブロックされCSRFに有効
None常に付ける(要 Secure)別ドメイン埋め込み等で必要。CSRF対策は別途必須
SameSite“だけ”に頼らない

SameSite=Lax(多くのブラウザの既定)は CSRF を大きく緩和しますが、単独の完全対策ではありません。理由は (1) 古い/設定次第のブラウザでは効かないことがある、(2) 同一サイト内(サブドメイン間など)から仕掛けられる経路は防げない、(3) SameSite=None が必要な構成では無力、だからです。SameSite は“保険”、本命は CSRF トークン。両方を重ねるのが正解です。

対策:Origin / Referer の確認

サーバ側で「このリクエストはどのサイトから来たか」を確かめる方法もあります。書き込み系(POST/PUT/DELETE)のリクエストに付く Origin(無ければ Referer)ヘッダを見て、自サイト以外なら拒否します。

// 状態を変える操作の前に、送信元オリジンを検証する
app.post('/transfer', (req, res) => {
  const origin = req.headers.origin || req.headers.referer;
  if (!origin || new URL(origin).host !== 'bank.example') {
    return res.status(403).send('Bad origin');
  }
  // …以降は CSRF トークン検証へ(重ねる)
});

Origin ヘッダは JS からは書き換えられないためなりすましが難しく、有効なチェックになります。ただし環境によっては Referer が送られない(プライバシー設定・プロキシ等)ため、これも単独ではなく、CSRF トークンと併用するのが堅実です。

やってはいけない“なんちゃって対策”

最後に、効きそうで効かない/不十分な対策を潰しておきます。

これらは CSRF 対策にならない
  • 「POST にすれば安全」 → 嘘です。攻撃者は自動送信フォームで POST も自由に作れます(冒頭の例がまさにそれ)。
  • 「Cookie ではなくセッションを使っているから大丈夫」 → セッションIDも Cookie で運ばれるなら、自動送信される以上 CSRF の対象です。
  • 「Referer をチェックすれば十分」 → Referer は送られないことがあり、それを“許可”すると簡単に回避されます。
  • 「ユーザーごとの秘密のURLにする」 → URL は Referer やログ、ブックマーク経由で漏れ、トークンの代わりになりません。
  • CAPTCHA や再認証 → 重要操作には有効ですが、全リクエストには現実的でなく、CSRF トークンの代替にはなりません。
実務のまとめ

「CSRF トークン(同期トークン or Double Submit)を本命に、SameSite=Lax/Strict と Origin 確認を重ねる」——これが多層防御の定石です。加えて HttpOnly / Secure Cookie で Cookie 自体を守り、XSS を出さないこと(トークンを読まれない)が大前提。多くの Web フレームワーク(Rails・Django・Spring・Laravel 等)は CSRF トークンを標準搭載しているので、**まずはそれを“切らずに使う”**のが第一歩です。

GET と状態変更(POST 等)の役割を分け、副作用のある操作を安全な経路に寄せる設計は、HTTP メソッドの安全性・冪等性の考え方とも地続きです。攻撃面の全体像は XSSSQLインジェクション と合わせて押さえると、Web の脆弱性が立体的に見えてきます。

セキュリティ Article

CSRF(クロスサイトリクエストフォージェリ)を実務で読む

TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。

解決すること

セキュリティ

比較で見る軸

難易度: intermediate / カテゴリ: セキュリティ / タグ数: 4

導入後に効く点

原因は Cookie が“別サイト発のリクエストにも自動で付く”こと。盗む(XSS)のではなく、本人の権限で勝手に実行させるのが本質。

先に潰すリスク

用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。

数字・仕様の読み方
難易度
intermediate
カテゴリ
セキュリティ
タグ数
4

判断チェックリスト

  • 自社の用途が「セキュリティ / CSRF」に近いか確認する。
  • 強みである「CSRF は「ログイン済みの利用者」を踏み台に、本人の意図しないリクエスト(送金・設定変更など)を本物サイトに送らせる攻撃。」が本当に評価軸になるか確認する。
  • 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
  • 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
  • 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
  • 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。

次に確認する観点

セキュリティCSRFCookieWebアプリセキュリティCSRFCookieWebアプリ
参考: 公式情報