核心问题:保持比特币核心安全

  • bitcoinm
  • 发布于 2026-02-25 19:53
  • 阅读 27

本文深入探讨了比特币核心(Bitcoin Core)项目如何处理安全漏洞,包括其漏洞披露政策、广泛的模糊测试基础设施以及全面的质量保证措施。文章详细阐述了不同严重级别的漏洞分类、私密修复流程、各种模糊测试策略(如差分模糊测试、系统级模糊测试)以及单元测试、功能测试等,旨在确保比特币网络的安全性、完整性和代码质量。

From The Core Issue: a look at how Bitcoin Core handles security vulnerability disclosures, testing for bugs, and patching them.

Bitcoin Core 是一个货币网络的支柱,保护着超过两万亿美元的价值。风险巨大,代码库的很大一部分可能存在高影响力的错误。共识引擎、点对点(p2p)消息处理代码和密码学库是漏洞可能导致盗窃、使网络停滞不前或从根本上破坏系统信任的领域。与受保险和法律补救措施支持的传统金融软件不同,Bitcoin 的安全性完全依赖于其代码质量和维护该质量的流程。

Bitcoin Core 的安全方法并非正式定义,而是一套随着时间推移而不断改进的实践。审查流程变得更加彻底,测试基础设施得到了显著扩展,整个项目对软件更改变得更加保守和慎重。这种较慢的节奏本身就是一种安全措施,通过避免仓促修改来降低引入新错误的风险。

本文探讨了 Bitcoin Core 处理安全的几个关键方面:

  • 处理已发现漏洞的披露政策
  • 寻找错误的广泛 fuzzing 基础设施
  • 在问题到达生产环境之前捕获问题的更广泛测试工具包

这些实践协同工作,虽然并非宏大的统一策略,而是作为项目成熟过程中发展起来的互补防御层。

漏洞披露流程

Bitcoin Core 作为一个软件项目,不为其发布的软件提供自动更新功能,这是为了保护其用户免受开发者的影响,并且所有发布的二进制文件都可以通过可重现构建来验证是否与发布的源代码匹配。节点运营者负责决定运行哪个版本的软件以及何时升级。在安全漏洞的背景下,这带来了严重的困境。修复程序在发布之前需要开源以供审查,但必须延迟完全披露,以给用户合理的更新时间,因为一旦漏洞细节发布,攻击者就可以利用它。

从历史上看,该项目对安全关键漏洞的公开披露,无论是外部报告的还是贡献者发现的,都做得不够。这导致许多用户认为 Bitcoin Core 从来没有错误,这是一种危险且不准确的看法。大约一年半前,受这些问题的驱动,该项目修订并正式化了其安全问题处理方式,形成了一份全面的披露政策和咨询流程。目标是提供更高的透明度,为安全研究人员设定明确的期望(激励他们发现并负责任地披露漏洞),更好地沟通运行过时版本的风险,并在披露后向更广泛的贡献者群体提供安全错误信息,以帮助吸取教训并防止未来的错误。

政策

所有漏洞都应报告至 security@bitcoincore.org(详见 SECURITY.md)。报告后,漏洞将被分配一个严重性类别。我们将漏洞分为四类:

危急(Critical):威胁整个 Bitcoin 网络基本安全和完整性的错误。这些错误可能导致协议层面的币盗窃,在规定发行计划之外创建币,或永久性、网络范围的链分裂。

高(High):对受影响节点或网络有显著影响的错误。这些错误通常在默认配置下可被远程利用,并可能导致广泛破坏。

中(Medium):可能显著降低网络或节点性能或功能的错误,但其范围或可利用性有限。这些错误可能需要特殊条件才能触发,例如非默认设置,或者导致服务降级而非完整的节点故障。

低(Low):难以利用或对节点操作影响较小的错误。它们可能只能在非默认配置下或从本地网络触发,并且不构成立即或广泛的威胁。

低严重性漏洞将在包含修复程序的主要版本发布后2周披露。中等和高严重性漏洞将在最后一个受影响版本**生命周期结束**(End of Life)后2周披露(大约在首次发布包含修复程序的主要版本后一年)。

