Bitcoin Core 项目的安全措施

作者:Niklas Gögge

来源:https://bitcoinmagazine.com/print/the-core-issue-keeping-bitcoin-core-secure

Bitcoin Core 软件作为比特币这个货币网络的股价,保护着超过 2 万亿美元的价值。风险巨大,并且代码库的许多部分都可能藏着高危漏洞。从共识引擎、处理点对点网络(P2P)消息的代码到密码学库,都有可能存在允许盗窃、使网络瘫痪或者在根本上破坏人们对比特币的信任的漏洞。传统的金融软件可以依靠保险和法律救济,比特币的安全性却完全依赖于加入网络的计算机上运行的代码的质量,以及维护其质量的流程。

Bitcoin Core 维护安全性的流程没有成文的规定,更多是一系列不断变化的习惯,而这些习惯在过去已经得到许多优化。代码审核流程已经变得更加彻底,测试架构也已经大大扩展;在面对软件变更时,整个项目也变得更加保守、谨慎。这种比较慢的节奏本身就是一种安全措施,可以降低在匆忙的修改中引入新 bug 的风险。

本文检视了 Bitcoin Core 获取安全性的几个关键侧面:

  • 处理漏洞披露的披露策略
  • 寻找 bug 的广泛模糊测试基础设施
  • 广泛的测试工具,在漏洞进入生产环境之前捕捉到它们

这些实践是彼此交织的,虽然没有一个统一的策略,但它们是互补的防御层,是在 Bitcoin Core 项目成熟过程中发展出来的。

漏洞披露流程

作为一个软件项目,Bitcoin Core 并不为它发行的软件提供自动更新功能,这是软件的用户对抗软件开发者的一种保护措施;并且,所有发布的二进制文件(可执行文件)都可以通过 “可复现编译” 来验证与源代码一致。节点运营者自己决定要使用哪个版本的软件、什么时候升级。而在考虑安全漏洞时,这就形成了一个严重的三难问题。漏洞的修复需要开放源代码,以供代码审核(在进入发行版本以前);但完整的漏洞披露又必须推迟,以允许用户有充足的时间来升级软件;同时,一旦漏洞的细节公开,攻击者们就可以利用它。

在历史上,这个项目的致命性安全漏洞的公开披露,不论是由外部开发者报告,还是由贡献者们发现,都是不充分的。这就导致了一种情形:许多用户都以为 Bitcoin Core 是从来没有漏洞(bug)的;这种看法既不准确,又危险。大约一年半以前,因为这些问题,Bitcoin Core 项目提炼了其处理安全问题的方法,并形成了一份全面的披露策略和顾问流程。披露策略的目标是提供更多的透明度、为安全研究员们设置更清晰的预期(为他们提供寻找和尽责地披露漏洞的一种激励) 、更好地告知运行过时版本的风险,并在披露之后,向广大的贡献者团体公开安全 bug,帮助他们从中学习、防止未来出现同样的错误。

策略

所有的漏洞都应该报告到 security@bitcoincore.org(详情见 SECURITY.md)。在报告之后,漏洞会被确定一个严重等级。我们区分四个等级的漏洞:

致命:漏洞会威胁到整个比特币网络的基本安全性和完整性。包括允许在协议层面盗窃钱币、在规定的发行计划之外增发钱币、或者造成永续的网络层面的区块链分裂的 bug 。

高危:对受影响的节点或网络有显著影响的 bug 。包括一般来说在默认的节点配置下可以远程爆破的漏洞,以及可以导致崩溃蔓延的漏洞。

中等:可以显著恶化网络或者节点的性能或功能的 bug,但在范围或者可利用性上比较有限。可能腰围特殊的触发条件,比如非默认的节点配置,或者结果是服务的恶化而非节点崩溃。

低危:难以利用、或者对节点的操作只有微小影响的 bug 。可能智能在非默认的配置下触发,或仅能在内网触发,并不会理解带来威胁,也不会散播风险。

低危安全漏洞将在包含修复措施的主要版本发行的 2 周后披露。中等高危的安全漏洞将在最后一个受影响的版本的设计寿命结束的两周以后披露(大致是包含修复措施的第一个主要版本发布的一年后)。

披露漏洞细节的两周之前,会发布一个预先声明。这个预先声明将跟新的主要版本的发行同步,并公开已修复的漏洞的数量及其危险等级。

