CSRF — 押した覚えのない送金が通ってしまう
銀行サイトにログインしたまま、別のタブで見知らぬサイトを開いた――その瞬間に、自分の口座から勝手に送金が実行される。CSRF(クロスサイト・リクエスト・フォージェリ)は、こんな「意図しない操作の代行」を成立させてしまう脆弱性です。
仕掛けはとても単純で、ブラウザがCookieを自動で付けて送ってしまう性質を悪用しているだけ。攻撃者はあなたのパスワードを知る必要すらありません。下の図1で、罠サイトのボタンを押して何が起きるかを見てください。そのあと対策のスイッチを入れて、同じ攻撃が通らなくなるところまで試せます。
認証は通っているのに、本人の意思ではない
CSRFの本質は、「認証(誰か)」は確認できているのに「意図(本人が望んだか)」を確認していないことにあります。ブラウザは bank.example 宛てのリクエストなら、それを引き起こしたのがどのサイトかに関係なく、保存済みのCookieを付けて送ります。サーバーから見ると、本人の操作と罠サイト経由の偽造リクエストがまったく同じ形で届く――だから区別できません。パスワードもトークンも盗まれていないのに成立するのが、CSRFの厄介なところです。
そこでCSRFトークンを使います。サーバーは正規のフォームを返すときに、セッションに紐づく推測できない使い捨ての値をhidden項目として埋め込み、POST時にそれが一致するかを検証します。罠サイトは他サイトのページ内容を読めない(同一オリジンポリシー)ので、この値を知りようがなく、偽造リクエストはトークン不一致で弾かれます。
もう1つの防波堤が SameSite 属性です。SameSite=Lax を付けたCookieは、他サイト発のPOSTにはそもそも送られません。近年のブラウザはこれを既定に近い扱いにしており、CSRFはかなり通りにくくなりました。ただし完全に置き換わるわけではないので、トークン検証と併用するのが定石です。加えて、状態を変える操作をGETで行わないことも重要な前提になります(<img src> だけで攻撃が成立してしまうため)。
- CSRF
- ログイン済みの利用者に、別サイト経由で意図しないリクエストを送らせる攻撃。
- CSRFトークン
- 正規フォームに埋め込む使い捨ての値。他サイトからは読めないため偽造を防げる。
- SameSite
- Cookieの属性。Lax/Strict にすると他サイト発のリクエストにCookieが付かなくなる。
- 同一オリジンポリシー
- 別オリジンのページの中身をJSから読めない制限。トークンが守られる根拠。
- XSSとの違い
- XSSはスクリプトを注入して読み放題にする攻撃。CSRFは中身を読まずに操作だけさせる。
まとめ
CSRFはCookieが自動で付くという便利さの裏返しです。サーバーは「ログイン済みか」だけでなく「この操作を本人が意図したか」を確かめなければならない。その確認手段が、他サイトからは知りえないCSRFトークンと、他サイト発のリクエストにCookieを載せないSameSiteです。あわせて更新操作はPOST等に限る――この3点を押さえれば、図1の攻撃は成立しなくなります。