递归处理不可信输入的危害与防护
单个恶意请求即可摧毁使用递归函数处理不可信用户输入的Web应用。我们开发了简易CodeQL查询来辅助发现栈溢出问题,并借此在多个知名Java项目中发现了拒绝服务(DoS)漏洞。这些项目均由安全意识强、开发实践健全的组织维护:
- ElasticSearch(PatternBank中的parseGeometryCollection)
- OpenSearch(FilterPath、parseGeometryCollection及validatePatternBank)
- Protocol Buffers CVE-2024-7254
- Guava Function重写
- XStream CVE-2024-47072
研究发现表明,递归虽是强大编程工具,但在有可用性要求的应用中处理不可信数据时会成为严重隐患。上述漏洞均已修复,但若大型项目都存在此类问题,你的代码中可能也存在类似风险。阅读下文了解我们发现这些问题的方法及预防措施,或查看我们的完整白皮书。
递归的危害性
递归优雅、简单且实用,常是处理嵌套结构的首选方法,无论是遍历树、访问图节点还是解析JSON等嵌套结构。
|
|
图1:Stack Overflow中的递归Fibonacci函数
然而,若攻击者控制输入,往往可轻易构造使栈在到达递归函数基线条件前耗尽的输入。开发者常考虑防止无限递归,但仅通过触发栈溢出的单个恶意输入就可能使应用崩溃。
|
|
图2:Stack Overflow中的StackOverflowError
客户端崩溃可能带来不便,服务端崩溃则可能摧毁关键服务,即使有DDoS防护。对有可用性要求的应用而言,这是具有实际危害的真实风险。
Protobuf Java案例研究
为说明这些漏洞如何实际显现,我们以Google协议缓冲区(Protobuf)库中的CVE-2024-7254发现过程为例。此问题表明即使安全意识强的组织也可能忽略递归处理漏洞。
据Protobuf官方文档:
协议缓冲区是Google的语言中立、平台中立、可扩展的结构化数据序列化机制——类似XML,但更小、更快、更简单。(来源)
解析不可信数据 notoriously tricky,安全研究人员已针对各种格式的解析器展开研究。Google开发协议缓冲区旨在提供一种序列化交换格式,并自动生成多种语言的解析器。它们被Google内部及更广泛生态系统广泛使用。
然而,它们也易受递归错误攻击。
例如,攻击者可通过发送以下单个消息使使用protobuf-lite库解析外部消息的Java应用崩溃:
|
|
图3:Protobuf中的恶意消息
此消息将抛出StackOverflowError。问题在于Protobuf解析未知字段的方式。据Protobuf文档:
未知字段是格式良好的协议缓冲区序列化数据,表示解析器无法识别的字段。例如,当旧二进制文件解析带有新字段的新二进制文件发送的数据时,这些新字段在旧二进制文件中成为未知字段。
当此问题与Groups(已弃用但因向后兼容性仍被解析的功能)结合时,会产生爆炸性混合:
- 一个组可包含另一个组。
- 若被攻击模式不包含组,新组将被解析为未知字段。
- 未知组可包含另一个组。
- 转到第2步。
以下是负责解析的代码片段:
|
|
图4:Protobuf中的mergeFrom函数
此漏洞的有趣之处在于对攻击目标有一个前提条件:必须使用Protocol Buffer库的Java lite版本。对目标应用使用的模式无要求。
尽管C++ API官方文档出于安全原因建议丢弃未知字段,但建议在解析消息后进行。此时为时已晚。
虽然Protobuf解析通常对递归攻击具有韧性(使用深度计数器),但Google在开发过程中忘记了此代码路径。我们负责任地向Google披露了此问题,其被分配为CVE-2024-7254。
调查此问题时,我们发现它也适用于其他Protobuf实现,包括Rust-protobuf(Rust中的非官方Protocol buffers实现)。
保护你的代码
随着软件系统日益需要处理JSON、XML和Protocol Buffers等嵌套数据格式,递归处理的风险已增长。我们最初研究主要关注Java项目,但递归处理不可信输入的基本模式超越语言边界,表明存在系统性安全风险。
以下是保护应用的两个具体步骤:
- 审计代码:识别处理不可信数据的递归函数,并查找对嵌套数据格式的解析操作。特别关注处理反序列化的库代码。像我们的CodeQL查询这样的静态分析工具可帮助简化审计过程。
- 实施安全措施:考虑迭代替代方案,为递归操作添加显式深度限制,并在处理前验证输入大小和嵌套深度(如果可能)。
以下是添加深度计数器防止恶意递归的示例:
|
|
图5:添加深度计数器的Fibonacci函数
了解更多
深入探索我们的发现:
- 阅读我们的白皮书《输入驱动递归:持续安全风险》
- 查看我们于2025年2月22日在华盛顿特区首届DistrictCon上的演讲
- 尝试我们用于辅助发现问题递归的CodeQL查询
若喜欢本文,请分享至: Twitter、LinkedIn、GitHub、Mastodon、Hacker News