致命漏洞不在标准披露策略的考虑范围内,因为可能需要采取紧急措施来处理它们。此外,一个 bug 也可能不会被认为是一个漏洞。任何得到报告的问题都可能被视为是严重的,但并不需要禁令。

当一项漏洞被报告给 Bitcoin Core 项目时,它会由 Bitcoin Core 的一个 “安全团队” 先行验证和评估;这个安全团队是一小群长期贡献者,在发现或修复安全漏洞上有良好的记录。Bitcoin Core 项目将漏洞分为四个等级:致命(威胁整个网络的完整性,比如盗窃钱币或通胀)、高危(巨大影响、可以远程利用)、中等(之时性能降级或者范围有限)以及低危(难以利用而且影响有限)。只要确定是严重的漏洞,修复措施会在私下开发并进行彻底的测试。然后,修复措施会作为一个 PR 提交,就像其它代码变更一样,但 PR 的介绍和讨论会模糊修复措施的真正性质。它可能会被说成是重构、性能提升或者对潜在问题的加固措施。这使得修复措施能走完正常的代码审核流程,同时让漏洞的细节保持低调。

这种方法当然也有它的确定,而且非常难以保持平衡。批评意见可能会说这是家长制,而且在少数比公众提前知晓漏洞的开发者手上集中了太多权力。这些担忧值得严肃的考虑,但相反的做法 —— 立即向公众披露 —— 也可能有灾难性的后果。在绝大部分用户升级软件之前发布漏洞的细节,等于是给攻击者同时提供了目标清单(未升级的节点)和武器(可以爆破的代码)。

模糊测试基础设施

“模糊测试(Fuzzing)” 是一种测试技术,向软件输入随机化的、格式混乱的或者意料之外的输入,以寻找 bug 。基本上,它需要自动化地连续生成测试场景并让测试场景突变,然后将它们喂给程序,然后观察程序的不符合预期的动作,比如崩溃、挂起、逻辑 bug,等等。最新的模糊测试使用演化算法来了解哪个输出触发了产生意外动作的代码路径、然后让这些输入变异,以深入了解程序。这是一种有效的方法,可以发现手动测试和代码审核几乎无法发现的边缘情形 bug (至少后者无法达到相同的速度)。

因为模糊测试器会为测试提供输入,开发者无法直接断言预期结果(比如,提供输入 A 就一定会产生输出 B)。相反,他们断言的是软件(在面临各种输入时)应当保持的整体属性。这是非常有价值的,因为它让我们可以通过测试属性(比如节点不要崩溃、确保货币供给量不要超过预期数值),对软件的动作建立起更广泛的信心。

因为对正确性、健壮性和安全性的极致需求,Bitcoin Core 广泛使用了各种方法的模糊测试。在 Bitcoin Core 的整个历史中,模糊测试一直在紧锣密鼓地进行。最早提到(非常原始的)模糊测试的时间可以追溯到 2012 年,而最早集成一个简单的模糊测试框架的时间是在 2016 年,并且它逐渐演变成了今天的综合性框架,包含超过 200 项单独的模糊测试,覆盖了代码库的最关键的组件和函数。

与标准的单元测试(unit test)不同,模糊测试并没有一个定义好的 “通过” 状态,也即,你没办法只运行一次测试,就得到一个 “通过” 或者 “失败” 的结果。因为模糊测试是一个持续的随机过程,任何对结果的声明(在没有发现错误的时候)都可能仅仅只是概率性的。一个模糊测试可能运行了 5000 各小时还没有发现任何 bug ,但在下一个 5000 小时中就会发现一个。因此,为了真正有效,模糊测试必须不断运行。虽然 Bitcoin Core 学习了谷歌的 oss-fuzz 基础设施来运行自己的模糊测试,它也投入了大量资源来开发自己的基础设施,多位贡献者一直在自己的设备上运行模糊测试。兹举一例,Brink 的基础设施独自提供了每年超过 100 万 CPU 小时来运行 Bitcoin Core 的模糊测试。

虽然 Bitcoin Core 代码库在 组件/函数 层面已经有了不计其数的模糊测试,多个外部项目还有自己的模糊测试策略。Cryptofuzz 曾经专注于 libsecp256k1 与其它密码学代码的差分模糊测试(现已退休)。对于非密码学的代码,比如序列化原语、共识逻辑和钱包描述符解析,bitcoinfuzz 使用了一种比特币专注的差分模糊测试方法。Fuzzamoto 还在开发一种全系统的模糊测试方法,以在系统层面发现 bug ,主要目标是,在代码库是可以作为一个完整的系统来交互时,发现因为代码库的不同部分的复杂交互而产生的 bug 。

