WWDC 中提到的浏览器 Fingerprinting

苹果在 WWDC 2018 发布 macOS Mojave 的时候,介绍了 Safari 现在具备了防御 fingerprinting 技术的能力。这个技术和指纹有什么关系,是用来做什么的,又有多值得普通用户担心呢?让我们从它的来龙去脉说起吧 😃

何谓 Fingerprinting

Fingerprinting 的本意是指纹采集,那么它在 Web 浏览器的语境下指代的是什么呢?来看看它所要解决的问题吧。

在人类社会里,要想唯一标识一个人,姓名和身份证号足够吗?一般情况下,使用这些基于社会制度的约定并没有问题,但很多时候这是不够的:

  • 姓名可以随意更换,还有大量重名。
  • 身份证可能被伪造或冒用。
  • 极端情况既没有姓名也没有身份证。

在 Web 中,如果把浏览器类比为人,那么我们就有了非常对应的类比:User Agent 相当于姓名,而 cookie 就好比身份证。比如,Chrome 浏览器的 User Agent 里会用形如 Chrome/66.0.3359.181 的字段标明自己的名称和版本,而对于重名(很多用户使用同个版本的 Chrome)的情况,我们还可以通过 cookie 来唯一标识用户。是不是很直观呢?但上面的三个问题在 Web 里我们照样逃不掉:

  • User Agent 就像姓名,在现代浏览器里基本可以随意更换。
  • Cookie 就像身份证。只要知道别人的身份证号(cookie 值),就可以把身份伪装成别人。
  • 对于匿名或恶意的访问,往往上面两者获得的信息都是无效的。

这就暴露出了这样假设「每个人都是好人」的约定,其固有的脆弱性。故而我们需要发展技术,来在生物学上唯一标识一个人,以及,在技术层面上唯一标识一个浏览器。对于前者,我们有指纹、虹膜、DNA 等识别技术可供使用。类似地,对于后者,我们所用到的技术就是下面所要介绍的 fingerprinting 了。

Web Fingerprinting 技术速览

某种程度上,fingerprinting 属于特别的奇技淫巧——完全不按照一个东西原本的用途来使用它,而是开发出了新用途:

  • 指纹原本是用来防滑的,我们拿来鉴定一个人。
  • 虹膜原本是用来调节瞳孔大小的,我们拿来鉴定一个人。
  • DNA 原本是用来送给妹子制造后代的,我们拿来鉴定一个人。

在程序员的世界,这样的奇技淫巧就更多了。要想唯一标识出一个运行在某个 OS 平台上的浏览器,你能想到多少种方式呢?在这个方面,只要看看开源的 fingerprintjs2 库,你就能感受到程序员们为了追踪用户能想出多么骚的操作。这些操作所涉及的维度主要包括但不限于:

  • IP 地址
  • JavaScript 行为
  • Flash 与 Java 插件
  • 字体
  • Canvas
  • WebGL

下面我们逐一对这些维度做一些简要的介绍。

IP 地址

最简单的 IP 地址收集并不需要客户端的配合,而主要是服务端的工作。比如,Web 站点服务端可以记录请求的 IP 地址,并据此获得用户的地理位置。如果用户添加了代理服务器,我们可以通过检测 HTTP 头中的 X-Forwarded-For 字段来发现这种情形。在 HTTP 应用层和 IP 网络层之间,我们也不难通过在服务端收集 TCP 包头的方式,获取一些传输层的信息。

获取上面这些信息,都只需要后端服务就足够了。那么这类数据的收集,是否就没有前端施展的空间了呢?并不是这样的,让我们看看两种特殊的 fingerprinting 方式:DNS LeakWebRTC Leak

只需要在前端做一点微小的工作,我们就能够定位用户所用的 DNS 服务器。具体地说,当你访问 example.com 的时候,只要在前端页面中随机生成一系列地址为形如 abcdefg.example.com 的图片,就可以让浏览器发起对这些子域名的 DNS 查询。只要 example.com 控制了最后形如 ns1.example.com 的次级域名服务器,那么查询这些地址时逐级发起的 DNS 查询就能够被服务端记录下来,进而获得用户的 DNS 服务器。这样一来,如果仅仅对 HTTP 请求配置了代理,用户所用的 DNS 地址就可能泄露。这时如果用户使用了运营商默认就近分配的 DNS 服务器,那么就可能对服务端暴露出其真实所在的位置

相比上面只需要插入动态链接的方式,WebRTC 泄露所需要前端的参与就更多了一点。我们知道 WebRTC 可以用于支持视频推流一类的实时应用,而 Firefox 和 Chrome 对 WebRTC 的实现中,需要 STUN 协议来用于让两个处于 NAT 后的主机之间创建 UDP 通信。而 STUN 服务器可以向用户返回本地和公网 IP。这样一来,我们就可以用这种方式,在 JavaScript 中获取到用户 NAT 后所在内网的 IP 地址了。

如果想要体验上面所介绍的这几种 fingerprinting 方式所能收集到的数据,请戳这里

JavaScript 行为

上面的描述看起来主要是网络层面上的工作,但其实在浏览里的 JavaScript 范畴内,同样有大量的信息可供采集。

要想编程控制 Web 页面的 UI 与行为,我们必须使用 JavaScript 来操作 DOM。而稍有经验的前端同学们都知道,DOM 是挂载了非常多属性而非常沉重的。这也就意味着,DOM 中存储了大量关于浏览器的敏感信息:User-Agent、系统架构、系统语言、本地时间、时区、屏幕分辨率……而对于 HTML5 中新加入的形如电量、加速度计、信息、Timing 等特性的 API,不要说检测它们的具体值是多少,光是检测这些 API 的存在性,信息量就非常大了。而对这些属性的检测难度有多低呢?我们只需要在 JavaScript 中访问 navigator.xxx 属性,就可以轻易地获得一个浏览器的「身高、体重、血型、星座……」了。

当然了,现代浏览器为了避免一些敏感的 DOM 属性泄露,会使用一些安全策略来限制一些属性的访问。但对于 fingerprinting 的场景来说,有些安全策略和掩耳盗铃差不多。让我们看看 fingerprintjs2 中的一段源码:

// https://bugzilla.mozilla.org/show_bug.cgi?id=781447
hasLocalStorage: function () {try {return !!window.localStorage} catch (e) {return true // SecurityError when referencing it means it exists}
}, 

这个套路在整个库中出现的次数还真不少。藏着掖着不让我访问?这不是此地无银三百两嘛 😃

对 JavaScript 的 fingerprinting demo,请移步这里

Real World 表现

上面介绍的一堆手段结合起来,就能获得非常强大的工业级 fingerprinting 库了。如果你对实际效果有疑问,不妨访问 fingerprintjs2 项目主页,尝试这样的操作:

1.先在你的 Chrome 普通模式下,生成一个 fingerprint。
2.在 Safari 下,也生成一个 fingerprint。
3.和同事的同款 Mac 对比一下结果是否有区别。
4.改掉你的 User Agent 后刷新页面,看看 fingerprint 有没有区别。
5.进入 Chrome 的匿名模式,重新生成一个 fingerprint,看看是否一致。

不出意外地,在同一个 Chrome 中修改各种常见的配置,fingerprint 是不会改变的。而不论更换成另一台电脑上的相同版本浏览器或是同一台电脑上的不同浏览器,都会带来不同的 fingerprint 结果。这就是 fingerprinting 技术的强大之处了。

根据 Mozilla 的数据1,在对站点 100 万次的访问里,有 83.6% 的浏览器有着唯一的 fingerprint,对于启用了 Flash 或 Java 的浏览器,这一数据达到了 94.2%。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值