CyberFix Note
脆弱性・CVE解説

CSRFとは何か。仕組みからトークン・SameSite Cookieによる対策まで実務目線で解説

対象の目安: Webアプリ開発者 / 実務レベル

ソウ攻撃・脆弱性リサーチ担当
・ 約19分で読めます
CSRFとは何か。仕組みからトークン・SameSite Cookieによる対策まで実務目線で解説

CSRF(Cross-Site Request Forgery、クロスサイト・リクエスト・フォージェリ)は、利用者がログイン済みであることを悪用し、本人の意図しないリクエストを攻撃者がWebアプリへ送り込ませる攻撃です。SQLインジェクションやXSSのように「サーバーやページに不正なデータを差し込む」攻撃とは性質が異なり、CSRFが狙うのは「ブラウザが正規のリクエストに自動でCookieを付けて送る」という、Webの正常な仕組みそのものです。だからこそ、対策の考え方を一度きちんと理解しておかないと、的外れな防御をして安心してしまいがちです。

近年はSameSite Cookieという仕組みがブラウザ側で広く効くようになり、「もうCSRFは気にしなくてよいのでは」という声も聞かれます。しかし結論から言えば、SameSiteだけに頼るのは危険で、CSRFトークンなどアプリ側の対策と組み合わせるのが正しい姿です。この記事では、なぜCSRFが成立するのかという原理から、CSRFトークン(同期トークンパターン・ダブルサブミットCookie)とSameSite Cookieの活用、そして両者をどう組み合わせるかという多層防御の判断基準までを、実務目線で順を追って整理します。

CSRF対策の早見表

まず全体像をつかむために、代表的な対策を整理します。詳細は後続のセクションで掘り下げます。

対策位置づけ仕組み主な注意点
同期トークンパターン根本対策サーバーがセッションに紐づくトークンを発行し、リクエストの値と照合する状態を持つ。トークンの漏えい・XSSに弱い
ダブルサブミットCookie根本対策(ステートレス向け)同じトークンをCookieとリクエスト両方に入れ、一致を確認する素朴な実装はCookie注入に弱く、署名付きが推奨
SameSite Cookie多層防御クロスサイトからのリクエストにCookieを付けさせないサブドメイン・ブラウザ実装差。単独の対策にしない
カスタムリクエストヘッダ補助(API向け)独自ヘッダの付与を要求し、CORSプリフライトを利用して防ぐ単純リクエストの範囲では効かない場合がある
再認証・重要操作の確認補助送金・退会など重要操作でパスワードや確認を挟むUXとのバランス。一般のCSRF対策の代替にはならない

なぜCSRFは成立するのか

問題の核心は、ブラウザがCookieを「リクエスト先のサイト」に対して自動的に付与する、という挙動にあります。利用者があるサービスにログインすると、サーバーはセッションを識別するCookieをブラウザに保存させます。以後、そのサービス宛てのリクエストには、ブラウザがこのCookieを自動で付けます。これはログイン状態を保つための正常な仕組みです。

ここで攻撃者は、利用者を罠ページに誘導します。罠ページには、標的サービス宛てにリクエストを送るHTMLが仕込まれています。たとえば次のようなフォームを、JavaScriptで自動送信させます。

<!-- 攻撃者の罠ページに仕込まれたフォーム(例: 送金操作を狙う) -->
<form action="https://bank.example/transfer" method="POST">
  <input type="hidden" name="to" value="attacker">
  <input type="hidden" name="amount" value="100000">
</form>
<script>document.forms[0].submit();</script>

このフォームが送信されると、宛先は標的サービスなので、ブラウザは標的サービスのログインCookieを自動で付けてリクエストを送ります。サーバーから見ると、正しいCookieが付いた、文法的にも正しいリクエストが届くだけです。それが本人の意思で送られたのか、罠ページから送らされたのかを、Cookieだけでは区別できません。命令そのものは正しく、ただ「誰の意図か」という一点だけがすり替わっている。これがCSRFの本質です。

重要なのは、攻撃者は利用者のCookieの中身を盗む必要がない、という点です。盗まなくても、ブラウザが勝手に付けてくれます。だからHTTPSで通信を暗号化していても、Cookieに HttpOnly を付けていても、それだけではCSRFは防げません。これらはCookieの盗み出しを防ぐ対策であって、ブラウザが自動でCookieを付ける挙動そのものは止めないからです。

何が起こりうるのか(影響)

CSRFが狙うのは「状態を変える操作」です。単に画面を表示するだけのGETリクエストは、本来副作用がないため標的になりにくく、副作用のある操作こそが危険です。

