キャッシュポイズニング攻撃について
キャッシュポイズニング攻撃は、Webサーバーやプロキシサーバーのキャッシュ機構を悪用して、攻撃者が不正なコンテンツをキャッシュに注入する攻撃です。これにより、ユーザーがキャッシュされた不正なコンテンツを受け取ることになり、フィッシングやマルウェア配布などの攻撃が可能になります。キャッシュポイズニングは、特にキャッシュのキーが不適切に管理されている場合や、キャッシュポリシーが不十分な場合に発生しやすいです。
キャッシュポイズニングは、これらのサーバーが不適切に構成されている場合に発生します。
攻撃者は、キャッシュサーバーやプロキシサーバーが不適切に構成されていることを利用して、特定のリクエストに対するレスポンスを不正にキャッシュさせます。その後、他のユーザーが同じキャッシュされたレスポンスを受け取ることで、不正なコンテンツが提供されるようになります。
脆弱なコード例:
<?php
$token = $_GET['token'];
if ($token === 'admin') {
$content = "Sensitive admin content";
} else {
$content = "Public content";
}
header("Cache-Control: public, max-age=3600");
echo $content;
?>
サーバー設定の例:
Cache-Control
ヘッダーが全リクエストに対して一律で設定されている。攻撃手法:
攻撃者は、token=admin
のリクエストを送信し、その結果がキャッシュされるように仕向けます。その後、他のユーザーが同じURLをリクエストすると、キャッシュされた管理者専用のコンテンツが提供されます。
脆弱なコード例:
from flask import Flask, request
app = Flask(__name__)
@app.route('/content')
def content():
user_type = request.args.get('user_type')
if user_type == 'admin':
content = "Sensitive admin content"
else:
content = "Public content"
response = app.make_response(content)
response.headers['Cache-Control'] = 'public, max-age=3600'
return response
サーバー設定の例:
Cache-Control
ヘッダーに基づいてキャッシュを管理している。攻撃手法:
攻撃者がuser_type=admin
を指定してリクエストを送信し、そのレスポンスがキャッシュされると、他のユーザーもそのキャッシュされた管理者専用コンテンツを受け取ることになります。
脆弱なコード例:
const express = require('express');
const app = express();
app.get('/content', (req, res) => {
const userType = req.query.userType;
if (userType === 'admin') {
res.set('Cache-Control', 'public, max-age=3600');
res.send('Sensitive admin content');
} else {
res.set('Cache-Control', 'public, max-age=3600');
res.send('Public content');
}
});
app.listen(3000);
サーバー設定の例:
Cache-Control
ヘッダーに基づいてキャッシュを管理している。攻撃手法:
攻撃者は、userType=admin
を指定してリクエストを送信し、そのレスポンスがキャッシュされると、他のユーザーが同じコンテンツを取得することになります。
脆弱なコード例:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
@RestController
public class ContentController {
@GetMapping("/content")
public String getContent(@RequestParam String userType, HttpServletResponse response) {
if ("admin".equals(userType)) {
response.setHeader("Cache-Control", "public, max-age=3600");
return "Sensitive admin content";
} else {
response.setHeader("Cache-Control", "public, max-age=3600");
return "Public content";
}
}
}
サーバー設定の例:
攻撃手法:
攻撃者がuserType=admin
を指定してリクエストを送信し、そのレスポンスがキャッシュされると、他のユーザーもそのキャッシュされたコンテンツを受け取ることが可能になります。
token
やuserType
のようなパラメータに基づいてキャッシュキーを分離することで、他のユーザーに影響を与えるキャッシュを避けます。PHPの例:
<?php
if ($token === 'admin') {
header("Cache-Control: private, max-age=0");
} else {
header("Cache-Control: public, max-age=3600");
}
echo $content;
?>
Cache-Control: private
やno-cache
を設定し、共有キャッシュに保存されないようにします。Pythonの例:
if user_type == 'admin':
response.headers['Cache-Control'] = 'private, no-store, no-cache, must-revalidate'
else:
response.headers['Cache-Control'] = 'public, max-age=3600'
Node.jsの例:
if (req.isAuthenticated()) {
res.set('Cache-Control', 'private, no-store');
} else {
res.set('Cache-Control', 'public, max-age=3600');
}
まとめ: キャッシュポイズニング攻撃は、キャッシュ機構を悪用して不正なコンテンツをユーザーに提供する攻撃です。キャッシュキーの適切な管理、キャッシュ制御ヘッダーの設定、認証情報に基づくキャッシュの無効化などの防止策を実施することで、この脆弱性を効果的に防ぐことが可能です。各言語やサーバー構成に合わせた最適な対策を講じることが推奨されます。