说说最近 Google Safe Browsing 引发页面加载阻塞的问题
作者: 发布于:

背景

一个礼拜前,在退款维权的业务中,发现这样一个问题: 在某些 Firefox 浏览器中,表单的 butterfly 加载阻塞导致功能异常了。

一开始,我们以为是即将发布的修改点导致的问题。

但再三确认本次的修改点后,确定只是改了文案啊! 这……

因此,我们首先怀疑是否线上已经有问题? 经过测试发现,果然,确实是个线上问题。

经过并不算麻烦的自测后,发现问题还不小:

影响范围:所有 Firefox 版本。
(注意:Firefox 部分修复,但版本为 30.00+ 的官方版 Firefox 浏览器未完全解决,原因是该版本携带有版本为 1.2.3 的“附加组件管理器”扩展程序)

Chrome 在一个月前也发现过类似问题,不过近期没有类似案例,可能已经在 35 版本中修复。

隐藏在 Firefox 中的 Google Safe Browsing 是如何工作的?

印象中,页面在 Firefox 中请求一个 JS 文件的过程,是这样的

图中看到了三个步骤:

  1. 页面向 Firefox 发起一个 JS 的请求;
  1. Firefox 判断是否为 reload 请求或者已在缓冲,如果是则直接读缓存,返回 JS 文件给页面使用;如果为 false 则执行步骤 3;
  1. 向阿里 CDN 请求,获取到 JS 文件,返回 JS 文件给页面使用,并且写入缓冲;
    看起来没什么问题,太符合我们的认知了。

直到有一天,发现页面因为 JS 加载阻塞导致页面功能严重受影响。而且怎么强刷、清理缓存,都无果。

原来,页面在 Firefox 中请求一个 JS 文件的真正过程,是这样的。

这里演示下 Google 服务正常和异常两种情况:

一. Google 服务正常时:

二. Google 服务不正常时:

图中可以看到多了个本地哈希碰撞和向 Google 服务发送检测的过程,更多步骤描述如下:

  1. CDN 返回 JS 给 Firefox 后,Firefox 先在本地 Safe Browsing 哈希库中执行哈希碰撞;
  1. 碰撞结果为不通过的话,会向 Google 服务器(safebrowsing.google.com:443)发起检测通知,并进入等待状态;
  1. 此时,页面的直观感受就是 JS 没有请求到,功能异常;
  1. 并且,如果再次请求同一个 JS 文件,首先会查看 Safe Browsing 等待队列;
  1. 如果已在 Safe Browsing 等待队列中,则什么都不做。没错!什么都不做!(这就解释了,为什么强刷,甚至清理缓存后的强刷,都毫无作用)

似乎已经定位到了,问题了

第一: Firefox 把我们的 JS 判定为可疑文件(也就是哈希碰撞结果为可疑);
第二: Google 服务被墙了

另外:

Safe Browsing 会对所有静态资源执行哈希碰撞;
哈希碰撞,只针对静态资源的名称;(也就是说与 JS 文件的文件内容无关)。
于是,向 Firefox 的同学请求帮助

无辜的受害者: “为什么 Firefox 把我们的 JS 认定为可疑文件?”

Firefox 的解释是: “我也不知道为什么啊!”;

Firefox:“因为 Firefox 浏览器会从 Google 下来一份 Safe Browsing 哈希库,这个哈希库会对所有静态资源请求执行哈希碰撞。 因此,具体算法,Firefox 方面,其实也是不知道的呢。”

无辜的受害者: “哦! 原来是被检查请求阻塞了呢?那要不你们添加一个阻塞行为的监控吧?”

Firefox:“对啊,对啊,在最新版本:30.00 中,我们加了阻塞情况下,只进行本地检查的处理了, 你下载最新的版本就可以了。”

几个小时后……

无辜的受害者:“我下更新到最新版本了,可还是不行呢?”

Firefox:“要怪就怪 GFW 吧,为了伪造成是 Google 自己服务器的问题,而不是国内封锁,现在 GFW 对 Google 的封锁采用 hold 连接,不释放,不重置,一直不返回数据,造成现在火狐以为连接一直在等待数据。”

无辜的受害人:“好的谢谢,保持联系”。

因此,又抛出了两个新的问题:

为什么升级了 Firefox 还是在本地哈希碰撞中被 fail 了?
为什么 Firefox 已经添加了防阻塞处理,结果却还是被阻塞了?
问题的答案:

Firefox 升级是升级了,但是本地哈希库,并没有被更新(因为 Google 服务调不到啊~); 自测发现哈希库被保存在 Firefox 的应用程序中,而非个人配置目录中;
Firefox 添加了阻塞处理没错,但是 GFW 似乎做了一件奇葩的事情: GFW 对 Google 的封锁采用 hold 连接,不释放,不重置,一直不返回数据,造成现在火狐以为连接一直在等待数据;看来是 Firefox 的解决方案不够彻底啊;
最后的问题变成:

Firefox 没有处理到 GFW 对 Google 服务请求采取 hold 连接的情况;
没有得到能够让用户一次操作(如更新插件,更新浏览器)就能解决的方案,难以形成终极解决方案。

以后怎么办

首先:考虑到网络安全敏感问题,能拿到 Google Safe Browsing 哈希库算法的可能性几乎不可能;尝试通过 hash 算法扫描本地代码库的思路不太可行。

看来:还是得靠 Firefox 那边,能够自己修复这个问题。 后续我们会持续跟进这一类的问题,并就这个问题跟 Firefox 方面保持反馈和测试结果的同步。

临时解决方案

JS 的出异常的解决方案是: 修改静态资源文件的文件名(注意如果是 JS 文件必须修改非参数部分如: g.tbcdn.cn/aaa/bbb/ccc/ddd-min.js 部分,而非 t=xxxxx.js)

另外:

由于 Google Safe Browsing 检测的是所有静态资源,目前已发现的出现问题的资源文件类型和解决方案是:

TypeSolution
AJAX修改请求名
JS、CSS修改目录时间戳
页面请求修改参数名或添加时间戳

最后

说多了都是泪, 庆幸本次问题基本只在 Firefox 中被发现,并且没有大面积爆发。(应该多向 Chrome 团队快速精准解决问题的作风学习呢~)

以后还是需要主动关注浏览器生态圈的动态,避免类似情况发生,以及对某些风险做好提前预防工作, 保证每一个使用 Firefox 的朋友有一个良好用户体验。

特别感谢 Firefox 的同学积极的帮助!后续还会继续骚扰!

题图:https://unsplash.com/photos/tLxV4GR1skc By @Thomas Hafeneth