深入解读 Read the Docs 遭遇的大规模 DDoS 攻击
2026年6月中下旬,Read the Docs 遭遇了有史以来规模最大、也最复杂的一次分布式拒绝服务(DDoS)攻击。攻击峰值时,我们的基础设施每分钟收到超过 550 万个请求,约为正常流量的 100 倍。
这次事件持续了近十天,对我们的基础设施、边缘防御和应急响应流程都是一场考验。与以往简单的流量洪峰不同,这次攻击的来源更加分散,能快速适应我们的防御手段,而且有意攻击那些绕过缓存的部分。
如今我们这个小规模运维团队终于恢复了正常作息,趁此机会来剖析一下这类攻击的原理:为什么我们现有的限流措施只能部分缓解,以及哪些策略真正帮助我们在攻击期间(基本)维持了服务可用性。
DDoS 攻击的演变
Read the Docs 一直对抓取我们所托管文档的爬虫和机器人比较宽容,基于 IP 的限流也基本能解决滥用问题。但大约两年前开始,随着 AI 爬虫 的兴起,滥用情况明显增多,看来开发基础设施社区的其他成员也遇到了类似问题。把 AI 生成的爬虫接入代理网络已经变得非常容易,我们的防御手段对此适应得还算顺利,但 6 月这次攻击的规模超过了以往任何一次的 10 倍。
这次攻击的主要特征包括:
-
流量巨大:峰值时每分钟收到 550 万个请求,而我们平时日峰值的每分钟请求量不足 10 万。
-
来源分散:恶意请求来自全球数百个网络(ASN)中的数百万个不同 IP 地址,既有住宅 IP 段,也有大大小小的主机服务商。
-
随机化 Header 和 TLS 参数:攻击者系统性地随机化 HTTP 请求头和 TLS 连接参数,以绕过基于签名的过滤器(JA3/JA4)。
-
自动化 CDN 防护的局限:Read the Docs 使用 Cloudflare,其自动 DDoS 防护确实拦截了来自所谓"已知僵尸网络"的部分流量,但攻击的大部分流量穿透了这道防线,直接打到了我们的 rate limiting 和 WAF 规则上。
-
缓存规避:攻击者专门寻找并针对会产生 cache miss 的 URL,比如带唯一路径的不存在页面(404)和临时重定向(302)。
-
自适应行为:每次我们实施封禁或 rate limit,僵尸网络就会调整请求速率,不断轮换目标路径,将流量分散到更宽的 IP 池,以此试探我们的防御边界。
规模与广度
此前我们遇到的小型 DDoS 攻击或大规模分布式爬虫,通常都会在某个维度上有所集中——请求要么来自少数几个国家,要么集中在少数 IP 段,要么只带有少数几种浏览器指纹。这次攻击则是真正的全球性的:流量同时来自所有国家。当 rate limiting 规则按 Cloudflare 各 colo(边缘节点)分别配置时,这简直是一场噩梦。很难制定出一套规则,既能限制分布式攻击,又不会误伤从单个 IP 或子网以合理速率爬取数据的合法 bot。
在某阶段,攻击者集中针对重定向,用海量流量冲击一个硬编码的 Nginx 重定向(一个简单的 rewrite 正则指令),流量大得即使水平扩展的架构也会出现请求丢失。一个这样的 Nginx 重定向,轻松处理每秒数千请求不成问题。
除了在全球范围内扩散,攻击还波及了 Read the Docs 的多个站点。公共社区文档和商业托管文档都受到了攻击,我们还发现攻击者试图打瘫需要登录的作者端 dashboard。
我们本可以简单开启 Cloudflare 的 "Under Attack Mode",对每一位访客——无论合法与否——都丢一个 JavaScript 挑战,但我们不想这样做。那会搞坏所有 API 集成,同时给数十万真实文档读者带来大量干扰。我们选择依靠 rate limiting 和定向挑战,配合增加缓存以及将更多功能推送到边缘节点。
"没有 Cloudflare,我们根本无法抵御这次攻击。"
攻击方绕过我们的防御
Read the Docs 大量依赖 Cloudflare 做缓存和限流,没有它我们根本扛不住这次攻击。我们维护着数十条限流规则(通过 Terraform 管理),从 IP 地址、Read the Docs 托管的数千个主机名和数十万个子域名、ASN、浏览器指纹,以及这些要素的任意组合等多个维度保护基础设施。
攻击最初集中在少数几个域名上——攻击者发现这些域名存在未被边缘节点缓存的 302 临时重定向,请求会直接打到我们的 Python 后端,而非 Nginx 等前端组件。几分钟内,运维团队就因短暂故障被呼叫(用户未必能感知,因为缓存中的文档页面仍会正常返回)。大约半小时后,我们就把这些重定向切换到了 Cloudflare 边缘节点处理,不再经过我们的服务器。我们以为事情到此为止,但攻击者随后一个半星期里不断变换策略,轮番对各个主机和服务发起攻击。
攻击期间呈钟摆式波动的流量分析数据。
攻击者先拉高流量探测我们的限流阈值,随后主动降速让限流窗口过期,再重新拉升——这就是所谓的 yo-yo 模式。其目的是最大化弹性扩容架构的财务成本,同时造成间歇性服务降级。攻击者清楚我们部署了 WAF 并设有速率限制,也知道如何在这些防护之下把破坏推到最大。
抵御流量型 DDoS 攻击
面对每分钟数百万次请求的流量洪峰,必须采用纵深防御策略:边缘缓存、Web 应用防火墙、速率限制、本地缓存和请求指纹识别缺一不可。最快的响应,一定来自 CDN 或 Web 应用防火墙直接返回。
边缘缓存
第一道防线是我们此前就在大量使用的方案:一个可靠的 CDN,尽可能让少量请求打到源站。用 CDN 分发文档好处很多。对 Read the Docs 来说,文档站点更新并不频繁,所以我们采用了比较激进的缓存策略,但每当新文档推送到 git 并触发重新构建时,就会清除对应站点的缓存。CDN 还能让离源站较远的用户更快地获取文档。
然而,攻击者在试探我们的防御时,很快通过 CDN 的响应速度分辨出哪些请求有缓存、哪些没有。也就是说,只要找到少数几个未缓存的请求,攻击者就有了突破口。我们仍在持续排查更多未缓存的路径和接口,不过即便是生存期很短的缓存(通过 Cache-Control 响应头 设置),无论对重定向还是正常的 200 响应,都有助于抵御这类攻击。
Read the Docs 收到每分钟 4.5 万未缓存请求时的 Slack 通知。如果没有缓存和速率限制,自动扩容的基础设施只会不停横向扩展来扛住流量,代价由我们承担。
速率限制与指纹识别
由于我们不想对所有用户都弹出 JavaScript 挑战,于是采用了定向速率限制规则:把 bot 概率评分 与按 IP 的速率限制结合起来,对可疑流量进行挑战,同时让正常用户和守规矩的 bot 不受影响地访问。解过 JavaScript 挑战的人都知道这有多麻烦。我们宁愿放过去一些恶意流量,也不愿误伤真实用户。话虽如此,我们仍然需要速率限制来保护基础设施。
防御的重点不应放在请求来自哪里(IP、国家),而应放在请求长什么样:
-
密码套件与 TLS 异常:自动化爬虫和机器人客户端的 TLS 连接通常与浏览器有明显差异。Cloudflare 的机器人检测提供了专门工具来识别这类异常。
-
过多的异常请求:正常用户和友好的机器人几乎只会收到 200 成功响应,而非重定向或 404。由于 200 响应几乎总是被缓存,基本不会造成问题。当发现大量重定向或 404 等高开销请求时,我们会对浏览器指纹、ASN 甚至整个域名实施限流。我们把这些规则称为"惩罚区",在攻击不断演变的过程中,它可能是自动缓解攻击最关键的措施。
-
协议不一致:恶意工具往往声明现代的 User-Agent,却使用较旧的 HTTP/1.1 连接。遗憾的是,本次攻击完全基于 HTTP/2 和 HTTP/3,这条线索基本帮不上忙。
-
客户端指纹识别:使用 Golang HTTP 客户端或 Python requests 模块、且 TLS 密码套件相同时,都会产生相同的JA4 指纹。这种指纹标识的是浏览器或工具,而非具体用户。不过本次攻击中指纹识别的效果也不明显,因为攻击者在随机化 TLS 参数。
-
IP 段分类:我们仍在推进的工作是,将更多 IP 段细分为不同类别并设置各自的限额。Read the Docs 这类服务接收大量自动化流量且需要放行机器人,来自 Amazon、Google Cloud、Azure 等大型云 ASN 的流量占比很高,这是可以预见的。这些大云厂商的限额应当高于普通住宅 IP 或小型主机商。
给用户留一条出路
我们做出的一个决定是:始终给真实用户留一条出路。 Read the Docs 极少对特定 IP 或 User-Agent 直接封禁。 最坏的情况也不过是一道 JavaScript 验证,用户通过之后,大约一天内不太会再次遇到验证。
经验教训与核心要点
2026 年 6 月的这次 DDoS 攻击,让我们对高流量基础设施的运维有了几个更深刻的认识:
-
面对分布式攻击,单纯封锁 IP 已经失效:僵尸网络和大规模爬虫都会借助代理服务,使简单的 IP 封禁形同虚设。这一点我们并非不了解,但此次事件再次敲响了警钟。防御体系需要在 IP 之外引入更广泛的速率限制维度,比如 ASN、主机名等。
-
把缓存用到极致:无论是静态文件、404 响应还是临时重定向,统统缓存起来。哪怕只设几分钟的缓存窗口,也能确保这些资源无法被利用来冲击后端。CDN 和大多数 Web 框架的默认缓存策略,远不能满足 Read the Docs 这类服务的需求。
-
守住缓存未命中的攻击面:攻击者会主动寻找无法缓存的路径,例如动态重定向、搜索接口和 404 页面。能缓存的地方尽量缓存,实在缓存不了的,就把处理逻辑尽可能下沉到边缘节点。
-
精准应对优于撒网式封锁:将 Bot 管理启发式规则与速率限制相结合,让我们在有效缓解攻击的同时,对正常用户的影响降到了最低。
-
Infrastructure as Code 不可或缺:通过 Terraform 管理边缘规则和 WAF 策略,让我们能够以版本控制的方式审查、测试并安全地快速上线复杂的过滤规则。
目前,来自攻击 IP 段的后台流量仍处于较低水平,但我们今天的基础设施韧性已远非攻击之前可比。随着 AI 工具和代理网络让这类攻击的成本越来越低、门槛越来越小,它们不再是大企业才能承受的威胁,而正在成为每一个高曝光度公共服务必须面对的常态。我们的运维团队终于能睡个整觉了,但我们对这件事的态度更接近"争取到了一段喘息时间",而非"攻击已是过去式"。
查看更多博客文章