历史上的重大软件BUG启示录 第2篇---心脏滴血

版权声明:本文为博主原创文章,未经博主允许不得转载。联系邮箱:[email protected] https://blog.csdn.net/zhzht19861011/article/details/52419159


(图片来源于网络)

      OpenSSL"心脏滴血"漏洞于2014年4月7号被曝光,“黑客只要对存在这一漏洞的网站发起攻击,每次读取服务器内存中64K数据,不断的迭代获取,就能获取程序源码、用户http原始请求、用户cookie甚至明文帐号密码等敏感信息”。全球三分之一的以"https"开头的网站受到影响,包括大批网银、购物网站、电子邮件等。

      引起这个漏洞的原因是服务器没有对客户端发来的心跳数据做严格检测。

      客户端和服务器正式通讯前,先向服务器发送一个心跳信号包来查询服务器是否在线。发送的心跳信号包中包含信息的长度和信息文本,如果服务器在线,就将收到的信息回送给客户端。比如客户端向服务器发送心跳包,告诉服务器我发送了5字节信息,信息内容是“Hello”,然后服务器就会向客户端回送“Hello”。

      或许你会疑惑,这样做没问题啊!是的,正常情况下没问题,但是服务器在回送的过程中,并没有验证信息的实际字节个数,而是直接根据客户端发来的信息长度字段来决定向客户端回送多少字节的信息。这样就带来了问题,比如客户端向服务器发送心跳包,告诉服务器我发送了64KB信息,信息内容是“”,你没看错,这也不是误写,内容就是为空!但服务器却没有验证到底有没有信息内容,也没有验证信息内容的字节数和信息长度字段是否吻合!服务器仍然使用memcpy函数将从指向保存信息内容的地址处开始的64K内存信息全部复制出来,然后回送给客户端。看,服务器内存中的数据就这样被送到了客户端的机器上!

      修复代码中最重要的一部分如下所示:

if (1 + 2 + 16 > s->s3->rrec.length)
     return 0; /* silently discard */
hbtype = *p++;  
n2s(p, payload); 
if (1 + 2 + payload + 16 >s->s3->rrec.length)
     return 0; /* silently discard per RFC 6520 sec. 4 */
pl = p;

      主要做了两件事:第1行代码将信息文本为空的情况排除,第5行代码将信息长度大于信息文本长度的情况排除。

      写《深入理解计算机系统》的Bryant曾说过:任何到外部环境的接口都应该是“防弹的”!OpenSSL代码显然忽视了这一点。       

      一个未严格检测的入口参数,却置成千上万的服务器于危险之中。

猜你喜欢

转载自blog.csdn.net/zhzht19861011/article/details/52419159