在过去这些年,由模糊测试发现的 Bitcoin Core 已发行版本(或 PR)中的 bug ,没有几千个也有几百各(当然,并非所有 bug 都与安全性相关),这充分说明了模糊测试的有效性和重要性。一个近期公开的高危漏洞是 CVE-2024-35202 ,它是一个远程可利用的崩溃 bug ,让攻击者可以崩溃所有公开可触及的节点,也是用通过模糊测试发现的。这个发现涉及到了重构致密区块转发的逻辑、抽取它到隔离的可测试的模块中,并为它编写一项模糊测试。

质量保证

虽然前面强调了模糊测试,Bitcoin Core 还在日常开发中应用了其它多种测试方法,以进一步降低问题进入生产环境的风险。

Bitcoin Core 有几百个单元测试。这些测试设计成验证小的、孤立的代码片段(比如单个函数或者类)的动作。举个例子,单元测试可以用来验证工作量证明验证函数的动作。这些测试涉及提供边缘情形的输入给函数,然后测试函数的输出符合预期。

功能测试(funcional test),则恰好相反,测试的是作为整体的一个或多个 Bitcoin Core 实例,在更高的系统侧面上验证它的动作;它利用的是软件的外部接口(例如,PRC、P2P 消息),以模拟可能的真实世界场景。这样的一个测试可能会,比如说,建立起一个小规模的节点网络、向其中一个节点提交一笔交易(例如,使用钱包 RPC),然后验证测试中的所有节点是不是最终都会观察到并接纳这笔交易。Bitcoin Core 历来缺乏重要的代码模块化,这个特点在多个领域至今存在。结果是,它从功能测试方法中知道的信息比单元测试更多,因为单元测试需要先重构代码,以隔离目标代码、独立进行测试。

每一种测试方法都有自己的长处和缺点。单元测试通常可以快速运行,而且能够精准地定位 bug 的为之,因为测试范围较小,而且有良好的定义。但是,顺理成章的是,它们无法发现只会在多个单元的交互中显现的 bug 。这就是功能测试有用的地方 —— 它将整个系统都置于测试中,而代价就是运行的速度,因为每次运行测试它们都需要建立和关停一些节点实例。在帮助开发者定位 bug 上,功能测试的效果也更差。就说上面这个例子吧,如果交易传播测试失败了(也就是交易没有传播到所有节点),很难说到底是系统的哪个组件出了问题。也许是交易池采纳逻辑有 bug,也可能是联网代码、用来创建交易的RPC,或者相关的任何一个组件。没有哪一种方法是最好的,所有方法的结合,才有望打造出以最高概率正确运行的软件。

对于每一个 PR 和每一次推送到代码库主分支的变更,都会在连续集成系统(CI)运行所有测试。所有单元测试、功能测试和模糊测试(使用以往生成的输入运行)都会在多种主机操作系统、CPU 架构矩阵上运行;此外,还会使用多种 bug 侦测机制,比如 sanitizer(地址、线程、未定义、内存)和 valgrind 来捕捉常见的与内存安全和未定义动作有关的 C++ bug 类型。

Bitcoin Core 最初是由中本聪发布的客户端,在整个开发过程中,贡献者们来来去去,也正因此,它包含了许多老式代码。重构现有的代码以简化它或者隔离它,一直是并且仍将是要在这个项目中完成的工作的重头。不论是内核、一种新的 P2P 特性、性能提升或为加入更多测试而作准备,全都要求重构。只不过,关于何时重构、如何重构,总有观点分歧,因为重构是把双刃剑。虽然重构能够为相关的代码更新语境、发现 bug 并(通常来说)可以追加更多测试,它也可能接触那些完全没人理解的代码,还可能会导致引入新的 bug,所以让人生畏。在系统层面的功能测试和其它测试策略(比如前面关于模糊测试的部分提到的 Fuzzamoto 项目),都是降低重构风险的方法,至少,在这个层面上测试,几乎不需要提前重构代码。

还有一个测试策略是,在主要版本发布以前,Bitcoin Core 会公开一个测试指南,让用户、开发者和整个社区能够手动测试已有的特性和新特性。这是一种行动号召,鼓励人们使用普遍的用法来测试软件,以验证个人用户的正常工作流依然有效。

(完)

Niklas Gögge2026-03-13
https://www.btcstudy.org/2026/03/13/the-core-issue-keeping-bitcoin-core-secure/

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