なぜ「あなたの知らない間に」銀行振込が?CSRFという名の「なりすまし」を防ぐ極意
こんにちは。現場で泥臭いインシデント対応をしていると、「まさか、そんな単純なことで?」という攻撃にさらされているシステムをたくさん目にします。
今日は、Webセキュリティの基本中の基本でありながら、いまだに誤解や実装ミスが多い「CSRF(クロスサイト・リクエスト・フォージェリ)」についてお話しします。難しそうな名前ですが、身近な例えを使えば誰でも理解できる「防犯」の話です。
—
CSRFとは?:あなたの「鍵」を悪用する泥棒の正体
CSRFをひとことで言うと、「あなたがログインしている隙に、あなたのフリをして勝手に悪さをする攻撃」です。
想像してみてください。あなたは今、銀行のWebサイトにログインしています。その状態で、別のタブで怪しい掲示板を開いてしまいました。すると、その掲示板の中に仕込まれていた罠が、あなたのブラウザ経由で銀行のサーバーに「この口座に10万円振り込め!」という命令を送るのです。
銀行のサーバーはこう思います。「お、このリクエストはさっきログインした本人から来ているぞ。本人確認も済んでいるし、実行しよう!」
そう、これがCSRFの恐ろしさです。サーバーは「あなたが操作しているのか、それとも勝手に命令が送られてきたのか」を判断できていないのです。
—
CSRF対策の基本:本物かどうかを見分ける「合言葉」
この攻撃を防ぐために、私たちが用意するのが「CSRFトークン」という名の「合言葉」です。
サーバーは、ページを表示するたびに「今回限りの秘密の合言葉(トークン)」を画面に隠します。あなたが何か操作(振込ボタンを押すなど)をするとき、その合言葉を一緒にサーバーへ送り返してもらいます。
もし、怪しい掲示板が勝手に命令を送ろうとしても、彼らはその「秘密の合言葉」を知りません。サーバーは「合言葉がない(または間違っている)なら、これは偽物だ!」と判断して、リクエストを拒否できるわけです。
1. トークンは「予測不可能」であること
たまに「`csrf_token=12345`」のような単純なトークンを見かけますが、これは論外です。鍵が「1」や「2」だったら泥棒も簡単に開けられますよね?
トークンは、暗号論的に安全な乱数(CSPRNG)を使って生成し、誰にも推測させないことが鉄則です。
2. リクエストごとに更新する(Per-Request Token)
「一度発行されたトークンをずっと使い回す」のも危険です。もし一度でも漏洩したら、その瞬間から攻撃され放題になります。
可能であれば、画面を開くたび、あるいはアクションごとに新しいトークンを発行するようにしましょう。
—
実装のヒント:コードで見る「守り方」
例えば、PHPでの簡易的な実装イメージはこんな感じです。
// 1. サーバー側で安全な乱数を生成してセッションに保存
if (empty($_SESSION[‘csrf_token’])) {
$_SESSION[‘csrf_token’] = bin2hex(random_bytes(32)); // 推測不可能な32バイトの乱数
}
// 2. フォームの中に隠しフィールドとして埋め込む
// 「カスタムヘッダー」という新しい防衛線
最近のモダンなWebアプリケーション(ReactやVue.jsなどを使う場合)では、もっとスマートな方法が好まれます。それが「カスタムHTTPヘッダー」を使った検証です。
ブラウザの仕様として、JavaScriptから別のドメインに対して「勝手にカスタムヘッダーを付けてリクエストを送る」ことは、CORS(Cross-Origin Resource Sharing)という仕組みによって厳しく制限されています。
つまり、「X-Requested-With」のような独自のヘッダーを付けて送られてきたリクエストだけを許可するようにすれば、そもそもブラウザの制限で攻撃者はそのリクエストを送ることすらできないのです。
- HTMLフォームの場合: 隠しフィールド(CSRFトークン)が必須。
- API通信の場合: カスタムヘッダー(X-CSRF-TOKEN等)の検証が推奨。
—
最後に:完璧なセキュリティなんてない、だからこそ「多層」で守る
ここまでCSRFトークンの話をしましたが、これだけで全て解決するわけではありません。Cookieの設定で `SameSite=Strict` や `Lax` を指定することも、現在のWeb開発では「標準装備」と言えるほど重要です。
セキュリティ対策は、「玄関の鍵をかける(トークン検証)」だけでなく、「窓にも鍵をかける(SameSite属性)」「防犯カメラを付ける(ログ監視)」といった多層的な備えが大切です。
「難しそう」と思わず、まずは自分の書いているコードが「誰が命令したものか」を正しく判別できているか、一歩立ち止まって確認してみてください。あなたのその小さな注意深さが、何千人ものユーザーの資産と信頼を守ることにつながります。
これからも、一緒に賢いエンジニアを目指していきましょう!

コメント