反向代理缓存投毒漏洞,Nginx
反向代理缓存投毒漏洞,简单说就是攻击者利用缓存键(cache key)覆盖不完整或URL解析差异,把恶意页面的内容“塞进”代理缓存,让正常访客也拿到被污染的数据。
这类问题在配置了 Nginx proxy_cache 的站点中并不少见,往往不是缓存功能本身的锅,而是安全参数没跟上。
本文用零基础也能照做的方式,带你理解漏洞成因、加固 proxy_cache 关键参数,并完成效果验证。
缓存投毒为什么会发生
Nginx 的缓存键默认基于请求路径和部分请求头生成,比如 scheme://host$request_uri。
如果配置里没有显式定义 proxy_cache_key,不同 Host 或端口可能共用缓存键,导致跨域污染。
此外,Nginx 对 URL 规范化有自己的规则,攻击者利用 //、/../、%2f 等变体会让缓存键与上游实际请求路径不一致,从而篡改缓存内容。
正常情况下,只有当缓存命中条件、缓存键和上游响应来源三者都校验正确时,才能放行缓存;
否则就需要通过参数收紧规则。 明白了这一点,下面的配置就有了明确目标。
加固 proxy_cache 的关键参数
核心思路就是让缓存键更精确、响应更可信、并发回源更受控。
建议在 nginx.conf 的 http 块中统一规划,然后在具体 server 或 location 中生效。
proxy_cache_key:必须显式定义,避免多个虚拟主机共用默认 key。推荐格式如下:
set $cache_key $scheme://$host$request_uri;
proxy_cache_key $cache_key;
proxy_cache_valid:只缓存指定状态码,比如200 302 60m;,不要默认缓存全部状态码。proxy_cache_lock:开启后同一时间只允许一个请求回源,其他请求等待,避免缓存失效时并发穿透。proxy_cache_revalidate:用 If-Modified-Since 条件请求替代完整响应,减少缓存过期后的重复拉取。proxy_hide_header:隐藏上游返回的敏感响应头,比如Set-Cookie、X-Accel-Redirect,防止被写入缓存。proxy_ignore_headers:按需忽略上游Cache-Control等头,避免上游控制权过大覆盖本地策略。
其中 proxy_cache_key 和 proxy_hide_header 是防投毒最直接的两个参数,务必优先配置。
实战配置示例
下面是一段兼顾安全与性能的反向代理缓存配置片段,可直接调整后使用:
http {
cache_key_zone my_cache:10m;
server {
listen 80;
server_name example.com;
location / {
proxy_cache my_cache;
proxy_cache_valid 200 302 60m;
proxy_cache_key $scheme://$host$request_uri;
proxy_cache_lock on;
proxy_cache_revalidate on;
proxy_hide_header Set-Cookie;
proxy_hide_header X-Accel-Redirect;
proxy_ignore_headers Cache-Control Expires Set-Cookie;
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
}
}
}
注意:proxy_cache_key 里包含 $host 后,不同域名即使路径相同也不会互相污染。
若使用 HTTPS,建议补上 $scheme,防止 http/https 混存。
验证缓存是否安全生效
配置完成后重新加载 Nginx:
nginx -t && nginx -s reload
然后用 curl 检查响应头里的缓存标记:
curl -I http://example.com/
若看到 X-Cache-Status: HIT 或 X-Cache: HIT,说明缓存已命中。
再做一次投毒探测,访问以下变体地址:
curl -I http://example.com/%2f%2fnormal-path/
如果这些地址返回的缓存响应与正常 URL 完全一致,说明缓存键定义有效,没有被绕过。若发现变体地址生成了独立缓存条目,就要检查 proxy_cache_key 是否还是默认值。
避坑指南与常见疑问
很多用户配置后遇到“缓存不生效”或“缓存了登录态”,多是没有处理 Set-Cookie。
如果你希望公共缓存完全避开带登录态的请求,可以在 proxy_cache_key 中加入 Cookie 判断,但性能会下降;
更稳妥的做法是直接 proxy_hide_header Set-Cookie,同时只缓存 200 和 302。
另一个常见疑问是:能不能靠 proxy_cache_valid 200 就完全防投毒?
答案是不能。
它只控制缓存时长,不管缓存内容是否被篡改。真正决定投毒风险的是缓存键精确程度和上游校验逻辑,两者必须配合使用。 另外,Nginx 官方文档对 proxy_cache 各参数的说明会随版本微调,具体以你所用版本的官方文档为准,不要照抄旧配置。
如果你现在正准备处理 396.反向代理缓存投毒漏洞,建议先把文中的配置逐行核对自己的 server 块;
遇到缓存命中异常时,优先查看 proxy_cache_key 和 proxy_hide_header 两个参数,再结合 curl 返回值定位问题。
安全加固没有一劳永逸,定期检查和更新配置才是长期有效的做法。