当前位置:首页 > 探索

亚瑟漏洞

2014年4月,亚瑟漏洞OpenSSL 的亚瑟漏洞代码仓库里躺着一段存在了近两年的致命缺陷。Heartbleed,亚瑟漏洞中文译名“心脏出血”。亚瑟漏洞这个名字起得精准——它确实像一颗心脏在往外泵血,亚瑟漏洞只不过泵出去的亚瑟漏洞是服务器的私钥、用户密码、亚瑟漏洞会话令牌,亚瑟漏洞一切恰好落在内存相邻位置的亚瑟漏洞东西。

问题出在 TLS 心跳扩展的亚瑟漏洞实现上。RFC 6520 定义了这个扩展:客户端发送一个心跳请求,亚瑟漏洞附带任意数据和一个长度字段,亚瑟漏洞服务端把数据原样回传。亚瑟漏洞逻辑够简单吧?亚瑟漏洞OpenSSL 的开发者写这段代码时,忘了校验那个长度字段是亚瑟漏洞否真的和实际数据匹配。

攻击者发一个心跳包,声称“我带了 65535 字节的数据”,实际只发 1 字节。服务端不检查,老老实实从内存里读 65535 字节返回。多出来的 65534 字节是什么?可能是上一个请求的密码,可能是私钥片段,可能是任何东西。每次最多泄露 64KB,反复请求就能把内存翻个底朝天。

我第一次读到这段代码时,盯着那几行看了很久。修复补丁只有两行——加一个边界检查。两行代码,两年时间,全球三分之二的 HTTPS 服务器暴露在风险中。2014 年 4 月 7 日漏洞公开,加拿大税务局紧急下线了报税系统,Stack Overflow 建议用户立刻修改密码,CloudFlare 发了一篇事后分析说他们早在漏洞公开前就收到了通知并完成了修复。普通用户呢?大多数人连 HTTPS 是什么都说不清。

这事有意思的地方在于它的讽刺性。OpenSSL 是互联网安全的地基,几乎所有人的加密通信都靠它。但它的开发团队当时只有几个全职人员,大部分贡献者是志愿者。一个支撑全球金融、医疗、政务系统的关键组件,维护力量还不如一个中型互联网公司的运维团队。Heartbleed 曝光后,Linux 基金会才成立了 Core Infrastructure Initiative,专门给这类“要命但没钱”的开源项目输血。

再说回漏洞本身。它为什么能藏那么久?因为心跳扩展在正常通信中很少被用到。大多数 TLS 连接根本不会触发这段代码。测试覆盖不到,代码审查也没盯住。这不是什么高深的逻辑错误,就是一个典型的 C 语言内存安全问题——信任了外部输入的长度字段,没有做边界验证。写 C 的人都知道这个坑,但知道和做到之间隔着一整个太平洋。

我后来在本地搭了个环境复现过。用 Python 的 socket 库构造一个畸形心跳包,发出去,几毫秒后收到回复。Wireshark 里看到返回的数据长度远超我发送的,里面混着之前请求留下的 Cookie 字符串。那一刻的感觉很怪——你明明在攻击自己的测试机,但看着那些本不该出现的数据从网络那头流回来,还是会后背发凉。

Heartbleed 不是第一个,也不是最后一个。它只是把开源基础设施的脆弱性推到了聚光灯下。我们每天用的加密通信,底下跑着的那堆代码,可能正由某个凌晨三点还在改 bug 的志愿者维护着。他们值得更好的待遇,但现实是,直到出了大事,钱和注意力才会来。

那两行修复补丁现在躺在 OpenSSL 的 git 历史里,commit message 写得平平无奇。但每次我配置服务器 SSL 的时候,都会想起它。互联网的安全,有时候就悬在这么几行代码上。

分享到: