なぜ「知らないうちに銀行振込」が行われるのか?CSRF攻撃の仕組みと守り方
こんにちは!セキュリティの現場で日々、泥臭いインシデントと向き合っているエンジニアです。
今日は、Web開発者なら絶対に避けて通れない「CSRF(シーエスアールエフ)」という攻撃についてお話しします。名前は難しそうですが、仕組みを知れば「ああ、なるほど!」と腑に落ちるはず。一緒に、家の防犯に例えながら紐解いていきましょう。
—
1. CSRFってなに?「泥棒に合鍵を使わせない」仕組み
CSRF(Cross-Site Request Forgery)を日本語に直すと「クロスサイトリクエストフォージェリ」。直訳すると「サイトをまたいだ偽造リクエスト」です。
イメージしてみてください。あなたの家(Webアプリ)には、一度鍵を開けて中に入れば、しばらくの間は鍵なしで自由に動き回れる「信頼の証(セッションCookie)」がありますよね。
攻撃者は、あなたがその信頼の証を持っている隙に、「あなたのふりをして、勝手に泥棒の要求を通す」ことを企みます。例えば、「銀行の残高を全額送金しろ!」という命令書を、あなたの知らない間にブラウザからサーバーに投げつけさせるのです。これがCSRFの正体です。
—
2. なぜ防げないのか?「泥棒はあなたの家の中からやってくる」
ここが一番の盲点です。サーバー側から見ると、送られてきたリクエストは「ちゃんとログインしている本人からのもの」に見えます。なぜなら、ブラウザが勝手に正しい「信頼の証(Cookie)」を添えて送ってしまうからです。
これを防ぐには、リクエストが「本当に本人が、自分の意志で、自分のアプリ画面からボタンを押して送ったものか?」を確かめる必要があります。
—
3. 実践!CSRFを見破る「2つの防犯カメラ」
では、どうやって偽物を見破るのでしょうか?現場で使われる代表的な手法を2つ紹介します。
① Referer/Origin ヘッダーのチェック
ブラウザはリクエストを送るとき、「どこから来たか」をヘッダーに記載します。
- Referer: 「どこのURLのリンクをクリックしたか」
- Origin: 「どこのドメインから来たか」
これらが「自分のサイト(例: https://your-bank.com)」以外であれば、それは「別の怪しいサイトから無理やり送り込まれた指令」である可能性が高いと判断できます。
② アンチCSRFトークンの導入
これが最も確実な対策です。家に入るたびに「毎回変わる使い捨ての合い言葉」を渡す仕組みです。
1. 発行: サーバーは、画面を表示するたびに予測不可能なランダムな文字列(トークン)を生成し、HTMLに隠し項目として埋め込みます。
2. 検証: ユーザーが「送金ボタン」を押したとき、サーバーは「送られてきたトークン」と「サーバーが発行した正しいトークン」が一致するかを確認します。
攻撃者は、この「HTMLの中にあるトークン」を読み取ることができません。だから、どんなに命令を偽装しても、サーバーに弾かれるというわけです。
—
4. ログで異常を検知する:現場の知恵
もし、あなたのサービスに攻撃が来ているとしたら、ログにはこんな特徴が現れます。
- トークン不一致エラーの急増: 特定のユーザーから、サーバーが知らない古いトークンや空のトークンが送られ続けている。
- Refererの不自然さ: 通常の動線ではありえない外部ドメインからのPOSTリクエスト。
ログ分析のヒント(サンプルコード)
サーバーサイド(PHPの例)で、トークンを検証するイメージはこんな感じです。
—
5. まとめ:今日からできる一歩
セキュリティ対策は「完璧を目指しすぎない」ことも重要です。まずは以下の3つをチェックしてみてください。
1. フレームワークの機能を使う: 最近のフレームワーク(Laravel, Rails, Djangoなど)には、CSRF対策機能が標準装備されています。自分でゼロから書こうとせず、フレームワークの設定を「ON」にしましょう。
2. GETとPOSTを使い分ける: データを変更する処理(送金、削除、パスワード変更など)には、絶対にGETメソッドを使わないでください。GETはURLに情報が出るため、CSRFの標的になりやすいです。
3. まずはログを見る: エラーログの中に「CSRFトークン不一致」が頻発していないか確認するだけでも、攻撃の予兆を掴むことができます。
セキュリティは、鍵を一つ増やすだけで泥棒が諦めるような「抑止力」が大切です。今日から、あなたのアプリに「しっかりとした鍵」をかけていきましょう!
何か分からないことがあれば、いつでも相談してくださいね。一歩ずつ、一緒に強固なシステムを作っていきましょう。
コメント