こんにちは!インフラの保守や開発に携わる中で、「Webキャッシュ」という言葉を聞いたことはありませんか?
「サイトの表示を速くするために裏側でデータを保存してくれている便利な仕組み」……大正解です。でも、この便利なキャッシュの仕組みが、もし悪い人に狙われたらどうなってしまうでしょうか?
今回は、サイバー攻撃の世界でもちょっとマニアックで、かつ非常に厄介な「Webキャッシュ汚染(Web Cache Poisoning)」という攻撃について、身近な例えを交えながら、一歩ずつ優しく紐解いていきたいと思います。難しく考えず、一緒に防犯の仕組みを学ぶつもりで読み進めてくださいね!
—
1. 家の合鍵と宅配ボックスに例える「Webキャッシュ」の仕組み
まずは、Webキャッシュが普段どんな動きをしているのかイメージしてみましょう。
皆さんのご自宅に「大きな宅配ボックス」があるとします。
ある日、ご近所さんが「これ、みんなに配ってるおすすめのチラシです!」と、あなた宛ではなく地域全体向けのチラシをその宅配ボックスに入れていきました。
あなたが仕事から帰ってきて、「あ、宅配ボックスに荷物(データ)が入ってる!」とそれを開け、中身を確認しますよね。もしそれが自分宛の荷物じゃなくて「みんな用のチラシ」だったら、「あ、これみんな見るやつだね」とそのまま受け取ります。
さらに、次に帰ってきたご近所さんも、同じ宅配ボックスを開けてそのチラシを取り出します。わざわざ遠くのお店まで取りに行かなくても、ボックス(キャッシュサーバー)の中にあるから、パッとすぐ手に入って便利ですよね。
これが「Webキャッシュ」の基本です。
ユーザーがアクセスしたWebページの結果を、手前のサーバー(キャッシュサーバーやCDN)に一時的に保存(キャッシュ)しておき、次に同じページを見に来た人には、元のプログラムを動かさずに、保存しておいたデータをそのままパッと渡すことで、サイトを高速に表示させているんです。
—
2. 泥棒が「偽のチラシ」を仕込む手口(Webキャッシュ汚染のメカニズム)
とっても便利なこの宅配ボックスですが、もしここに悪意を持った泥棒がやってきたらどうなるでしょうか?
泥棒は、宅配ボックスの管理ルールにある「ある大きなスキ」に気づきました。
それは、「ボックスに入れるとき、宛先(キー)をどこまで細かく確認しているか」というルールです。
例えば、キャッシュサーバーが「URL(例: https://example.com/index.php)」だけで、誰から来たリクエストかを判断(キーを生成)していたとします。
ここで、攻撃者は次のような細工をしたリクエストをこっそり送り込みます。
GET /index.php?user_input=こんにちは HTTP/1.1
Host: example.com
X-Forwarded-Host: 悪いサイトのドメイン
このリクエストの中にある X-Forwarded-Host というヘッダーは、本来「ユーザーが元々アクセスしていたブラウザのドメイン情報」を裏側のサーバーに伝えるためのものです。
もし、Webアプリのプログラム側が、「おっ、親切にドメイン教えてくれたから、画面の中にそのドメインをそのまま表示しちゃおう!」と、うっかりこのヘッダーを信用してこんなHTMLを作ってしまったとします。
<!-- アプリが生成してしまう危険なHTMLの例 -->
<script>
// 渡されたドメインの情報を読み込む処理
var trackingDomain = "悪いサイトのドメイン";
console.log("Tracking loaded from: " + trackingDomain);
</script>
キャッシュサーバーは、このレスポンスを受け取ったとき、こう考えます。
「お、/index.php 宛てのデータだな!じゃあ、この結果をボックスにしまっておいて、次に同じページを見に来た人にもそのまま渡そう!」
……お気づきでしょうか?
この瞬間、「悪意あるスクリプトが埋め込まれた状態のWebページ」が、キャッシュサーバーという公式の宅配ボックスに保存(汚染)されてしまったのです。
—
3. 永続的な被害:次に訪れた罪なきユーザーへの連鎖
キャッシュが汚染されてしまうと、ここからが本当の恐怖です。
あなたがその「汚染されたWebサイト」に普通にアクセスしたとします。すると、キャッシュサーバーは、中身の安全性を確認することなく、こう言います。
「はい、さっき保存した最新のページデータですよ!」
あなたのブラウザは、そのページを受け取り、中に書かれていた悪意あるJavaScriptを実行してしまいます。
- あなたのクッキー(ログイン情報など)がこっそり抜き取られる
- 偽のログイン画面に飛ばされる
攻撃者が仕掛けた罠は一度きりではなく、キャッシュが残っている間、そのサイトを訪れた世界中の罪なきユーザー全員に牙をむくことになります。これが、「永続的な攻撃の仕組み」と呼ばれる所以です。
—
4. 現場でどう防ぐ?開発者・インフラ担当者がやるべき対策
「うわ、怖い……どうやってこの泥棒を防げばいいの?」と不安になりますよね。
でも大丈夫です。セキュリティの世界には、しっかりとした「防犯対策」が用意されています。一歩ずつ設定を確認していきましょう。
対策①:見知らぬ入力(HTTPヘッダー)をそのまま画面に出さない
一番の根本治療は、アプリ側(PHPやNode.jsなど)の設計ミスを直すことです。
特に、X-Forwarded-Host や X-Host などのリクエストヘッダーは、ユーザーが自由にいじれる値です。これらを信頼して、HTMLのリンクやスクリプトの読込先に使うのは絶対にやめましょう。
対策②:キャッシュの「キー」を正しく設定する(Varyヘッダーの活用)
キャッシュサーバーがデータを保存・識別するときの「キー(目印)」に、予期せぬヘッダーが含まれないようにします。
例えば、レスポンスの際に次のようなヘッダーを返し、キャッシュサーバーに「このヘッダーの内容が変わったら、別のデータとして保存してね」と伝えます。
# Varyヘッダーの設定例
Vary: Accept-Encoding, User-Agent, Cookie
これにより、攻撃者がヘッダーを書き換えて変なリクエストを送っても、通常のユーザーのキャッシュとは別の扱いになり、正常なユーザーを守ることができます。
対策③:CDNやキャッシュサーバー側のルールを見直す
CloudflareやAWS CloudFront、VarnishなどのCDN/キャッシュサーバーを使っている場合、「URLのクエリパラメータや特定のヘッダーを、キャッシュのキーから除外する・または厳密に制限する」という設定が可能です。
不必要なカスタムヘッダーがキャッシュの判断材料に使われないよう、インフラ側の設定を一度棚卸ししてみましょう。
—
5. まとめとこれからの第一歩
今回は、Webキャッシュ汚染の仕組みと、身近な例え、そして具体的な対策について解説しました。
- Webキャッシュは便利だけど、ルールの隙を突かれると危険な「共有の宅配ボックス」
- 攻撃者は信頼されていないはずのヘッダーを悪用して、偽のデータをボックスに詰め込む
- 開発者は入力値を信用せず、インフラ側はキャッシュのキーを厳格に管理する
セキュリティに初めて触れるときは、覚えることが多くて圧倒されてしまうかもしれません。ですが、「ユーザーからの入力や外部からの情報は、すべて一度疑ってかかる(Zero Trustの精神)」という基本の意識を持つだけで、書くコードや組むインフラの安全性は劇的に変わります。
焦らず、一歩ずつ、安全なWebの世界を作っていきましょう!それではまた次回の記事でお会いしましょう。
コメント