引言
话说某一天,被产品经理捉住的我被要求实现一个“对任何进入过特定页面的用户进行追踪”的小功能,当时我的内心是拒绝的:汝闻人言否?用户的隐私也是好重要的好伐?
可是没办法,当是时,我一抬头,正前方挂着的就是“996是我们修来的福报”几个沉甸甸血淋淋的大字;左手边站着的就是磨刀霍霍准备贯彻落实公司狼性法则的产品经理;往右一瞧,扑入眼帘的正是老板手腕上的劳力士反射的刺目阳光,它们朴实无华且枯燥地提醒着我后边工位上那兢兢业业诚诚恳恳的十佳员工是因为什么原因而被派去了非洲出差五十年……
形势比人强,长叹一口气之后,弱小可怜而又无助的我只能坐下来,开始了对以帆布指纹识别(Canvas Fingerprinting)为首的一系列浏览器指纹识别技术的研究与探索。
浏览器指纹识别技术
浏览器指纹是指仅通过浏览器的各种信息,如系统字体、屏幕分辨率、浏览器插件等获取到一串可以作为唯一性标识的编码,无需 cookie,就能近乎绝对定位一个用户,就算使用浏览器的隐私窗口模式,也无法匿名(只要不禁用js)。
只要通过浏览器进入了互联网,各种网站上对于用户的追踪几乎无时不刻不在发生——当你网购时,即便没有登录,关掉浏览器后购物车的物品也不会消失;当你访问其他新闻、娱乐网站时,弹出的广告往往都是近期浏览购物网站的类似商品;稍有意识的用户可能会不定时清空浏览器缓存、使用“无痕浏览”、“隐私保护模式”等,然而仍然不能阻止类似广告的洗脑。
这是一个被动的识别方式。也就是说,理论上你访问了某一个网站,那么这个网站就能识别到你,虽然不知道你是谁,但你有一个唯一的指纹,将来无论是广告投放、精准推送,还是其他一些关于隐私的事情,都非常方便。
这里我也不再展开,有兴趣可见 Online tracking: A 1-million-site measurement and analysis 与 Cross-Device Tracking: Measurement and Disclosures 这两篇文献,里面有很多关于当前互联网上利用有关技术进行客户端识别与追踪的研究。
几种比较常见的硬件指纹
1. 帆布指纹(Canvas Fingerprinting)
HTML5的新特性<canvas>提供了很多图案绘制的api,具有支持将形状、圆弧和文本绘制到自定义画布元素的功能。
然而即使相同的HTML5 Canvas元素进行绘制操作,在不同操作系统、不同浏览器上,产生的图片内容也不会完全相同。这是因为在图片格式上,不同浏览器使用了不同的图形处理引擎、不同的图片导出选项、不同的默认压缩级别等不同的。
这些字体渲染、平滑、抗锯齿以及其他设备功能的差异会导致设备以不同的方式绘制图像。这使得生成的像素可以用作设备指纹的一部分。下图就是一个指纹脚本使用的画布图像类型的典型示例。
一个典型的利用Canvas api获取帆布指纹的场景:在Canvas画布上面画出各种内容之后,利用canvas.toDataURL()这个API获取到相应的base64编码作为输出的帆布指纹。
2. 音频上下文指纹(AudioContext Fingerprinting)
与画布指纹相似,音频上下文指纹是一种浏览器或设备指纹技术,在设备指纹元素方面相对较新。通过在现代浏览器中使用HTML5提供的AudioContext API,可以利用固定音频波形(例如正弦或三角波)呈现中的细微差别来提取一致的指纹。
需要注意的是,当使用AudioContext API对系统进行指纹识别时,代码不会收集计算机播放或录制的声音——这里的AudioContext指纹指的是计算机音频堆栈本身的属性。
下面是两种常见的音频堆栈指纹识别方法,它们的方法略有不同,但效果不相上下。
- 生成音频信息流(三角波),对其进行FFT变换,计算SHA值作为指纹
上图显示了如何使用AudioContext属性为音频堆栈设置指纹。首先,用OscillatorNode产生三角波,此信号通过AnalyserNode和ScriptProcessorNode传递。最后,信号通过增益设置为零的GainNode传递到,以在连接到音频上下文目的地(例如计算机扬声器)之前使任何输出静音。AnalyserNode提供对音频信号的快速傅里叶变换(FFT)的访问,该变换使用ScriptProcessorNode添加的onaudioprocess事件处理程序捕获。生成的FFT被输入到散列中并用作指纹。
- 生成音频信息流(正弦波),进行动态压缩处理,计算MD5值
上图显示了使用OfflineAudioContext属性为音频堆栈设置指纹。首先,使用OscillatorNode产生正弦波,输出信号连接到DynamicCompressorNode,以增加系统间处理音频的差异。DynamicCompressorNode的输出被传递到离线音频接口的buffer。然后将buffer值之和的哈希散列用作fingerprint。
下图是从test case中看到对经过处理的OscillatorNode的一个可视化过程:
代码太多就不贴了,如有兴趣可到 示例网站 去看例子以及源代码。
3. WebRTC Local IP Discovery
WebRTC( 网页实时通信,Web Real Time Communication ),是一个被用于在浏览器中进行点对点实时通信的框架,可以通过Javascript访问。为了发现对等点之间的最佳路径,每个对等点收集所有可用的候选地址,包括来自本地网络接口(如以太网或WiFi)的地址和来自NAT公共端的地址,并在没有用户明确许可的情况下将它们提供给web应用程序。从而这些信息也被用于对用户的识别与追踪。
其原理是利用到RTCPeerConnection的API,大致函数如下:
4. 字体枚举指纹(Font Enumeration Fingerprinting)
Javascript和Flash都可以被用来枚举浏览器中的字体,并将它们用于生成标识用户的独特指纹。HTML5的Canvas API提供了一个来推断安装在某特定浏览器上的字体的方法。
Canvas API 中提供了measureText方法,该方法提供了绘制到Canvas上的文本的结果宽度(resulting width)。因而JavaScript脚本可以尝试使用大量不同的字体绘制文本,然后测量它们的结果宽度——如果文本的宽度不等于使用默认字体的文本宽度(如果相同则意味着浏览器没有这种字体),则脚本可以断定浏览器确实有该字体存在。
5. 数学程序指纹(Math Routine Fingerprinting)
现代的CPU和操作系统在计算数学公式时遵循IEEE标准,但是有许多函数没有明确的标准。虽然如何执行函数的代码很清楚,但由于不同浏览器、操作系统和数学库之间依赖包的不同以及处理中间值的方式,最终的结果往往会略有不同。
如上所述,IEEE明确定义了数学方面的标准。但是,它们并没有明确定义如何计算某些函数,如SIN、COS、TAN等。由于这些函数通常需要多个步骤,中间值可以定义为float、doubles或其他值,并且每轮计算的舍入误差都会稍微改变LSB。这为我们在许多情况下确定浏览器和操作系统提供了依据。
6. 显示设备指纹指纹(Display (Screen) Fingerprint)
显示设备指纹是任何指纹脚本中最基本的真实数据点之一。在windows对象里面有许多属性可用于确定屏幕的高度和宽度、可用的高度和宽度、颜色深度、像素密度等。综合起来,它们的结果非常强大。这种指纹的缺点就是,用户相对容易更改——然而大多数用户从来都不会更改这些设置。
function fingerprint_display() {
"use strict";
var strSep, strOnError, strScreen, strDisplay, strOut;
strSep = "|";
strOnError = "Error";
strScreen = null;
strDisplay = null;
strOut = null;
try {
strScreen = window.screen;
if (strScreen) {
strDisplay = strScreen.width + strSep + strScreen.height +
strSep + strScreen.availWidth + strSep + strScreen.availHeight + strSep + strScreen.colorDepth;
}
strOut = strDisplay;
return strOut;
} catch (err) {
return strOnError;
}
}
综合指纹的应用
然而即使是上述的四种方法,产生碰撞的几率依然不小,所以又有了把各种各样样的浏览器指纹以及其他属性综合起来计算出一个哈希值的综合指纹,这样可以大大地降低碰撞的可能性。
下图就是一个示例:
有朋友就要问了:你在这里唧唧歪歪一大通,连行代码都没有,让弟兄们怎么复用?不知道什么叫做 "Talk is cheap, show me the code" 吗?
其实是目前开源的浏览器指纹生成库 fingerprintjs2已经实现地很完美了,除了我上面简略提及的几种浏览器指纹以外,还应用了诸如Accessibility fingerprinting, Camera information, DRM support, Accelerometer support, Virtual keyboards, List of supported gestures (for touch-enabled devices), Pixel density, Video and audio codecs availability等等多种浏览器独特的,一般开发者难以了解的属性。如果真的是有需要的同学,开箱使用即可。
我在这里唧唧歪歪再多代码,又哪里比得上一行npm install fingerprintjs2呢? (睿智.jpg)
Reference List
1. Online tracking: A 1-million-site measurement and analysis