理解Web缓存与Cache-Key:投毒为何可能发生
Web缓存的核心目标是减少源站负载并加速内容分发,其运作依赖于“缓存命中”机制。当客户端发起请求时,CDN或反向代理会提取请求特征生成唯一的Cache-Key,并在缓存存储中查找匹配项。若命中,则直接返回缓存响应;若未命中,则回源获取并缓存。默认情况下,Cache-Key通常仅包含URL路径与Host,但实际业务中,请求头(如Accept-Language)、Cookie或查询参数同样可能改变源站生成的HTML或JSON内容。缓存投毒的根本风险正源于此:当某个输入参数实质影响了源站响应,却未被纳入Cache-Key的计算范围时,缓存系统会错误地将不同语义的请求视为同一对象。例如,若应用根据未加入Cache-Key的自定义Header动态渲染页面,攻击者即可利用该差异污染缓存,导致后续所有匹配该Key的正常用户均收到被篡改的响应。
典型Web缓存投毒:从异常输入到恶意缓存响应
典型的Web缓存投毒攻击链始于攻击者构造包含异常输入的HTTP请求。该请求到达源站后,若后端代码未对特定变量(如Host、X-Forwarded-Host、查询参数或自定义Header)进行严格过滤,便可能将其直接拼接到响应体中,例如生成错误的重定向地址或注入恶意脚本。由于缓存层的Cache-Key未包含该变量,系统会将其与正常请求归为同一缓存对象,并将受污染的响应持久化存储。当后续普通用户发起相同路径的请求时,缓存直接返回恶意内容,完成攻击闭环。与普通Web漏洞(如反射型XSS或SQL注入)不同,缓存投毒不依赖受害者主动触发恶意链接,而是通过污染共享缓存实现“一对多”的被动传播。其危害具有隐蔽性与持久性,即使源站修复漏洞,已缓存的恶意响应仍会在TTL过期前持续影响大量用户。

实战验证:如何判断Cache-Key是否安全
在授权测试环境中验证Cache-Key安全性,需遵循系统化排查流程。首先通过响应头中的Server、Via或X-Cache字段识别缓存层类型。随后发送两次相同请求,观察首次返回X-Cache: MISS,第二次返回HIT,确认缓存已生效。接着,逐项修改可能影响响应的输入变量(如添加非常规查询参数、修改Accept-Encoding或伪造X-Forwarded-Host),保持URL路径不变。若发现响应内容发生实质性变化,但后续请求仍返回X-Cache: HIT且Age值持续增长,则说明该变量未被纳入Cache-Key,存在投毒风险。测试时需重点关注缓存信号的一致性,并记录异常响应是否会被后续相同Key的请求复用。整个过程必须严格限制在授权范围,避免对生产环境造成污染或触发安全告警。

防御Cache-Key:让“影响响应的输入”与缓存规则一致
防御缓存投毒的核心原则是确保Cache-Key的覆盖范围与所有实质影响响应的输入保持严格一致。在CDN或反向代理配置中,应明确将协议、端口、Host、关键查询参数及语言偏好等维度纳入Key计算。例如,Nginx可通过proxy_cache_key "$scheme$host$request_uri$http_accept_language";实现精细化控制。对于动态或个性化内容,应利用HTTP的Vary头指示缓存层根据指定请求头区分对象,或直接设置Cache-Control: private禁止公共缓存。同时,需严格区分公开资源与用户私有数据,避免将含认证状态的响应错误缓存。合理配置并非简单禁用缓存,而是通过精准匹配缓存边界与业务逻辑,在保障性能的同时消除输入差异导致的响应混淆风险。
验证修复与常见避坑:避免“看似安全”的缓存配置
修复配置后必须进行闭环验证,确保不同语义的请求不再共享同一缓存对象。重新执行前述测试用例,确认修改关键输入后缓存层返回MISS或生成独立Key,且响应内容符合预期。同时检查缓存清理与失效策略,确保紧急情况下可通过Purge API快速清除污染数据。实践中常见误区包括:仅过滤URL参数而忽略Header或Cookie的影响;盲目将所有请求头加入Cache-Key导致缓存命中率骤降;忽视认证状态导致私有响应被公开缓存;以及仅检查首次响应差异,未验证后续请求是否真正命中独立缓存。安全的缓存设计需持续监控命中率与异常拦截日志,结合自动化测试定期审计Cache-Key策略,避免陷入“配置已改但风险犹存”的假象。

