如何保护隐私[6]:如何防范“浏览器指纹”?

2014-01-22IT IT.信息安全

  前一篇介绍了“浏览器指纹的基本概念”今天这篇分享一些防范的技巧。


★防范“指纹”的一般性原则?


  不管是哪一种特征,要想成为“指纹”至少要具备两个条件:“唯一性”和“稳定性”。比如人类手指的纹路就同时具有“唯一性”和“稳定性”——任意两个人的纹路都不同,而且每个人的纹路终生不变。所以,要对付“指纹识别”,咱们就必须反其道而行——破坏“唯一性”和“稳定性”。对浏览器而言,做到这两点并不难。且听俺细细道来。


★“浏览器指纹”的构成及信息量


  前一篇博文已经给大伙儿介绍了 EFF 的浏览器指纹测试工具(链接在“这里”)。通过这个工具可以明显看出,User Agent 的信息量最大,至少占据一半以上的信息量。换句话说,其它所有特征的信息量加起来都没有 User Agent 大。而且除了 User Agent,其它特征的信息量都比较小。这说明啥捏?
  请大伙儿换位思考一下:如果某个网站想要利用浏览器指纹进行用户身份定位,User Agent 是必不可少的一项。缺少这一项,定位的精度会大打折扣。所以,User Agent 是浏览器指纹的关键性信息。
  俺已经在博客中多次唠叨了“二八原理”,浏览器指纹中的 User Agent 就是这关键性的“20%”。有鉴于此,本文的主要篇幅谈【User Agent】;聊完它之后,再聊另外几种指纹机制及防范。


★如何消除【User Agent】的指纹


◇利用浏览器内置的防范措施


  先来聊最简单的招数——使用浏览器内置防御措施。
  要想用这招,首先要判断你使用的浏览器,是否内置了“伪装 User Agent”的功能。
  由于浏览器有很多种,以下介绍用 Firefox 来举例。

  Firefox 从版本 59 开始,引入 RFP 功能(这是洋文“Resistance Fingerprinting”的缩写)。如果启用了该功能,Firefox 默认就会伪装 User Agent 的信息——把真实的 User Agent 伪装成某个常见的 User Agent。

  本方案的优点
  “易用性”很好——你只需开启这个功能,Firefox 自动就帮你伪装好了。

  本方案的缺点
  主要缺点是“不够彻底”——由于 Firefox 使用某个固定且常见的“User Agent 值”进行伪装。因此,目标网站依然【有可能】判断出你在使用 Firefox。仅仅知道你在使用 Firefox,这个信息量【很小】。因此,这个缺点不严重。

◇“多浏览器”方案


  这个方案最简单,也最容易想到。一看这个小标题,估计大部分读者都猜到俺想喷啥口水。
  如果你同时具有两个不同的浏览器(比如:一个 Firefox 一个 Chrome),那么这两个浏览器必然具有不同的 User Agent。如果某个网站收集了浏览器指纹,而你又想在这个网站注册两个不同的马甲,那么你就可以用“多浏览器方案”——分别用不同的浏览器注册不同的马甲。

  本方案的优点
  操作很简单,会装浏览器的同学都玩。

  本方案的缺点
  浏览器的种类毕竟有限(知名且靠谱的浏览器,一只手都能数过来)。万一你想注册十多个马甲,用这个方案就显得傻逼了。

◇“多实例”方案


  为了解决“多浏览器方案”的局限性,自然会想到“多实例”这个方案。此招数俺曾经在《如何防止黑客入侵》系列博文中介绍过。
  在主流的三大浏览器中,Firefox 和 Chrome 支持“多实例”,IE 不支持。所以那些喜欢 IE 的同学就没法用这招了。
  关于 Firefox 和 Chrome 如何配置多实例,请看俺之前的博文(这里)。对于用 Chrome 的同学,俺再次罗嗦一下:Chrome 同时提供“多实例”(洋文叫“Multiple Profiles”)和“多用户”(洋文叫“Multiple Accounts”)两种功能,这两者是完全不同滴。它的“多用户”依然在同一个“实例”中。
  配置完“多实例”之后,一定要记得修改每一个实例的 User Agent,并确保【两两不同】。至于如何修改 User Agent 请参见“这篇博文”——里面提供了三大主流浏览器的修改方法。

  本方案的优点
  浏览器的实例可以配置任意多个(只要你有耐心,硬盘够大,配几百几千都可以)。

  本方案的缺点
  某些浏览器(比如 IE)不支持多实例。

◇“多虚拟机”方案


  要对付 User Agent 的指纹,前面两招基本够用了。但某些同学可能有特殊需求,或者安全要求比较高,所以俺顺便介绍第三种方法。
  第三种方法就是利用虚拟机软件安装不同的虚拟系统,然后在每个虚拟系统中安装浏览器。没用过虚拟化软件的同学,先看俺之前的扫盲教程(在“这里”)。再次罗嗦:如果你在不同的虚拟机中安装相同的浏览器,要记得修改【每个】虚拟机中浏览器的 User Agent。

  本方案的优点
  优点1:前面说了,某些浏览器不支持多实例。万一你偏偏喜欢这种浏览器,就可以考虑用“多虚拟机”的方案。
  优点2:因为屏幕分辨率、系统时区也都是指纹特征。所以在虚拟系统中,你还可以调整屏幕分辨率和时区(使之不同于你真实系统的分辨率和时区)。

  本方案的缺点
  缺点1:你需要额外安装虚拟化软件,然后再安装虚拟系统。过程稍嫌繁琐。对技术菜鸟也有难度。
  缺点2:对系统的硬件有一定的要求(如果你的电脑硬件太寒酸,就甭考虑这招啦)。

◇“动态 User Agent”方案


  (现在来聊最高级,也最难的方案)
  善于思考的同学会发现:前面三个招数,其本质是相通滴。说白了都是利用技术手段“隔离”出不同的浏览器环境,然后单独修改每个环境的指纹,以此来伪造出多个身份。但是对于每一个具体的环境,其指纹依然是固定的。换句话说,前面那三个招数都是针对指纹的【唯一性】。下面俺要介绍的招数可以用来破坏指纹的【稳定性】。
  前面说了,浏览器指纹的信息量,至少有一半以上是来自于 User Agent。所以要破坏浏览器指纹的稳定性,只要让浏览器的 User Agent 动态变化即可。下面分别说明技术思路(以下的招数适合于有一定折腾能力的同学,需要用到一点点编写脚本的伎俩)。

  如何获取常见的 User Agent
  要构造随机的 User Agent ,其实也不难。到“这个网站”可以看到各种各样浏览器的 User Agent。你可以收集一大堆预存着,然后每次从中随机挑选一条作为你的伪装。为了做到每次随机挑选并设置,你可以写一个脚本来干这事儿,然后顺便让这个脚本来帮你启动浏览器。
  再唠叨一下:挑选 User Agent 是有讲究滴,要尽量选择那些比较常见的 User Agent——越常见的 User Agent 所包含的信息量越小。

  对 Firefox 的定制
  三大浏览器中,最有利于隐私保护的是 Firefox(具体的原因分析请看本系列前面的博文),所以先说它的技术实现。

  通过修改 user.js 文件,可以手工指定 Firefox 使用的 User Agent。具体做法是:往 user.js 添加一个配置项,其“名称”是 general.useragent.override,其“值”就是“伪装的 User Agent”。
  如何修改 user.js,请参见博文:《扫盲 Firefox 定制——从“user.js”到“omni.ja”

  上述做法只能达到【静态】效果——你伪装了 User Agent 之后,它就一直保持你设定的值。
  要想做到【动态】的效果,就需要用到【脚本】来自动修改 user.js 文件里面关于 general.useragent.override 的那行代码,每次修改都使用某个【随机选定】的 User Agent。修改完 user.js 之后再把 Firefox 启动起来。
  对于 Windows 下的 Firefox,可以用 VBScript 或 JScript 或 PowerShell 这三种系统内置的脚本;对于 Linux 或苹果系统,可以尝试各种 shell 脚本。
  某些爱思考的同学可能会问,为啥不直接在 user.js 文件里面用 javascript 代码进行 User Agent 的随机生成。
  俺也曾经企图这么干,可惜不行!因为 user.js 中对函数 user_pref 的调用,两个参数都必须是【常量】;而且, user.js 中除了调用该函数,不允许再出现其它的代码行。

  对 Chrome 的定制
  对于 Chrome,可以在命令行参数指定其 User Agent,具体请参见“这篇博文”。
  所以,你可以自己写一个脚本,专门用来启动 Chrome。每次启动都传递一个随机的 User Agent 作为命令行参数。
  对于 Windows 下的 Chrome,可以用 VBScript 或 JScript 或 PowerShell 这三种系统内置的脚本;对于 Linux 或苹果系统,可以尝试各种 shell 脚本。

  对 IE 的定制
  对于 IE 的 User Agent,需要修改注册表的键值(HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\User Agent)。所以捏,可以通过事先写好的脚本(VBScript 或 JScript 或 PowerShell)往相应的注册表键值中写入随机的User Agent,然后再由这个脚本启动 IE。

