返回 登录
7

OpenSSL被曝严重安全漏洞,又是C语言惹的祸

OpenSSL官方网站4月7日发布公告,有研究人员发现OpenSSL 1.0.1和1.0.2-beta版本中存在安全漏洞(编号为CVE-2014-0160),可能暴露密钥和私密通信,应该尽快修补,方法是:

  • 升级到最新版本OpenSSL 1.0.1g
  • 无法立即升级的用户可以以-DOPENSSL_NO_HEARTBEATS开关重新编译OpenSSL
  • 1.0.2-beta版本的漏洞将在beta2版本修复

更老版本的OpenSSL(1.0.0和0.9.8等)反而不受影响。

这个漏洞是由安全公司Codenomicon的研究人员和Google安全小组的Neel Mehta相互独立地发现的。漏洞出在OpenSSL对TLS的心跳扩展(RFC6520)的实现代码中,由于漏了一处边界检查,而可能在每次心跳中暴露客户端与服务器通信中的64K内存,这并不是设计错误。

Hacker News网友drv在阅读了漏洞代码后指出,这是一个低级错误。他解释说:

TLS心跳由一个请求包组成,其中包括有效载荷(payload),通信的另一方将读取这个包并发送一个响应,其中包含同样的载荷。在处理心跳请求的代码中,载荷大小是从攻击者可能控制的包中读取的:

  • n2s(p, payload);
  • pl = p;

这里p是指向请求包的指针,payload是载荷的期望长度(16位短整数,也就是每次请求64K)。pl指针指向实际的载荷。

然后响应包是这样构造的:

  • /* Enter response type, length and copy payload */
  • *bp++ = TLS1_HB_RESPONSE;
  • s2n(payload, bp);
  • memcpy(bp, pl, payload);

载荷长度保存在目标包里,然后从源包pl将载荷复制到目标包bp。

bug出在载荷长度没有根据请求包的大小进行检查。因此,memcpy()发送任意载荷长度(最大64K)加上一个小载荷,就能读取请求存储位置之外的任意数据。

drv评述说:

很难相信OpenSSL的代码居然没有对字节流的处理做抽象,如果包用(指针,长度)对来表示,用简单的封装函数复制,就能避免这个漏洞。用C语言的时候,写这种问题代码太容易了,但API设计仔细一点,就会大大增加犯错的难度。

更多技术细节可以参考Heartbleed网站Hacker News上的讨论也极具价值。配置和部署管理工具Squadron创始人Sean Cassidy的博客文章(乌云上有翻译)最为详尽。(感谢新浪微博上的 @我思故我在北京鼓楼 指出)

OpenSSL是互联网上最流行的开源密码库和TLS实现,不仅是诸多Linux和BSD版本操作系统的默认安全通信机制,也是Apache和nginx等Web服务器的加密引擎。这次发现的漏洞是2011年12月引入OpenSSL库中的,2012年3月14日1.0.1正式版发布后,含有漏洞版本的库被广泛使用,因此影响范围极大。如果有攻击者在此时间之内利用这一漏洞侦听获取了许多密钥等信息,可以用来发起进一步的其他攻击。所以,各设备和服务厂商最安全的做法,是假设自己的服务器、设备与服务已经被攻击,采取相应的措施如更新密钥,并通知用户。

你的网站是否存在问题?可以通过以下网址来测试:

当然,结果仅供参考。

无论如何,有网友测试了世界最流行的1000家网站,结果有30%~40%的都有问题。

之前最流行的DNS服务器BIND的代码质量不好,开发者不得不在版本9时大幅重写,现在OpenSSL也问题迭出,互联网基础设施软件看来需要进行一次大规模的安全审计了。

评论