WebVulnerabilities

キャッシュデセプション(Web Cache Deception)攻撃について

概要

キャッシュデセプション(Web Cache Deception)攻撃は、Webサーバーやプロキシサーバーが動的コンテンツを誤ってキャッシュするように仕向ける攻撃手法です。攻撃者は、特定のリクエストパスを工夫することで、サーバーが本来キャッシュすべきでないユーザー固有の情報をキャッシュするように誘導します。その結果、他のユーザーがこのキャッシュされたコンテンツを取得することになり、機密情報が漏洩するリスクが生じます。


脆弱性を持つコードとサーバー構成と設定の例と攻撃手法

サーバー構成

この攻撃は、サーバーが誤って動的コンテンツをキャッシュする場合に発生します。

攻撃手法の例

攻撃者は、通常キャッシュされない動的コンテンツをキャッシュさせるために、リクエストURLの末尾に.jpg.css.jsなどの静的リソース拡張子を付け加えます。これにより、サーバーやプロキシがこのリクエストを静的なリソースとして認識し、キャッシュするように誘導します。

例:

サーバーが/account/settings/profile.jpgを静的ファイルとして誤認すると、このリクエストがキャッシュされ、他のユーザーがアクセスした際に同じ内容が提供されます。

PHP

脆弱なコード例:

<?php
session_start();
if (!isset($_SESSION['user'])) {
    header("Location: /login.php");
    exit();
}

// ユーザー固有のデータを表示
echo "Welcome " . $_SESSION['user'];
?>

サーバー設定の例:

攻撃手法: 攻撃者はhttps://example.com/account/settings/profile.jpgのようなURLでリクエストを送信し、mod_cacheがこのページをキャッシュすると、他のユーザーがアクセスした際に攻撃者のセッション情報が表示される可能性があります。

Python(Flask)

脆弱なコード例:

from flask import Flask, session, redirect

app = Flask(__name__)
app.secret_key = 'super_secret_key'

@app.route('/account/settings')
def account_settings():
    if 'user' not in session:
        return redirect('/login')
    
    return f"Welcome {session['user']}"

if __name__ == '__main__':
    app.run()

サーバー設定の例:

攻撃手法: 攻撃者はhttps://example.com/account/settings/profile.jsのようなリクエストを送信し、Nginxがこのリクエストをキャッシュすると、他のユーザーが同じURLにアクセスしたときに攻撃者のセッションデータが表示される可能性があります。

Node.js(Express)

脆弱なコード例:

const express = require('express');
const session = require('express-session');
const app = express();

app.use(session({ secret: 'super_secret_key', resave: false, saveUninitialized: true }));

app.get('/account/settings', (req, res) => {
    if (!req.session.user) {
        res.redirect('/login');
    } else {
        res.send(`Welcome ${req.session.user}`);
    }
});

app.listen(3000);

サーバー設定の例:

攻撃手法: 攻撃者がhttps://example.com/account/settings/profile.cssのようなリクエストを送信し、Varnishがこれをキャッシュすると、他のユーザーが同じURLにアクセスした際に攻撃者のセッション情報が表示される可能性があります。

Java(Spring)

脆弱なコード例:

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

import javax.servlet.http.HttpSession;

@Controller
public class AccountController {

    @GetMapping("/account/settings")
    public String accountSettings(HttpSession session) {
        if (session.getAttribute("user") == null) {
            return "redirect:/login";
        }
        return "Welcome " + session.getAttribute("user");
    }
}

サーバー設定の例:

攻撃手法: 攻撃者がhttps://example.com/account/settings/profile.pngのようなリクエストを送信し、Tomcatがこれをキャッシュすると、他のユーザーが同じURLにアクセスした際に攻撃者のセッション情報が表示される可能性があります。


防止策

  1. 動的コンテンツのキャッシュ制御:
    • 動的コンテンツには、必ずCache-Control: no-storeまたはprivateを設定し、共有キャッシュに保存されないようにします。

    PHPの例:

    header("Cache-Control: private, no-store");
    

    Pythonの例(Flask):

    @app.route('/account/settings')
    def account_settings():
        if 'user' not in session:
            return redirect('/login')
        response = make_response(f"Welcome {session['user']}")
        response.headers['Cache-Control'] = 'private, no-store'
        return response
    
  2. URL構造の確認と制限:
    • URL構造を確認し、ユーザー固有のデータを提供するエンドポイントには、拡張子を持つパスが使用されないようにします。また、クエリパラメータを用いてリソースを指定する際には特に注意が必要です。

    Node.jsの例:

    app.get('/account/settings', (req, res) => {
        if (!req.session.user) {
            res.redirect('/login');
        } else {
            res.set('Cache-Control', 'private, no-store');
            res.send(`Welcome ${req.session.user}`);
        }
    });
    
  3. サーバーキャッシュ設定の最適化:
    • キャッシュサーバーやプロキシの設定を見直し、動的コンテンツやユーザー固有のコンテンツがキャッシュされないように設定を行います。また、リクエストの拡張子に基づいてキャッシュを行う場合は、例外リストを設定するなどの工夫を行います。
  4. URL正規化と入力検証:
    • サーバーに届くリクエストのURLを正規化し、不正なパスや拡張子が含まれたリクエストが処理されないようにします。
  5. キャッシュの監視と検査:
    • サーバーやプロキシのキャッシュを定期的に監視し、予期しないキャッシュが発生していないか検査します。

まとめ: Web Cache Deception攻撃は、サーバーが動的コンテンツを誤ってキャッシュするように誘導する攻撃です。キャッシュ制御ヘッダーの適切な設定、URL構造の管理、キャッシュサーバーの設定の最適化などの防止策を講じることで、この脆弱性を効果的に防ぐことが可能です。各プラットフォームや言語に共通する問題であるため、これらの対策を適用することが推奨されます。