第2回:善意を装う罠「CSRF」
〜見えない攻撃と、秘密の合言葉(トークン)〜
導入:絶対防壁「SOP」のたったひとつの盲点
前回(第1回)で、ブラウザには「同一オリジンポリシー(SOP)」という絶対防壁があり、ハッカーのサイトから銀行のデータを 「勝手に盗み見ること」 はできないとお話ししました。
「なんだ、SOPがあるならWebは安全じゃないか」
そう安心したエンジニアたちをあざ笑うかのように、ハッカーたちはSOPのルールの 「ある致命的な盲点」 を突いた、極めて卑劣な攻撃を編み出します。
SOPは確かに「他人のデータを読み取る(Read)」ことは防いでくれます。
しかし、「他人のサイトに向けて、勝手にデータを送りつける(Write/Post)」ことまでは禁止していなかったのです。
今回は、ユーザーの「信頼(ログイン状態)」を逆手にとり、ユーザー自身のフリをして悪事を働かせる見えない罠、「CSRF(クロスサイトリクエストフォージェリ)」 の恐怖と、それを防ぐ盾の物語です。
1. 悲劇のシナリオ:あなたが「犯人」にされる日
CSRF(Cross-Site Request Forgery)を直訳すると「サイト横断的な、リクエスト(要求)の偽造」となります。これがいかに恐ろしい攻撃か、具体的なシナリオを見てみましょう。
あなたは今、お気に入りの「SNS(または掲示板)」にログインしています。
ブラウザには、あなたが本人であることを証明する身分証 「セッションCookie(クッキー)」 が保存されています。
その状態で、ふと気になって別タブで「絶対に儲かる裏ワザ!」という怪しいリンク(ハッカーのサイト)を踏んでしまいました。
画面には「準備中」とだけ書かれており、何も起きません。
あなたは「なんだ、つまらない」とタブを閉じました。
しかし数日後、あなたの家に突然警察がやってきます。
「あなたがSNSで、爆破予告を書き込みましたね?」
「えっ!? そんな書き込み、絶対にしていません!」
しかし、サーバーの記録には、間違いなく「あなたのアカウント(あなたのCookie)」から書き込まれた証拠が残っているのです。
2. なぜ罠は発動したのか?(Cookieの自動送信)
一体、裏側で何が起きていたのでしょうか?
ハッカーの怪しいサイトの裏側(HTMLの中)には、次のような「見えない入力フォーム」が隠されていました。
<form action="https://sns.example.com/post" method="POST" id="evilForm" style="display:none;">
<input type="hidden" name="message" value="爆破してやる!">
</form>
<script>
// サイトを開いた瞬間に、勝手に送信ボタンを押すプログラム
document.getElementById('evilForm').submit();
</script>
このサイトを開いた瞬間、ブラウザは裏側でこっそりと「SNSの投稿用URL」に向けて、強制的にデータを送信(POST)させられていたのです。
ここで最大の問題が起きます。
ブラウザは仕様上、SNS宛てに通信を送る際、 「ブラウザに保存されているSNS用の身分証(Cookie)を、無意識に自動でくっつけて送ってしまう」 のです。
SNSのサーバー側から見れば、「正しいパスワードでログインした本人のCookie」がくっついて投稿が送られてきたわけですから、疑う余地はありません。「あ、本人が書き込んだんだな」と受理してしまいます。
ハッカーはSOPの壁があるため、あなたが書き込んだ「結果の画面」を見ることはできません。しかし、 「撃ちっぱなしのミサイル」 のように、リクエストを強制的に送らせること(フォージェリ=偽造)は可能だったのです。
3. エンジニアの反撃:秘密の合言葉「CSRFトークン」
「ブラウザが勝手にCookieを送ってしまうなら、サーバーはどうやって『本物の画面から送られた通信』と『ハッカーの罠から送られた通信』を見分ければいいんだ?」
エンジニアたちは頭を抱えましたが、やがて非常に美しく、かつ完璧な防衛策を編み出します。
それが 「CSRFトークン」 です。
仕組みは「ワンタイムパスワード」に似ています。
ユーザーがSNSの「正しい投稿画面」を開いた時、サーバーは画面の入力フォームの中に、 ランダムな乱数の文字列(トークン) をこっそり隠しておきます。
<form action="/post" method="POST">
<input type="text" name="message">
<input type="hidden" name="csrf_token" value="aB39xZ81pQ...">
<button type="submit">投稿する</button>
</form>
ユーザーが「投稿する」ボタンを押すと、Cookieと一緒にこの「CSRFトークン(合言葉)」も送信されます。サーバーは 「Cookieが正しいか」と「合言葉が一致しているか」の2つが揃って初めて、投稿を受理する ようにルールを変えました。
なぜハッカーはトークンを偽造できないのか?
ここで、第1回で学んだ 「SOP(同一オリジンポリシー)」 が最高の伏線として効いてきます!
ハッカーは、罠サイトの裏側から強制的にデータを送信させることはできます。しかし、本物の投稿画面に埋め込まれた「今回のCSRFトークンの文字列」が何なのかを読み取ることは、SOPの壁に阻まれて絶対にできないのです。
ハッカー「チクショウ! Cookieは勝手に送らせたのに、CSRFトークンの文字列が分からないから、サーバーに弾かれてしまう!」
こうして、トークンという「秘密の合言葉」の導入により、CSRFという恐ろしい罠は完全に無力化されました。
現在、LaravelやRailsといったモダンなフレームワークでは、このCSRFトークンが最初から自動で組み込まれるように進化しています。
4. さらなる進化:SameSite属性の登場
近年では、ブラウザ自身も賢くなりました。
Cookieの設定に 「SameSite属性」 という新しいルールが追加されたのです。
これはブラウザに対し、 「他人のサイト(別ドメイン)からPOST送信させられる時は、俺のCookieを絶対に一緒に送るな!」 と命令できる機能です(SameSite=Lax や Strict)。
現在、Google Chromeなどの主要ブラウザではこれが標準の挙動となりつつあり、CSRFトークンと二段構えで、ユーザーの安全はより強固に守られるようになっています。
おわりに:目に見えるものが全てではない
CSRF攻撃の恐ろしさは、「被害者が全く気づかないうちに、加害者に仕立て上げられてしまう」という点にありました。
インターネットの世界では、ブラウザの画面に表示されているものだけが全てではありません。裏側でどんな通信が飛び交っているのかを想像し、対策を講じることこそが、Webエンジニアという「盾の勇者」の腕の見せ所なのです。
次回予告
SOPの壁とCSRFトークンの盾によって、ハッカーは「外側のサイト」から罠を仕掛けることが困難になりました。
外から攻撃できないなら、ハッカーはどうするでしょうか?
「なら、相手のサイトの『内側』に、直接俺の悪意あるプログラムを注射(インジェクション)してやればいい」
掲示板のコメント欄やSNSのプロフィール欄に仕掛けられた、たった一行の <script> タグ。それが引き起こす、サイト崩壊のパンデミック。
次回、第3回。
「毒された入力欄『XSS』 〜魔法のタグの恐怖と、無害化(サニタイズ)の盾〜」
📚 参考文献・出典
本記事で解説した攻撃手法と防御策の詳細は、世界的なWebセキュリティ推進組織や公式技術ドキュメントに基づいています。
-
CSRF(クロスサイトリクエストフォージェリ)の定義と対策
-
OWASP (Open Worldwide Application Security Project):
- Webセキュリティにおける世界的なデファクトスタンダード「OWASP」によるCSRFの公式解説と、防衛策(チートシート)です
- Cross-Site Request Forgery Prevention Cheat Sheet - OWASP
-
OWASP (Open Worldwide Application Security Project):
-
SameSite Cookie属性による防御
-
MDN Web Docs (Mozilla):
- 現代のブラウザにおける強力なCSRF対策である
SameSiteクッキー属性の詳細な仕様と動作についての解説です - Set-Cookie: SameSite属性 - MDN Web Docs
- 現代のブラウザにおける強力なCSRF対策である
-
MDN Web Docs (Mozilla):