@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:

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的代码如下:

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

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

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

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

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 被用来操作这块内存。然后:

/* 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 的真实长度

代码如下:

    /* 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 上停留的时间。当然拐点是不是如下图所示就在今年业界有些争议,但是拐点已经要来了是没有人再怀疑了。

Don't touch me

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

Don't touch me

移动客户端上网站和 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 这样的做中间件的公司,又会春风得意了吧。

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