【実務・中級編】 Web Cache Poisoning (Webキャッシュ汚染) の攻撃シーケンス – オフェンシブセキュリティ & リバースエンジニアリング防御ガイド

Webキャッシュ汚染(Web Cache Poisoning):キャッシュサーバーを「凶器」に変える手口と防衛術

やあ。現場の最前線でインフラを支える諸君、お疲れ様。
今日は、多くのエンジニアが「CDNやキャッシュサーバーは速くするためのもの」と高を括っている裏側で、静かに牙を研いでいる恐ろしい攻撃手法――Webキャッシュ汚染(Web Cache Poisoning)について話そう。

これは単なるWebアプリの脆弱性じゃない。ユーザーのブラウザとサーバーの間に立つ「仲介者」を騙し、君たちの正当なアプリケーションを、攻撃者好みの「汚染されたコンテンツ」へと書き換えてしまう、極めて破壊的な手法だ。

—

なぜキャッシュサーバーが「共犯者」になるのか

Webキャッシュ汚染の核心は、「キャッシュキーの不一致」にある。

キャッシュサーバー(Nginx, Cloudflare, Varnish等)は、リクエストのどの要素を「キー(識別子)」として扱うかを決定している。通常はURLだが、攻撃者はここに「キャッシュには含まれないが、アプリ側では処理されるヘッダー」をねじ込む。

例えば、X-Forwarded-Host ヘッダーをアプリが信頼して動的にJavaScriptの読み込み元(src)を生成している場合、攻撃者は以下のようにリクエストを投げる。

1. 攻撃者が X-Forwarded-Host: evil-attacker.com を付与してリクエスト。
2. アプリ側はこれを受け取り、script src="https://evil-attacker.com/malicious.js" というHTMLを生成。
3. キャッシュサーバーは、この「悪意あるレスポンス」をキャッシュキー(URLのみ)と紐付けて保存。
4. 次にやってきた無実の一般ユーザーに対し、キャッシュサーバーはキャッシュされている「悪意あるレスポンス」を配布する。

こうなると、被害者は君たちのドメイン上で、攻撃者のスクリプトを堂々と実行することになる。セッションハイジャックや認証情報の窃取など、やりたい放題だ。

—

攻撃シーケンス:こうしてシステムは汚染される

現場の防御を考えるために、まずは攻撃者が狙う「隙」を確認しよう。

  • Unkeyed Inputs(非キャッシュキー入力)の発見: X-Forwarded-Host, X-Original-URL, X-Rewrite-URL といったヘッダーが、アプリのレスポンスに反映されるか確認する。
  • キャッシュの強制更新: Cache-Control: no-store を無視させるような工夫や、キャッシュサーバーが更新タイミングを誤る挙動(バグ)を突く。
  • 汚染の永続化: 多くのユーザーにヒットする人気コンテンツ(トップページやログイン画面)をターゲットにし、キャッシュの寿命(TTL)が切れるまで攻撃を継続させる。

—

実践:防御のための堅牢な実装

「ヘッダーを信頼しない」というのが鉄則だが、具体的にどう書くか。まずはPHPでの実装例を見てくれ。

【NG】信頼してはいけない実装

// 絶対にやってはいけない:ヘッダーをそのままURL生成に使う
$host = $_SERVER['HTTP_X_FORWARDED_HOST'] ?? 'default.example.com';
echo '<script src="https://' . $host . '/assets/app.js"></script>';

【推奨】許可リスト(Whitelist)方式の実装

/**
 * 安全なホスト名取得関数
 */
function get_safe_host() {
    $allowed_hosts = ['static.example.com', 'cdn.example.com'];
    $requested_host = $_SERVER['HTTP_X_FORWARDED_HOST'] ?? '';

    // 許可リストになければデフォルトを返す
    if (in_array($requested_host, $allowed_hosts, true)) {
        return $requested_host;
    }
    return 'static.example.com'; // 安全なフォールバック先
}

// テンプレート内での使用
$safe_host = get_safe_host();
echo '<script src="https://' . htmlspecialchars($safe_host, ENT_QUOTES) . '/assets/app.js"></script>';

—

インフラ層での防御:Nginx/WAFの設定

アプリの修正だけでなく、ゲートウェイでの制限も必須だ。Nginxで不要なヘッダーを削除する設定を推奨する。

Nginxのヘッダー除去設定

# キャッシュ汚染の原因となるヘッダーをアップストリームに渡さない
proxy_set_header X-Forwarded-Host "";
proxy_set_header X-Original-URL "";

# もし必要なら、明示的にホワイトリスト以外のヘッダーを無視する
# 信頼できるヘッダーのみを透過させる
proxy_set_header Host $host;

WAF(AWS WAF等)での対策

WAFを使用している場合、X-Forwarded-Host のようなヘッダーに「予期せぬドメイン名が含まれていないか」を監視するルールを適用せよ。特に、正規表現で「自社ドメイン以外」の値をブロックするのは非常に効果的だ。

—

最後に:セキュリティエンジニアとしての心得

Webキャッシュ汚染を防ぐことは、単なるコードの修正ではない。「外部からの入力を、どの層が信頼して処理しているのか」というデータフローの可視化だ。

開発チームにはこう伝えてほしい。
「ヘッダーは、ユーザーが自由に変えられる『ただのテキスト』だ。それを信頼してドメインやパスを生成することは、家の鍵を道端に置くのと同じことだ」と。

キャッシュサーバーを味方につけ、堅牢なシステムを構築する。それが我々プロフェッショナルの仕事だ。質問があればいつでも持ってきてくれ。共に堅牢なシステムを作り上げよう。

コメント

タイトルとURLをコピーしました