心脏出血波及比特币客户端时:2014年OpenSSL漏洞事件复盘 图 1
心脏出血波及比特币客户端时:2014年OpenSSL漏洞事件复盘 · 图 1

钱包没病,钱包用的库病了

2014年4月上旬,加密界披露了OpenSSL的心脏出血漏洞(编号CVE-2014-0160):TLS心跳处理缺少边界检查,远程攻击者可借此读取服务进程最多六十四千字节的内存内容。比特币软件本身没有同类缺陷,但比特币核心项目当年发布公告承认,0.9.0及更早版本软件链接的OpenSSL版本包含该漏洞,因此这些版本的发行包同样处于风险之中,官方建议立即升级到链接了修复版OpenSSL 1.0.1g的0.9.1。使用官方Windows安装包的普通用户,风险场景被描述为:若钱包未设口令,在浏览网页时点开一个比特币支付请求链接,理论上钱包文件可能被泄露。命令行用户的暴露面则是另一种:启用了RPC的SSL选项并把可接受RPC的主机范围放开的节点,来自白名单地址的攻击者很可能读到RPC密码与最近一次RPC请求内容,私钥被顺带读走的概率较低但并非零。

处置节奏

官方公告给出的动作很干脆:立刻升级到0.9.1;自行编译或使用发行版源的Linux用户更新系统OpenSSL;安卓4.1.1系统本身带病,尽量升级到4.1.2,使用比特币安卓钱包的用户应升级到3.45版以上。0.9.1发布说明则显示,这个版本本身就是一个纯安全更新,距上一个大版本仅数周,同时顺带修复了另一个影响椭圆曲线随机数的侧信道问题。一个开源项目能在漏洞公开几天内完成重新构建、签名和分发,这个响应速度后来成为比特币核心安全流程的基准线。

为什么私钥暴露面取决于你没用过的那些代码

比特币的密码学是比特币核心的代码,但TLS连接、网络请求、图形界面的加密交互几乎全部委托给通用加密库。用户保护自己的私钥时盯着助记词和软件版本,常常漏掉依赖库这一层:你的币由一行你从未读过、由另一个项目的另一批人维护的代码守护。心脏出血事件把这条缝隙照亮了——漏洞不在任何比特币逻辑里,却能撬开装私钥的进程内存。此后多年,围绕SOCKS代理组件缓冲区溢出、压缩库、UPnP组件的多个比特币核心安全公告,走的都是同一条剧本:上游组件带病,比特币核心跟进发版。

给今天的用户三条防御要点

第一,把钱包软件升级当作安全事件而不是功能事件处理:官方的紧急版本哪怕界面毫无变化也值得立刻安装,当年漏洞公告列表里相当比例的修复版本就是这种静默安全版。第二,优先选择官方渠道的发行包并使用提供的签名文件核验,这决定了你拿到的OpenSSL是不是被重新编译加固过的版本,还是被中间人换过的旧库。第三,理解每一台运行钱包软件的设备都在替所有依赖库还债:老旧操作系统、多年不更新的共享库与钱包进程共存时,最薄弱一环决定私钥的生死。事件本身的细节以当年公告与发布说明为准,本文不构成投资建议,只提供防御性知识。

把教训写进今天的软件供应链习惯

心脏出血之后十年里,这类剧本反复重演:2017年,恶意SOCKS服务器可触发部分节点的缓冲区溢出隐患,修复落在0.15.1;2015年,miniupnp组件的缺陷要求升级到0.11.1;更早还有压缩库与解析库的各处修补。逐条看都是小概率窄暴露,连起来看则是一个结构性事实:钱包软件永远比它调用的库先老去。对应到今天的个人实践,是把三件小事固化为习惯——升级通知订阅官方公告页而不是靠应用商店提醒;核对发行包附带的校验文件与签名,确认二进制与源码构建可对应;把还在运行旧钱包进程的旧机器当作已泄露候选来处置,而不是等到出事。私钥安全从来不是钱包核心代码一个模块的事,它是一条从助记词、操作系统、加密库到网络路径的完整链条,链条的强度由最弱一环说了算。2014年那次,最弱的一环在所有人的硬盘里,却不在任何人的清单上。