影響具体例
設定の改ざんメールアドレスや通知先の変更、公開範囲の変更
認証情報の乗っ取りパスワード変更、メールアドレス変更による乗っ取りの足がかり
金銭的被害送金、ポイント移転、商品の購入・発注
データの破壊退会、投稿やファイルの削除
権限の悪用管理画面での権限付与・ユーザー追加(管理者を狙うCSRF)

特に注意したいのは、メールアドレス変更とパスワード変更です。この二つをCSRFで突かれると、攻撃者は本人をアカウントから締め出して乗っ取れます。重要操作ほど、後述する再認証などの追加防御を重ねる価値があります。

注意

CSRFの検証は、必ず自分が管理する環境、または明示的に許可を得た対象に対してのみ行ってください。他人のサービスに対して罠ページからリクエストを送り込む行為は、不正アクセス禁止法をはじめとする法令に抵触するおそれがあります。本記事の手法はすべて、自社サービスの防御を確認する目的で理解してください。

根本対策(1)同期トークンパターン

最も基本的な根本対策が、CSRFトークン(同期トークン、Synchronizer Token Pattern)です。考え方はシンプルで、「攻撃者が知り得ない秘密の値」をリクエストに含ませることを必須にします。罠ページの攻撃者は、利用者のセッションに紐づくこの秘密を知らないため、正しいリクエストを組み立てられません。

具体的には次のように動きます。サーバーは、フォームを表示するときに、セッションに紐づく予測不能なトークンを生成し、隠しフィールドに埋め込みます。

<form action="/transfer" method="POST">
  <input type="hidden" name="csrf_token" value="9f3a...(予測不能なランダム値)">
  <input type="text" name="to">
  <input type="text" name="amount">
  <button type="submit">送金</button>
</form>

リクエストを受け取ったサーバーは、送られてきた csrf_token の値と、セッションに保存しておいた値が一致するかを照合します。一致しなければ拒否します。罠ページはこのトークンの値を知らないため、攻撃は成立しません。

OWASPのCSRF Prevention Cheat Sheetは、状態を持つアプリケーションでは同期トークンパターンを推奨し、トークンはサーバー側で生成し、予測不能・一意・秘密であるべきだとしています。

トークンを正しく機能させるための条件がいくつかあります。

  • 予測不能であること: 暗号論的に安全な乱数で生成します。連番や時刻ベースの推測できる値は避けます。
  • セッションに紐づくこと: あるユーザーのトークンが、別のユーザーのリクエストで通ってはいけません。
  • 状態を変えるリクエストに必須にすること: POST/PUT/PATCH/DELETEなど副作用のある操作すべてで照合します。GETには付けないのが原則です(後述)。

なお、多くのWebフレームワークはこの仕組みを標準で備えています。自前で実装するより、フレームワークのCSRF対策機能を正しく有効化するほうが安全です。

メモ

トークンをGETリクエストのURLパラメータに載せるのは避けてください。URLはアクセスログやReferer、ブラウザ履歴に残りやすく、トークンが漏えいする経路になります。トークンはPOSTのボディやリクエストヘッダで送るのが基本です。

根本対策(2)ダブルサブミットCookie

セッションにトークンを保存する同期トークンパターンは「状態を持つ」方式です。これに対し、サーバー側に状態を持ちたくない(ステートレスにしたい)場合に使われるのが、ダブルサブミットCookieです。

仕組みはこうです。サーバーは同じトークンを二つの経路で持たせます。一つはCookie、もう一つはリクエスト(ヘッダや隠しフィールド)です。サーバーは、Cookieの値とリクエストの値が一致するかだけを確認します。罠ページの攻撃者は、ブラウザが自動で付けるCookieは送らせられても、その値を読み取ってリクエスト側に同じ値を入れることはできません(別サイトのCookieはJavaScriptから読めないため)。だから一致させられず、攻撃は失敗します。

ただし、素朴なダブルサブミットCookieには弱点があります。サブドメインなどから攻撃者がCookieを書き込めてしまう「Cookie注入」が起きると、攻撃者が自分の知る値をCookieに入れ、同じ値をリクエストにも入れることで照合を突破できてしまいます。

OWASPのCheat Sheetは、素朴なダブルサブミットCookieはCookie注入の脆弱性があるとして「推奨しない(DISCOURAGED)」とし、HMACで署名する「署名付きダブルサブミットCookie」を推奨しています。

実装する場合は、トークンにセッション情報を含めてHMACで署名し、サーバー側でその署名を検証する署名付き方式を採用してください。単に「CookieとリクエストでトークンSが一致すればよい」という素朴な実装は、サブドメインを攻撃者に取られた状況などで破られる可能性があります。

ここまでがアプリ側の根本対策でした。これに重ねる強力なブラウザ側の防御が、SameSite Cookie属性です。Cookieに SameSite 属性を付けると、そのCookieをクロスサイト(別サイト)からのリクエストに付けるかどうかをブラウザが制御します。値は次の三つです。

挙動
Strict別サイトからのリクエストには一切Cookieを付けない。リンクをたどった遷移でも付かない
Lax別サイトからの「安全なメソッド(GET等)かつトップレベル遷移」のときだけ付ける。POST等の副作用操作には付けない
None別サイトからのリクエストにも付ける。利用には Secure 属性が必須

CSRFの多くはPOSTなど副作用のあるリクエストを別サイトの罠ページから送らせる攻撃なので、SameSite=Lax でも罠ページからのPOSTにはCookieがつかなくなりCSRFが大きく抑えられます。SameSite=Strict ならさらに厳格ですが、外部リンクから自サイトに来た直後にログイン状態が引き継がれないなど、利用者体験に影響することがあるため、用途に応じて使い分けます。

MDNのSet-Cookieリファレンスによれば、SameSite=Laxは「同一サイト由来のリクエスト」と「トップレベル遷移かつ安全なHTTPメソッドの両方を満たすクロスサイトリクエスト」にのみCookieを送信します。一部のブラウザはSameSite未指定時の既定値としてLaxを用います。

SameSiteを「単独の対策」にしてはいけない理由

SameSiteは強力ですが、これだけに頼るのは危険です。OWASPも、SameSiteはCSRFトークンの代わりではなく、トークンと共存させてより堅牢に守るものだ、と明言しています。理由を整理します。

  • 登録可能ドメイン単位で効く: SameSiteの判定は「サイト(登録可能ドメイン)」単位であり、オリジン単位ではありません。a.example.comb.example.com は同一サイト扱いになるため、信頼できないサブドメインがあると、そこからのリクエストは「同一サイト」とみなされて防げません。
  • 既定値や挙動にブラウザ差・経緯がある: 多くのブラウザがSameSite未指定時の既定をLax相当として扱いますが、その挙動には経緯や例外があり、すべての環境で同一とは限りません。明示的に属性を設定するのが安全です。
  • クライアントサイドCSRFには効かない: 自サイト内のJavaScriptの不備を突く形のCSRFには、SameSiteは保護を提供しません。

「SameSite=Laxが既定で効くようになったと聞いて、CSRFトークンの実装を外そうかと検討したことがあります。ただ調べてみると、自社は複数のサブドメインを運用していて、その一部は外部ベンダーに委託していました。サブドメインが同一サイト扱いになる以上、SameSiteだけでは守りきれないと分かり、トークンは残す判断にしました。」

あるWebアプリ運用担当の声

トークン認証のAPIとCSRF

近年のSPAやモバイル向けのAPIでは、認証情報をCookieではなく、Authorization: Bearer ... のようなヘッダにトークンを載せて送る設計が広く使われます。この方式は、原理的にCSRFの影響を受けにくいのが特長です。

理由は単純で、CSRFはブラウザがCookieを「自動で」付ける挙動を悪用する攻撃でした。一方、Authorizationヘッダのトークンは、JavaScriptが明示的に付与しない限り送られません。罠ページのJavaScriptは、別オリジンであるAPIのトークンを保存場所から読み出して付与することができないため、攻撃が成立しにくくなります。

ただし、いくつか前提があります。

  • トークンをCookieに保存して自動送信させると、結局CSRFの土俵に戻ります。Cookieに認証トークンを入れる設計を採るなら、Cookie認証と同様にCSRF対策が必要です。
  • トークンをlocalStorage等に保存する場合は、今度はXSSのリスクが前面に出ます。XSSがあればトークンを盗まれるため、CSRF対策の代わりにXSS対策の重要度が上がる、というトレードオフを理解しておく必要があります。

つまり「APIだからCSRFは関係ない」と一律に言えるわけではなく、認証情報がどう運ばれるか(Cookie自動送信かヘッダ明示付与か)で判断するのが正しい見方です。

状態を変えないGETにしない、という設計上の原則

CSRF対策の土台として、設計段階で守るべき原則があります。それは「状態を変える操作をGETで実装しない」ことです。

GET /delete?id=10 のように、URLにアクセスするだけで削除や設定変更が起きる作りは、CSRFの格好の的になります。<img src="..."> を罠ページに置くだけで、利用者のブラウザに副作用のあるGETを送らせられるからです。HTTPの仕様(RFC 9110)でも、GETは「安全(safe)なメソッド」、すなわち取得が目的で状態を変えないものと定義されています。状態を変える操作は、慣例としてPOST/PUT/PATCH/DELETEなどの安全でないメソッドで扱います。この原則を守るだけで、攻撃面はかなり狭まります。

