Cloudflare 最近记录了其开发团队如何发现并修复一个Rust常用HTTP库hyper中的罕见漏洞:该漏洞可能会在返回HTTP 200成功响应的情况下,悄然截断大型的 HTTP 响应。该问题已经存在多年,仅在特定的时序条件下才会触发,现在它已经在上游修复,这引发了 Rust 从业者对该事件及 Cloudflare 处理方式的讨论。
该漏洞是在 Cloudflare 的Cloudflare Images中重构 Workers Images 绑定时被发现的。上线后,尽管响应报告为成功,但是部分大型图像转换请求会间歇性返回被截断的数据。
在技术拆解中,团队说明了是如何逐步定位根因并列出修复路径的。Cloudflare 的产品经理Deanna Lam、高级系统工程师Diretnan Domnan与Matt Lewis一同总结说:
我们花了六周时间追踪一个几乎不可见的漏洞,在 hyper 库中仅在特定条件下发生的竞态条件,影响了 Images 绑定如何将处理后的图像数据返回给客户端。最终,我们只用了四行代码就修复了它。
Rust的hyper库是一个实现 HTTP 协议的底层网络库,为许多高层 Rust Web 框架和应用所依赖的客户端与服务端提供了核心功能。该项目始于 2014 年,由 Sean McArthur 发起,采用宽松的 MIT 许可发布。
在客户开始报告图像被截断后,团队注意到响应返回了期望的 Content-Length 且状态为 HTTP 200,但在某些实例中只实际传输了 200 KB 而不是预期的 3.3MB,这使得截断源头难以识别。
团队通过构建可靠的复现用例、在不同 hyper 版本与环境中测试、对每个服务进行埋点,并使用分布式追踪逐步排除了各种可能性,最终将问题锁定到 Images 服务的 HTTP 响应路径。
应用层的追踪与日志并为显示错误,但低层内核系统调用跟踪(strace)显示 hyper 在缓冲的响应数据完全发送前就过早关闭了连接,确认了一个依赖时序的竞态条件。
Cloudflare 将问题追溯到了 hyper 的 HTTP/1 分发循环,它错误地忽略了未完成的缓冲刷新并过早关闭了连接,这导致在罕见时序下缓冲的响应数据丢失。为了修复该问题,团队添加了可确定性复现该竞态的测试,并修改了 hyper,确保在关闭连接前完成缓冲数据的刷新。Lam、Domnan 与 Lewis 补充说:
关键突破来自使用了内核级工具 strace,这是一层能记录套接字上实际发生了什么事情的手段。根本的漏洞存在于部分刷新与过早关闭之间的几毫秒窗口,这是在我们让系统变得更快后才出现的。
在 Reddit 上,Rust 编译器的贡献者 Martin Nordholts 对此发表了评论:
这是异步 Rust 已知的设计缺陷。在同步 Rust 中,如果能通过编译,通常就能工作,而在异步 Rust 中,情况并非如此。一类导致此类问题的原因是静默取消(silent cancellation),本文就是此类漏洞可能带来问题的一个例子。
关于 Cloudflare 并未赞助 hyper 及其他重要的 Rust 基础库的维护者 Sean McArthur,Jim Fuller写到:
一家年收入达 20 亿美元的公司撰写了精彩文章,却似乎并未直接支持那些对该公司收入至关重要的开发人员。
在一条热门的Hacker News讨论 中,有从业者将注意力放在 Rust 的代码质量上:
如果启用 Clippy 的 `let_underscore_untyped`或`let_underscore_must_use` lint,这个问题本可被标出,但遗憾的是这些 lint 并没有默认开启。
除此之外,还有声音质疑 Cloudflare 的监控能力:
Cloudflare 是在大规模发送错误响应并且直到客户投诉才察觉到这一点吗?这本应通过采样以及对若干回复的 lint 检查提前发现。
修复及其配套测试已经被合并进了hyper项目,将在未来的发布中提供,以防止该响应截断问题再次发生。
查看英文原文:Cloudflare Identifies Race Condition in hyper’s HTTP/1 Implementation





