缓存污染与缓存走私是啥?CDN配置加固最全防坑指南(小白版)

Web缓存污染和缓存走私是近年来针对CDN的高危攻击,能让你正常访问的网站突然弹出恶意脚本,或把别人的隐私数据塞进你的浏览器。本文用大白话拆解攻击原理,并给出7条可落地的CDN配置加固规则,附带验证和回滚步骤,适合零基础运维或站长直接照着操作。

缓存污染与缓存走私是啥?CDN配置加固最全防坑指南(小白版)
封面图:ZuCDN · ZuCDN 原创

说到Web Cache,很多问题都出在细节上。很多站长以为CDN只负责加速,装上以后网站变快就万事大吉。直到有一天,用户反馈说访问首页时跳到了赌博网站,或者明明没登录却看到了别人的订单信息——这时候你才意识到,CDN可能已经被利用了。这不是DNS劫持,也不是服务器被黑,而是一种更隐蔽的漏洞:Web缓存污染(Web Cache Poisoning)缓存走私(Web Cache Deception)

这两类攻击专门瞄准CDN的缓存机制,让攻击者把一个恶意内容“存进”CDN节点,然后所有用户从节点里拿到的都是被污染过的页面。更可怕的是,缓存走私还能绕过CDN的权限校验,直接拉取到本该只有管理员才能看到的接口数据。本文不扯复杂的HTTP头部推导,而是用搬仓库的比喻把原理讲清楚,再给出7条你立刻就能在CDN控制台里动手的加固规则。

一、先搞懂CDN是怎么“存”网页的

先看关键判断

想象你是一个仓库管理员(CDN节点)。用户A(首次访问者)来取货,你发现仓库里没存货,就去工厂(源站)拉了一箱货回来,放在货架上,并记下:“订单号=用户A的请求URL + 请求头里的某些特征”。下次用户B来要同一箱货,你查订单号匹配,直接拿存货给他。这个过程就叫缓存命中,货架就是缓存池,订单号就是缓存键(Cache Key)

问题出在“订单号”该怎么设计。如果只把URL当作订单号,而忽略了其他特征(比如Host头、Cookie、Accept-Language),攻击者就能伪造一个看似相同但实际不同的请求,让它被当成同一个缓存键。

二、缓存污染:攻击者如何往你家货架塞假货——Web Cache

验证与回滚

缓存污染的核心思路是:攻击者发送一个精心构造的请求,让CDN解析出错误的缓存键,然后把一个恶意响应缓存在你的网站名下。比如:

  • 攻击者请求 https://example.com/js/app.js?cb=evil,但HTTP头里偷偷加了一个 X-Forwarded-Host: evil.com
  • 你的源站收到这个请求后,可能为了支持动态域名解析,返回的HTML里把所有资源的URL都写成了 evil.com 开头。
  • CDN把这个响应缓存下来,缓存键是 example.com/js/app.js?cb=evil
  • 正常用户后来访问 /js/app.js?cb=evil(比如点击了某个带参数的链接),CDN直接返回那个带恶意域名引用的脚本。

整个过程,攻击者没有黑掉你的服务器,只是利用了CDN对某些HTTP头部的宽容处理。用户浏览器执行了来自 evil.com 的脚本,等于在受害者页面里植入了任意代码。

三、缓存走私:攻击者如何绕过权限看你的后台

先看关键判断

缓存走私听起来和污染像双胞胎,但目标完全不同。走私攻击是为了从CDN节点里偷到本不该公开的内容,比如:源站有一个敏感API,只允许管理员访问,并且要求带 Authorization 头。正常情况下,这个API不会被缓存,因为CDN通常不缓存带有Auth头的响应。

但攻击者可以构造一个“让源站认为是静态文件,让CDN认为是同一请求”的诡计。比如:

  • 攻击者请求 https://example.com/admin/api/users.txt,但故意在URL后面加个 ?static=1,或者用路径遍历 /admin/api/users/../..
  • 源站可能没做严格的路径校验,直接返回了敏感数据。而CDN却认为这是一个普通的静态文件(因为URL看起来像 .txt),于是把它缓存了。
  • 攻击者下一次就绕过 Authorization 头直接请求这个URL,因为CDN节点上的缓存是公开的,谁都能取到。

更常见的变种是:攻击者利用CDN和源站对请求路径的解析差异(比如是否解码、是否处理双斜杠),让同一个URL在CDN端和源站端被解释成不同的资源。

四、7条CDN配置加固规范,直接防住90%的缓存攻击

下面每一条都对应一个具体的攻击面,执行时请先在测试节点上验证,再全量推送。