その上で、副作用のあるメソッドにCSRFトークンの照合を必須にし、Cookieに適切なSameSiteを設定する、という多層構成にします。

まとめると、どう組み合わせるか

整理すると、現実的なCSRF対策は次の重ね方になります。

  1. 1

    設計で攻撃面を狭める

    状態を変える操作はGETで実装せず、POST/PUT/PATCH/DELETEで行う。これが土台です。

  2. 2

    根本対策としてCSRFトークンを入れる

    フレームワークのCSRF対策機能を有効にする、または同期トークン・署名付きダブルサブミットCookieを正しく実装し、副作用のあるリクエストすべてで照合します。

  3. 3

    SameSite Cookieを明示的に設定する

    セッションCookieに SameSite=Lax(要件次第でStrict)と Secure、HttpOnly を明示的に付け、ブラウザ側の多層防御を効かせます。

  4. 4

    重要操作には追加の確認を重ねる

    パスワード変更・送金・退会などには、再認証や確認ステップを挟み、万一の突破に対する保険を用意します。

ここで強調したいのは、これらが「どれか一つを選ぶ」関係ではなく「重ねる」関係だという点です。

でも触れられているとおり、単一の防御に依存せず多層で守るのがWebセキュリティの基本姿勢です。なお、CSRFと混同されやすいXSSや、命令とデータの分離という観点では

あわせて読みたい

SQLインジェクションとは何か。仕組み・攻撃手法・影響・対策を原理から徹底解説

の考え方も併せて押さえておくと、Web脆弱性の全体像がつながって見えてきます。

よくある質問

HTTPSにしていればCSRFは防げますか?
防げません。HTTPSは通信の盗聴・改ざんを防ぎますが、CSRFはブラウザが正規のリクエストに自動でCookieを付ける挙動を悪用する攻撃です。暗号化の有無とは別の問題で、CSRFトークンなどの専用対策が必要です。
Cookieに HttpOnly を付ければCSRF対策になりますか?
なりません。HttpOnlyはJavaScriptからCookieを読めなくする、いわばXSSによる窃取への対策です。CSRFは攻撃者がCookieの中身を読む必要がなく、ブラウザが自動で付けてくれるため、HttpOnlyでは防げません。
SameSite=Lax が既定で効くなら、CSRFトークンは不要ですか?
不要にはなりません。SameSiteはサイト(登録可能ドメイン)単位で効くためサブドメイン経由の抜け道があり、ブラウザ実装差やクライアントサイドCSRFという限界もあります。OWASPもSameSiteはトークンの代わりではなく共存させるものだとしています。
GETリクエストにもCSRF対策は要りますか?
状態を変えないGETであれば原則不要です。むしろ重要なのは、状態を変える操作をGETで実装しないことです。副作用のある操作はPOST等にし、そこにトークン照合を必須にします。
REST APIでトークン認証(Authorizationヘッダ)を使えばCSRF対策は不要ですか?
認証トークンをCookieで自動送信していなければ、原理的にCSRFの影響は受けにくくなります。ただしトークンをCookieに入れる設計なら対策が必要ですし、localStorage保存ならXSS対策の重要度が上がる、というトレードオフがあります。
ダブルサブミットCookieは安全ですか?
素朴な実装はCookie注入で破られる可能性があるため、OWASPは推奨していません。採用する場合はHMACで署名する署名付き方式にし、サーバー側で署名を検証してください。

まとめ

CSRF対策チェックリスト

  • 状態を変える操作をGETで実装していないか(副作用はPOST等にしているか)
  • 副作用のあるリクエストすべてでCSRFトークンを照合しているか
  • トークンは予測不能でセッションに紐づき、URLに載せていないか
  • ダブルサブミットCookieを使う場合、署名付き方式になっているか
  • セッションCookieに SameSite・Secure・HttpOnly を明示的に設定しているか
  • 信頼できないサブドメインがSameSiteの抜け道になっていないか確認したか
  • パスワード変更・送金など重要操作に再認証などの追加防御を重ねているか

CSRFは、仕組みさえ理解すれば「正しいCookieが付いていても、それが本人の意図かどうかは別問題」という一点に集約されます。だからこそ、本人しか知り得ない秘密(トークン)をリクエストに要求し、ブラウザ側でもSameSiteで自動送信を絞る。この二段構えを土台に、重要操作には確認を重ねる。単一の魔法の対策を探すのではなく、原理に沿って多層で守ることが、CSRFに対する最も確実な構えです。

出典・参考

この記事をシェア

関連する記事