@Lenciel

Openssl Heartbleed Bug

连某宝都中招的Heartbleed bug究竟是个什么东西?简单地说就是攻击者可以读最多64KB内存的内容。

读了这64KB能干嘛?用报这个bug的人的话来说:

Without using any privileged information or credentials we were able steal from ourselves the secret keys used for our X.509 certificates, user names and passwords, instant messages, emails and business critical documents and communication.

那么读取64KB内存和获取这么多关键信息究竟有什么关系呢?

The bug

先来看看patch里面的ssl/d1_both.c:

1
2
3
4
5
6
7
int
dtls1_process_heartbeat(SSL *s)
    {
    unsigned char *p = &s->s3->rrec.data[0], *pl;
    unsigned short hbtype;
    unsigned int payload;
    unsigned int padding = 16; /* Use minimum padding */

可以看到,heartbeat里有一个 SSLv3 record的指针,这个record的代码如下:

1
2
3
4
5
6
7
8
9
10
11
typedef struct ssl3_record_st
    {
        int type;               /* type of record */
        unsigned int length;    /* How many bytes available */
        unsigned int off;       /* read/write offset into 'buf' */
        unsigned char *data;    /* pointer to the record data */
        unsigned char *input;   /* where the decode bytes are */
        unsigned char *comp;    /* only used with decompression - malloc()ed */
        unsigned long epoch;    /* epoch number, needed by DTLS1 */
        unsigned char seq_num[8]; /* sequence number, needed by DTLS1 */
    } SSL3_RECORD;

可以看到,每个record有它的typelengthdata,规规矩矩。

回到dtls1_process_heartbeat

1
2
3
4
/* Read type and payload length first */
hbtype = *p++;
n2s(p, payload);
pl = p;

可以看到SSLv3 record的第一个byte就是放这个heartbeattype。 宏n2s 则是从p里面取两个byte放到payload里面,被用来作为payload的长度。 注意这里并没有检查SSLv3 record 实际的长度。

接下来在这个函数里面干了下面这些事情:

1
2
3
4
5
6
7
8
9
unsigned char *buffer, *bp;
int r;

/* Allocate memory for the response, size is 1 byte
 * message type, plus 2 bytes payload length, plus
 * payload, plus padding
 */
buffer = OPENSSL_malloc(1 + 2 + payload + padding);
bp = buffer;

可以看到,用户要多少程序就分配多少,最多可以分配到65535+1+2+16,指针bp被用来操作这块内存。然后:

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

s2nn2s做的操作恢复出来:先拿16个bit的值放到2个byte里面,也就是原来请求的payload的长度。然后把pl里面放的payload(请求者提交的data)拷贝到新分配的bp里面。

看起来是很平常的操作,只不过没有认真的检查用户输入而已,但问题也就在这里了。

Where is the bug

如果用户并没有正在提交声称的那么多个bytes的payload,那么memcpy就会读到同一个process里面SSLv3 record附近的内存内容。

这附近有哪些内容呢?

首先要明白在linux上,内存的动态分配主要是通过sbrk 或者是 mmap。如果内存是通过sbrk分配的,它会使用heap-grows-up规则,泄露出来的东西不会那么多(但是如果是同时并发请求还是有东西会漏)。

在这里,pl因为malloc里面的mmap_threshhold多半是sbrk分配的,但是,那些关键的用户数据,则多半是通过mmap分配内存。于是这些数据就会被攻击者用pl拿到。如果再考虑并发请求,就…

The fix

所以,整个patch里面最主要的fix就是: * 检查是否有长度为0的虚假heartbeat * 检查record的真实长度

代码如下:

1
2
3
4
5
6
7
8
/* Read type and payload length first */
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;

So?

这个bug大概算是影响这么剧烈的bug里面最好明白的一个,所以居然我也看明白了。感受:

  • 为了可扩展性引入了复杂度,经常都会带来恶梦
  • 用户的输入,无论如何都不能相信,一定要check
  • C语言的确是大牛小牛都会踩到坑啊

应用开发能火多久?

不管是从日常生活里面的观察和感受,还是查看统计数据,都很容易发现人们在移动设备上停留的时间已经逐渐超过了在PC上停留的时间。当然拐点是不是如下图所示就在今年业界有些争议,但是拐点已经要来了是没有人再怀疑了。

mobile vs desktop

而移动设备取代PC机成为最主要的入口之后,就意味着谁占领了移动设备,谁就拥有未来。同样不管是从切身体会还是数据都不难知道,和PC上各种网站(包括各种浏览器+插件提供的服务)占据统治地位不同,在移动平台上,应用程序获得了全面的胜利。

mobile apps vs website

移动客户端上网站和App相比所处的劣势会越来越严重。无论是我们自己公司还是行业内其他人,都知道做移动互联网就是要做应用才行。所以你看手机网页上和游戏里,各种弹窗、各种广告、各种骚扰短信,都是指向某个应用的下载链接。

这也是为什么那么多财大气粗的实体官方的网站在移动客户端上看起来就跟狗屎一样:他们的老板们的逻辑和开发者一样,那些网站没什么人在手机上看,只要我的应用、我的微信公众号看起来好就行了。

这么一来,最好的开发和设计人员都去做应用了,大量的钱也都烧在应用推广上去了。

最终我们手机上的浏览器几乎被闲置了,打开它主要是为了:

  • 搜索
  • 下载一个应用
  • 从一些sns程序里面点开某个链接

而且,就第三项用处来看,越来越多的sns程序,比如微信,微博等,都是直接在自己内嵌的webview里面打开链接,根本不会使用系统安装的浏览器。

从长远看这种应用一骑绝尘网站无人问津的状况还是对整个生态有很大的风险:

  • 看看有线电视发展到后面是什么样:大寡头们有更好的设备,更强大的制作班底,更多的明星,控制了整个行业。这种状况下,用户打开电视能看到什么样的节目几乎没得选,小团队要靠创新来出头也变得非常困难
  • 应用主要在少数几个主流应用商店发行,比如Google和Apple的。意味着Google和Apple不仅仅要抽水,还要对应用内容,应用怎么推广,甚至应用用什么语言开发进行控制。

比如Apple。在PhoneGap最开始出来的时候,所有用这个hybrid framework开发的应用都被Apple强制封杀,理由居然是“不使用native library开发的应用不像一个应用”。再比如最近,它直接发了一个policy就让所有跟BT币有关的应用下架了。

感觉在移动平台上会上演类似PC上的历史,首先会有Apple和Google这样提供OS的企业通过应用这个渠道来做成大山头。然后生态系统对其他参与者越来越艰辛,于是会有很多企业尝试破冰,比如通过开发功能强大的浏览器形成新的渠道,来脱离寡头们的控制。最终,移动平台上的浏览器肯定也会像现在PC上的浏览器一样强大,成为各种服务的入口。

而且,这个过程肯定会比PC上要快很多。首先,大家都已经被教育过一次了,大腾讯大百度们做自己的浏览器不是做着玩的;更重要的是,Web发展到今天这个地步,开放性已经有些脱离技术,变成了社会生活中的一种意识形态。一旦移动网络资费和速度真正给力,肯定会有揭竿而起的。即使大如Google和Apple,也很难再像当年MS那样hold住全场了。那个时候,很多Myriad这样的做中间件的公司,又会春风得意了吧。

当然,最近这些年肯定还是应用开发热火的时候,小伙伴们,过时不候,放手干吧。