# 踩坑实录:CDN边缘缓存欺骗攻击与缓存键重构修
故障定位思路
# 踩坑实录:CDN边缘缓存欺骗攻击与缓存键重构修复 某天下午,运营同事突然反馈:用户访问我们官网时,页面显示的内容竟然是其他站点的首页截图!我第一反应是CDN回源出了问题,但登录控制台查看缓存命中状态,一切显示正常。然而紧接着,监控告警爆发——大量HTTP 200请求导致源站负载飙升,而CDN边缘节点却始终返回缓存内容。更诡异的是,被缓存的内容并非我们的页面,而是一段恶意脚本的HTML。直觉告诉我,这不是简单的缓存击穿,而是遭遇了CDN边缘缓存欺骗攻击。 ## 问题现象与初步排查 故障发生前,我们的CDN配置一直沿用默认策略:对静态资源(CSS/JS/图片)缓存7天,对HTML页面缓存5分钟。问题出现在一个促销活动页面,URL结构类似 `/promotion?id=123`。用户访问该页面时,返回的HTML内容被篡改,包含了指向钓鱼网站的链接。 初步排查步骤: 1. **验证源站**:直接访问源站IP,返回的HTML完全正常,无任何恶意代码。 2. **清除缓存**:在CDN控制台手动刷新该URL,再次验证恢复正常,但几分钟后又复现。 3. **对比请求头**:对比正常请求和异常请求的Header,发现异常请求的 `User-Agent` 和 `Accept-Language` 与正常用户明显不同,更像爬虫或攻击脚本。 此时已经意识到:问题出在CDN边缘节点对动态URL的缓存策略上。攻击者利用某种手段绕过了缓存验证,将伪造的内容强制写入边缘节点。 ## 深入分析:缓存欺骗攻击原理 CDN边缘缓存欺骗(Cache Poisoning)是一种通过控制HTTP响应来污染缓存内容的安全攻击。常见手法包括: – **Host头注入**:伪造 `Host` 头让CDN回源到攻击者控制的服务器。 – **路径遍历**:利用 `../` 或编码绕过,命中缓存键中不存在的路径。 – **参数污染**:修改查询参数,让CDN误以为不同URL而缓存攻击者的响应。 在我们的场景中,攻击者利用的是**缓存键设计缺陷**。默认情况下,CDN以完整的URL(包括查询字符串)作为缓存键。但我们的业务逻辑中,`id` 参数来自数据库查询,对相同内容的不同 `id` 需要各自缓存。攻击者构造了一个带恶意参数的URL,例如 `/promotion?id=../../evil`,由于缓存键包含 `id` 参数,CDN认为这是一个全新的请求,回源到源站。但源站并未对参数做严格校验,导致返回了404页面(或错误页面)。攻击者再通过某种方式(如利用CDN边缘脚本或第三方漏洞)将404页面替换为恶意内容,并强制CDN缓存该结果。此后,所有访问 `/promotion?id=../../evil` 的用户都会收到恶意缓存。 更可怕的是,如果CDN支持 `Vary` 头或 `Cache-Tag`,攻击者还可以进一步扩大污染范围。 ## 踩坑点:缓存键配置的误区 事故发生时,我们正在使用某主流CDN服务。CDN控制台提供了“高级缓存键”功能,允许自定义哪些请求参数参与缓存键计算。工程师的常见做法是:将所有查询参数都包含,认为这样能保证“不同参数不同缓存”。但这是最大的误区! 误区一:**无差别缓存所有参数**。攻击者可以随意构造新参数,导致缓存键无限膨胀,并且为缓存欺骗提供了入口。正确的做法是只缓存业务上真正影响内容的参数(如 `id`),并将其他参数(`utm_source`、`session` 等)排除在外。 误区二:**忽略HTTP方法**。默认仅缓存GET请求,但CDN边缘节点可能会收到HEAD或POST请求,如果配置不当,可能被用来注入。 误区三:**忽略 `Cache-Control` 头**。源站响应头中的 `Cache-Control: no-cache` 或 `private` 会被CDN忽略(如果配置了强制缓存),导致本不应缓存的内容被缓存。 我们当时就踩了第一个误区:为了“方便”,将 `id` 和 `type` 两个参数均加入缓存键,但没有对参数值做任何限制。攻击者利用 `type=../../../` 实现了路径穿越。 ## 修复方案:缓存键重构实战 发现问题后,团队立即启动应急修复。步骤如下: ### 1. 紧急止血 – 暂停所有HTML页面的CDN缓存,回源直连。 – 在WAF上添加规则,拦截包含 `../`、`..` 等路径穿越特征的请求。 – 清除所有边缘节点缓存(全站刷新)。 ### 2. 重构缓存键策略 – **移除易被利用的参数**:对于 `id` 之外的参数,一律设为“忽略”。 – **规范化参数值**:在CDN边缘节点使用函数(如 `lowercase`、`remove_dots`)对参数值进行预处理,阻止路径穿越。 – **增加缓存键校验**:将域名、协议(http/https)、请求路径(不含查询字符串)作为主键,仅对 `id` 参数做严格格式验证后再加入缓存键。 – **启用 `Cache-Tag` 机制**:为每个资源生成唯一的标签,便于精细化的缓存清除。 ### 3. 源站加固 – 对所有输入参数做白名单验证,只允许数字和字母。 – 业务层增加 `Content-Security-Policy` 头,防止注入脚本执行。 ### 4. 验证与灰度上线 – 先在测试环境模拟攻击,确认修复有效。 – 灰度10%流量,观察无异常后再全量开启。 – 持续监控边缘节点缓存命中率与HTTP 4xx/5xx错误率。 ## 总结与教训 这次CDN边缘缓存欺骗攻击让我们付出了惨痛代价:业务中断2小时,部分用户数据可能泄露。复盘得到的核心教训: 1. **缓存键不是越多越好**,严格限定影响内容的参数,对其他参数做归一化或忽略。 2. **不要信任任何用户输入**,包括URL参数、Host头、Referer等,所有内容在CDN边缘和源站都应做安全检查。 3. **CDN不是百分百安全**,缓存机制本身可能成为攻击入口,需结合WAF、边缘函数等做多层防护。 4. **监控不能只看缓存命中率**,要关注异常响应体大小、异常参数分布等指标。 现在,我们已将缓存键配置固化到代码仓库,通过CI/CD自动部署,并定期进行安全演练。建议所有使用CDN的团队,立即检查自己的缓存键配置,避免重蹈覆辙。想继续深入:此处可内链到“CDN边缘缓存欺骗优化清单”文章。
相关阅读:此处可内链到“CDN边缘缓存欺骗常见问题”专题。
关联教程:此处可内链到“CDN边缘缓存欺骗部署与验证”内容。
延伸阅读:此处可内链到“CDN边缘缓存欺骗配置案例”相关文章。
补充参考:此处可内链到“CDN边缘缓存欺骗故障排查实例”。
延伸阅读
