泥棒は「あなたの家」を知っている?CSRFから大切な情報を守るための「秘密の合言葉」の話
こんにちは!セキュリティの現場で日々、複雑な攻撃と対峙しているエンジニアです。
今日は、Web開発を始めたばかりの皆さんが必ず一度は耳にするであろう「CSRF(クロスサイト・リクエスト・フォージェリ)」という攻撃について、少しだけお話しさせてください。
名前を聞くと難しそうですが、実はこれ、「本物になりすまして、勝手にドアを開けさせる」という、非常に古典的かつ巧妙な手口なんです。今日はこの攻撃をどう防ぐか、その切り札である「Anti-CSRFトークン」の正しい使い方を、一緒に紐解いていきましょう。
—
1. CSRFってどんな攻撃なの?(泥棒の例え)
想像してみてください。あなたは今、銀行のWebサイトにログインして、自分の口座からお金を送金しようとしています。
そこへ突然、怪しいメールが届き、あなたはついクリックしてしまいました。すると、裏側であなたのブラウザが「勝手に」銀行のサイトへ送金リクエストを送ってしまう……。これがCSRFです。
なぜそんなことができるのか? それは、ブラウザが「ログイン中のあなた」であるという証明(セッションクッキーなど)を、勝手にリクエストに添えてしまうからです。
銀行のサイト側から見れば、「あれ? 本人が送金ボタンを押したんだな」と勘違いしてしまうんですね。泥棒があなたの家の鍵(セッション情報)をこっそり借りて、勝手にドアを開けるようなものです。
—
2. 秘密の合言葉「Anti-CSRFトークン」
この「なりすまし」を防ぐために登場するのが、Anti-CSRFトークンです。
これは、Webサイト側が発行する「その人だけの、そのリクエストだけの秘密の合言葉」です。
仕組みはこうです:
1. 発行: あなたがフォーム画面を開くとき、サーバーは「今回限りの使い捨てパスワード(トークン)」をこっそり画面に埋め込みます。
2. 送信: 送金ボタンを押すとき、ブラウザはその「合言葉」も一緒にサーバーへ送ります。
3. 検証: サーバーは「送られてきた合言葉は、私がさっき渡したものと一致するか?」を確認します。
もし、怪しいサイトが勝手に送金リクエストを送ろうとしても、そのサイトは「秘密の合言葉」を知りません。サーバーは「お前、合言葉がないじゃないか! 偽物だな!」と門前払いできるわけです。
—
3. トークンを正しく管理する「ライフサイクル」
では、このトークンをどう扱えばいいのか。実装のポイントを3つのステップで見ていきましょう。
① 生成(セッションとの紐付け)
トークンは推測不可能なランダムな文字列である必要があります。
// PHPでのトークン生成例
session_start();
// セッションIDに基づいて、ユニークなトークンを生成
if (empty($_SESSION[‘csrf_token’])) {
$_SESSION[‘csrf_token’] = bin2hex(random_bytes(32)); // 推測不能な文字列
}
② 埋め込み(フォームへの隠し味)
トークンはブラウザの画面上に埋め込みますが、ユーザーに見せる必要はありません。 を使いましょう。
③ 検証と破棄(ガードマンの仕事)
サーバー側でリクエストを受け取った際、必ず突き合わせを行います。
// 検証処理
if ($_POST[‘csrf_token’] !== $_SESSION[‘csrf_token’]) {
die(“不正なリクエストです!”); // 拒否する
}
// 処理が終わったら、または一定時間経過で破棄(再利用防止)
unset($_SESSION[‘csrf_token’]);
—
4. プロの視点:これだけは守ってほしい「3つの鉄則」
現場で多くのコードを見てきましたが、以下のポイントを押さえていないと、せっかくの対策も穴だらけになってしまいます。
- Cookieの属性を固める:
セッションクッキーには必ず SameSite=Strict または Lax 属性を付与しましょう。「ブラウザの自動送信」を制限する強力な防壁になります。
- GETメソッドで状態を変えない:
「URLをクリックするだけで送金できる」ような作りは絶対NGです。データの変更を伴う処理は、必ず POST や PUT を使い、トークンによる検証を必須にしてください。
- トークンの漏洩を防ぐ:
トークン自体をURLパラメータに含めたり、ログに出力したりするのは厳禁です。「秘密の合言葉」が誰かに見られたら、防犯の意味がありません。
—
最後に:完璧な防御を目指して
セキュリティ対策に「これで一生安心」という終わりはありません。しかし、こうして一つひとつ仕組みを理解し、正しい実装を積み重ねることで、あなたの作ったアプリケーションは、泥棒が「ここは手強そうだ」と諦めるような、強固な城へと進化していきます。
最初は少し面倒に感じるかもしれませんが、それはユーザーの信頼を守るための大切なステップです。一歩ずつ、丁寧に実装していきましょう。
もしコードで迷ったり、設計に不安を感じたりしたら、いつでもまた相談してくださいね。応援しています!
コメント