CSRF
クロスサイトリクエストフォージェリ
ログイン済みユーザーに意図しないリクエストを送らせる攻撃。Cookieの自動送信を悪用する。
概要
CSRF(クロスサイトリクエストフォージェリ、「シーサーフ」とも読みます)は、あるサイトにログイン済みのユーザーを罠にかけ、本人が意図しないリクエストをそのサイトへ送らせる攻撃です。攻撃者自身はユーザーの認証情報を知りません。にもかかわらず「本人による正規の操作」として通ってしまう点が、この攻撃の巧妙さです。
鍵になるのはブラウザの Cookie の挙動です。ブラウザは、あるドメインへリクエストを送るとき、そのドメインの Cookie を自動的に添えます。この「自動送信」は、リクエストがどのサイトの JavaScript や HTML から発生したかを問いません。攻撃者はこの性質を利用し、罠サイトから標的サイトへリクエストを飛ばさせることで、被害者のセッションに便乗するのです。
なぜ生まれたか
CSRF もまた、Web の基本設計の副作用として現れた脆弱性です。HTTP はもともとステートレス(状態を持たない)で、リクエストごとに「これは誰か」を判別できません。そこで、ログイン状態を保つために Cookie にセッション ID を入れ、ブラウザが以降のリクエストへ自動で添える、という仕組みが広まりました。この「利用者が意識しなくてもログイン状態が引き継がれる」利便性が、そのまま弱点になりました。
サーバから見ると、正規の画面から送られたリクエストも、まったく無関係な罠サイトから送られたリクエストも、有効なセッション Cookie が付いていれば区別がつきません。「Cookie が付いている=本人の意思による操作」と暗黙に信頼してしまっていたわけです。この「リクエストがどこ由来かを検証していなかった」という欠落を突く攻撃手法として CSRF が知られるようになり、その対策が Web アプリの標準的な備えとして定着していきました。
詳細
攻撃の流れ
具体的な流れをステップで追います。前提として、被害者は銀行サイトにログイン済みで、セッション Cookie がブラウザに残っているものとします。
罠は驚くほど単純です。たとえば <img src="https://bank.example/transfer?to=attacker&amount=100000"> という画像タグを罠ページに置くだけで、被害者がそのページを開いた瞬間、ブラウザは銀行サイトへ GET リクエストを送り、セッション Cookie を添えます。POST が必要な場合も、被害者に見えない自動送信フォームを使えば同様です。被害者は「攻撃者のページを開いた」だけで、送金操作をした覚えはありません。
対策1: CSRFトークン
古くからの王道が CSRF トークンです。サーバはフォームを表示するときに、推測不可能なランダムな値(トークン)を埋め込み、同じ値をセッションにも保存しておきます。フォーム送信時にはこのトークンも一緒に送らせ、サーバは受け取った値とセッション側の値が一致するかを検証します。
この対策が効く理由は、同一オリジンポリシーにあります。罠サイトの JavaScript は、標的サイトが発行したトークンの値を読み取れません。Cookie は自動で付いてしまっても、フォームの中身であるトークンまでは攻撃者が知りようがないため、正しいトークンを添えられず検証に落ちる、という仕掛けです。
正規のフォームと罠サイトで結果が分かれる様子を図にすると、この仕掛けがよく分かります。
対策2: SameSite Cookie属性
より新しく、現在の第一防衛線になっているのが Cookie の SameSite 属性です。これは「別サイトから発生したリクエストには、この Cookie を添えない」とブラウザに指示するものです。SameSite=Lax(多くのブラウザの既定値)なら、他サイトからの POST などには Cookie が送られなくなり、CSRF の前提である「Cookie の自動送信」自体が成立しなくなります。SameSite=Strict はさらに厳格です。
ただし SameSite だけに頼り切るのは危険です。古いブラウザは対応していないことがあり、また同一サイト内に別の脆弱性があると回避されうるため、重要な操作では CSRFトークンと SameSite を併用する多層防御が推奨されます。
誤解しやすい点と XSS との対比
いくつか注意点があります。まず、CSRF 対策としてよく誤解されるのが CORS です。CORS はレスポンスの「読み取り」を制限する仕組みであって、リクエストが届いて処理されること自体は止めません。CSRF は結果を読めなくても送金が成立すれば目的を達するため、CORS は CSRF 対策になりません。また、参照だけの GET と違い、状態を変える操作は必ず POST/PUT/DELETE にし、そこにトークン検証をかけるという設計の基本も効いてきます。
最後に XSS との対比で覚えると区別が明確になります。XSS は「攻撃者のスクリプトを被害者のブラウザで実行させる」攻撃、CSRF は「被害者のブラウザに意図しないリクエストを送らせる」攻撃です。そして重要なのは、XSS が成立している環境では、攻撃者のスクリプトがページ内から CSRFトークンを読み取れてしまうため、CSRF 対策が突破されうるという点です。CSRF 対策は「XSS がないこと」を土台に成り立っている、という依存関係を押さえておくと、両者の関係が立体的に見えてきます。