◇补充说明


  (本文发出之后,看到某些读者留言,特地补充这个小节)
  对于“动态 UserAgent 方案”,很多读者在问:为啥不直接给出代码?
  俺提醒一下:【授人以鱼不如授人以渔】是本博客长期奉行的原则。所以在技术方面,俺更愿意分享一些思路,尽量避免直接给出现成的东西。自己动手实践,有助于能力的提升而且印象更深刻。
  如果你是个程序猿/程序媛,写这样一个脚本应该是易如反掌滴;如果你不是搞技术的,顺便学一下简易的脚本编程(其实很容易滴)。不会编程的同学,俺建议从 Python 开始入手,功能强且门槛低,具体请参见《为啥俺推荐 Python》系列博文。


★如何消除【屏幕分辨率】的指纹


◇“屏幕分辨率”的信息量


  对于【不】使用虚拟机的普通网友,其屏幕分辨率也就是【常见】的那几种(大概在20种以内)——这种情况下,“屏幕分辨率”暴露出的信息量【很低】,不要紧。
  但如果你使用“操作系统虚拟机”,就需要留意“屏幕分辨率的问题”。
  当你在 Guest OS 中上网,并且你【没有】使用全屏模式,那么 Guest OS 的分辨率可能会是一个很奇怪的分辨率(因为独特性很高,会包含【很多】的“指纹信息量”)。所以,俺建议那些用虚拟系统上网的同学,采用如下几个措施:

◇如何防范


  措施1:每个 VM 都采用“全屏模式”
  这个方案针对的是——【普通】的隐私需求。
  VM 全都采用【全屏】,虽然每个 VM 的分辨率相同。但至少这个分辨率是某个【常见】的分辨率,因此【信息量很低】。

  措施2:对每个 VM 都采用某个常见的分辨率(【非】全屏),且每个 VM 的分辨率【各不相同】
  这个方案针对的是——【特别高】的隐私需求。
  由于每个 VM 的分辨率各不相同,假设网站收集了分辨率作为指纹,不同 VM 的上网身份,会被识别为【不同身份】。


★如何消除【Canvas】的指纹


◇“Canvas”是啥玩意儿?


  在本文发布约半年后,有读者在博客留言中询问了“基于 HTML5 的 Canvas 语法进行指纹追踪”。所以俺单独补充了这个章节。
  所谓的“Canvas 指纹”,依赖的是 HTML5 新增的 Canvas 语法。利用这个 Canvas 语法可以实现一些绘图的功能。由于不同类型的浏览器使用了不同的绘图引擎;并且同一种浏览器在不同操作系统平台上,绘图引擎的特性也会有细微的差别。因此,“Canvas 的功能特性”会成为某种指纹信息。

◇如何防范


  Canvas 的绘图功能要依赖于 JS 脚本。因此,只需“禁用 JS 脚本”就可以让“Canvas 指纹”失效。
  俺的建议是:使用一些安全扩展(比如 NoScript),对你不信任的网站禁用 JS 脚本。另外,电子前哨基金会(EFF)提供的“Privacy Badger 扩展”,也可以屏蔽“Canvas 指纹”。
  要测试自己的浏览器是否存在“Canvas 指纹”,请猛击“这个链接”。
  对于 Firefox 浏览器,从版本 59 开始,已经引入 RFP(洋文“Resistance Fingerprinting”的缩写),默认就会限制 Canvas 指纹。
  退一步讲,就算你无法屏蔽“Canvas 指纹”,也不用怕。在本文开头提到了“防范指纹的一般性原则”,其中之一是【破坏唯一性】。前面章节介绍了几个招数,用来破坏“User Agent 的唯一性”。这些招数也可以用来破坏“Canvas 的唯一性”。
  提醒一下:单纯用“多实例”的招数无法破坏“Canvas 指纹”的唯一性。因为在“多实例”的情况下,每个实例共享【同一个】浏览器引擎。所以你必须采用“多浏览器”或者“多虚拟机”的方式。


★补充说明: EFF 的浏览器指纹测试


  前一篇博文介绍了 EFF 的浏览器指纹测试工具,估计很多同学都去测试了。其实捏,不必太在意具体每一项的“比特数”。大伙儿只需要关注其“定性”而不必太在意其“定量”。因为 EFF 网站目前收集的样本还不够多(只有几百万),所以其分析出的信息量(相比全球的统计数据)会有所偏差。
  另外,很多人测试下来的总信息量是 21.85 bits,这是因为 EFF 的总样本目前只有 370万 左右(370万 约等于“2的21.85次方”)。所以比特数到 21.85 就封顶了。


回到本系列的目录