在发布漏洞详情前两周将进行预先公告。此预先公告将与新主要版本的发布同时进行,并包含已修复漏洞的数量及其严重性级别。

危急错误不在此标准政策考虑范围内,因为它们很可能需要特别程序。此外,一个错误可能根本不被视为漏洞。任何报告的问题也可能被视为严重问题,但不需要禁运。

当漏洞报告给项目时,它首先由 Bitcoin Core 的“安全团队”进行验证和评估,该团队由一小群在发现或修复安全错误方面有记录的长期贡献者组成。项目将漏洞分为四个严重性级别:危急(Critical)(对网络完整性的威胁,如币盗窃或通货膨胀)、高(High)(影响显著,可远程利用)、中(Medium)(性能下降或范围有限)和低(Low)(难以利用且影响较小)。如果确认为严重,则会私下开发并彻底测试修复程序。然后,修复程序像其他任何代码更改一样作为 pull request 提交,但 PR 描述和讨论会模糊修复程序的真实性质。它可能被描述为重构、性能改进或针对潜在问题的强化。这使得修复程序可以进行正常的代码审查,同时保持漏洞细节的私密性。

这种方法涉及真实的权衡,并且确实难以维持平衡。批评者可能会认为它过于家长式,或者它将过多的权力集中在少数在公众之前了解漏洞的开发者手中。这些担忧值得认真考虑,但立即公开披露的替代方案可能是灾难性的。在大多数用户更新之前发布漏洞详情,实际上是为攻击者提供了目标列表(未更新节点)和武器(利用代码)。

模糊测试(Fuzzing)基础设施

fuzzing 是一种测试技术,它向软件提供随机的、格式错误的或意外的输入以寻找错误。基本上,它持续自动生成和变异测试用例,将其输入程序,并观察意外行为,如崩溃、挂起、逻辑错误等。现代 fuzzer 使用进化算法来学习哪些输入触发了有趣的代码路径,然后变异这些输入以更深入地探索程序。这是一种有效的方法,可以发现通过手动测试或代码审查几乎不可能以相同速率发现的边缘案例错误。

由于 fuzzer 为此测试提供输入,开发者无法直接断言预期结果(例如,输入 A 必须产生输出 B)。相反,他们断言软件应保持的一般属性。这非常有价值,因为它允许我们通过测试诸如防止节点崩溃或确保币供应永远不会超出预期通胀等属性来建立对所需行为的更广泛信心。

由于对正确性、健壮性和安全性的关键需求,Bitcoin Core 广泛利用各种方法进行 fuzzing。在 Bitcoin Core 的整个历史中,fuzz 测试工作一直在加强。最早提及非常原始的 fuzzing 可以追溯到 2012 年,而简单的 fuzzing 框架的整合发生在 2016 年,如今已发展成为一个包含 200 多个独立 fuzz 测试的综合框架,覆盖了代码库中关键的单个组件和功能。

Unlike standard unit tests, fuzz tests do not have a defined“通过”点,即你不会运行它们一次就得到一个“通过”或“失败”的状态。因为 fuzzing 是一个持续的随机过程,所以关于结果的任何陈述(当没有发现缺陷时)只能是概率性的。一个 fuzz 测试可能运行 5000 小时而没有发现错误,但接下来的 5000 小时可能会发现一个。因此,为了有效,fuzz 测试必须持续执行。虽然 Bitcoin Core 依赖 Google 的 oss-fuzz 基础设施来运行其 fuzz 测试,但它也大力投资建设自己的基础设施,有几位贡献者使用自己的设置持续进行 fuzzing。例如,Brink 的基础设施每年就为 fuzzing Bitcoin Core 提供了超过 100 万 CPU 小时。

尽管 Bitcoin Core 仓库在组件/功能层面有大量的 fuzz 测试,但几个外部项目采用了不同的 fuzzing 策略。现已退役的 Cryptofuzz 专注于对 libsecp256k1 和其他密码学代码进行差分 fuzzing。对于非密码学代码,例如序列化原语、共识逻辑和钱包描述符解析,项目 bitcoinfuzz 使用了 Bitcoin 特有的差分 fuzzing 方法。一种在系统层面发现错误的全面系统 fuzzing 方法也正在与 Fuzzamoto 一起开发,主要旨在发现代码库不同部分作为完整系统交互时产生的复杂交互引起的错误。