1. 缓存键中加入Host头

攻击者通过修改 HostX-Forwarded-Host 来污染不同的虚拟主机。你的CDN配置里,必须把 $host$http_host 作为缓存键的一部分。在主流CDN(如Cloudflare、Akamai、阿里云CDN)中,通常有自定义缓存键的功能。比如Nginx作为CDN时:

proxy_cache_key "$scheme$host$request_uri";

注意不要包含 $http_x_forwarded_host 之类的用户可控变量。如果你必须保留该变量用于多站点识别,一定要在缓存键中显式排除,或者用WAF把它限制在白名单内。

2. 严格限制HTTP方法和缓存条件

只对GET和HEAD请求做缓存。POST、PUT、DELETE等不安全方法应该直接穿透或拒绝。很多攻击利用OPTIONS或TRACE触发源站返回特殊头,然后被CDN误缓存。在CDN层面设置:

proxy_cache_methods GET HEAD;

3. 规范化请求路径,消除解析歧义

CDN和源站对 //../%2e%2e 等编码字符的处理方式不同。攻击者利用这种差异绕过审计。建议在CDN的请求入口处做URL标准化:

  • 合并多余斜杠:///static///app.js/static/app.js
  • 拒绝包含 .. 或编码后等于 .. 的路径(返回403)
  • 统一对查询参数排序:确保 ?a=1&b=2?b=2&a=1 缓存键不同(但最好强制一致)

可以用CDN的“源站改写规则”或边缘计算函数来实现。

4. 使用 Vary 头精细控制缓存变体

少用 Vary: *,这等于告诉CDN每个请求都要去源站验证,彻底破坏缓存。更安全的方式是明确声明 Vary: Accept-EncodingVary: Cookie(仅当需要区分会话时)。对于静态资源,最好放弃使用 Vary 头,直接通过CDN配置来区分。

5. 禁用或严格限制 X-Forwarded-* 系列头对缓存键的影响

源站可能依赖 X-Forwarded-HostX-Forwarded-Prefix 来生成相对路径。在CDN侧,应该清除所有用户传入的 X-Forwarded-* 头,然后由CDN自己按规范添加。

6. 对敏感接口添加 Cache-Control: no-storeprivate

源站返回的响应头是最后一道防线。确保所有需要权限的接口(/admin/、/api/user/等)在HTTP响应中显式返回 Cache-Control: no-store,即使CDN配置了缓存也应当遵循。同时CDN侧可以配置规则:如果URL路径匹配敏感目录,强制跳过缓存。

7. 启用CDN的防缓存投毒功能/选项

现在主流CDN提供商已经推出了针对缓存投毒的防护。比如Cloudflare有“Cache Key”和“Origin Pull”设置中的“Verify Origin”选项;阿里云CDN也有“高级缓存配置”里的“防篡改”。找到并开启它们。

Web Cache:五、验证你的加固是否生效

配置前的检查

加固之后必须验证,否则等于没做。以下三个CURL命令可以快速检测缓存污染和走私漏洞:

  • 检测Host头污染: curl -I -H 'Host: malicious.com' https://yourdomain.com/ 如果返回的 LocationContent-Location 包含恶意域名,说明有漏洞。
  • 检测路径规范滥用: curl -I https://yourdomain.com/admin/api/../protected/data 如果响应与直接访问 /protected/data 一致且 Cache-Control 允许缓存,则存在走私风险。
  • 检测缓存键混淆: 依次请求 https://yourdomain.com/?a=1https://yourdomain.com/?a=1&b=2,如果第二个请求命中了第一个的缓存(通过 X-Cache: HIT 判断),说明缓存键范围太大。

六、如果误配置导致线上故障怎么办

实际操作要点

回滚方案必须准备:

  1. 如果是CDN控制台修改——立即恢复到修改前半小时的配置快照;
  2. 如果是Nginx规则——执行 nginx -s reload 前先备份旧配置文件,出事马上 cp backup.conf /etc/nginx/nginx.conf && nginx -s reload
  3. 如果已经缓存了错误内容——在CDN控制台执行全站缓存刷新(Purge),并联系源站修改响应头。

七、总结

配置前的检查

缓存污染和走私并不需要多么高深的黑客技术,它们往往源于配置人员对缓存机制的忽视。把上面7条规则当做安全检查清单,每次上线新功能前过一遍,就能挡住绝大多数针对性攻击。记住:CDN不只是加速器,也是一面需要你亲手拧螺丝的盾牌。把这些步骤跑通后,Web Cache基本就能稳定落地。

延伸阅读