多年来,通过 fuzzing 在已发布的 Bitcoin Core 版本或 pull request 中发现了数百甚至数千个错误(显然并非所有都与安全相关),这凸显了 fuzzing 的有效性和重要性。最近发布的一个高严重性示例是 CVE-2024-35202,这是一个通过 fuzzing 发现的远程可达的崩溃错误,可能使攻击者能够使所有公开可达的节点崩溃。这项发现涉及重构紧凑区块中继逻辑,将其提取到独立的、可测试的模块中,并为其编写 fuzz 测试。

质量保证

虽然上面强调了 fuzzing,但该项目日常还采用了各种额外的测试方法,以进一步最大限度地降低问题进入生产代码的风险。

Bitcoin Core 有数百个单元测试。这些测试旨在验证小的、独立的代码片段(例如单个函数或类)的预期行为。例如,单元测试用于验证工作量证明验证函数的行为。这些测试涉及向函数提供边缘案例输入,并测试其结果输出是否符合预期。

另一方面,功能测试是将一个或多个 Bitcoin Core 实例作为一个整体进行测试,通过使用软件的外部接口(例如 RPCs、p2p 消息)来模拟潜在的真实世界场景,从而在更高的系统级别验证行为。例如,这样的测试可以启动一个小的节点网络,向其中一个节点提交一个交易(例如使用钱包 RPCs),然后验证测试中的所有节点是否最终观察并接受了该交易。Bitcoin Core 历史上缺乏显著的代码模块化,这一特点在多个领域依然存在。因此,该项目更倾向于功能测试方法而非单元测试方法,因为它通常需要提前重构代码以独立隔离目标代码进行测试。

每种测试方法都有其优点和缺点。单元测试通常执行速度快,并且善于指出错误所在,因为它们的范围小且定义明确。然而,根据定义,它们不会检测到仅因多个单元交互而出现的错误。这就是功能测试的优势所在,因为它们对整个系统进行测试,但这会以执行速度为代价,因为它们必须在每次测试运行中设置和拆除节点实例。它们在向开发者指出错误所在方面也差得多。以上述示例来看,如果交易传播测试失败(即交易未传播到所有节点),则更难判断系统的哪些组件存在错误。这可能是 mempool 接受逻辑、网络代码、用于创建交易的 RPCs 或任何其他相关组件中的错误。没有哪种单一方法是最好的,正是所有方法的结合才能打造出最有可能正常运行的软件。

所有测试都在每个 PR 和每次推送到 master 分支时在 CI 中运行。所有单元测试、功能测试和 fuzz 测试(运行先前生成的输入)都在不同的主机操作系统、CPU 架构以及各种错误检测机制(例如 sanitizers(Address, Thread, Undefined, Memory)和 valgrind)的矩阵中运行,以捕获与内存安全和未定义行为相关的常见 C++ 错误类别。

Bitcoin Core 从中本聪发布的原始客户端逐步演变而来,随着时间的推移贡献者来来去去,因此包含大量遗留代码。重构现有代码以简化和隔离它,一直是并且仍然是项目正在进行的大部分工作。无论是 Kernel、新的 p2p 功能、性能改进,还是为引入更多测试做准备,所有这些都需要重构。然而,关于何时以及如何重构的观点存在分歧,因为它可能是一把双刃剑。虽然重构能为相关人员刷新背景、发现错误并通常能实现更多测试,但它也可能令人恐惧去触碰没有人再理解的代码,并且还可能导致引入新错误。功能测试和系统级别的其他测试策略(例如在 fuzzing 部分中提到的 Fuzzamoto)都是降低重构工作风险的方法,因为在该层面的测试几乎不需要前期重构。

在主要版本发布之前,作为一项额外的测试策略,该项目会为用户、开发者和整个社区发布测试指南,以手动测试已有的和新功能。通常鼓励通过典型用法测试软件,作为一项行动号召,以验证个人用户的正常工作流程是否保持功能正常。

  • 原文链接: bitcoinmagazine.com/prin...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
bitcoinm
bitcoinm
江湖只有他的大名,没有他的介绍。