论文阅读| Fingerprinting the Fingerprinters: Learning to Detect Browser Fingerprinting Behaviors 指纹识别:学习检测浏览器指纹识别行为

laolao's Blogs / 2023-05-12 / 原文

https://ieeexplore.ieee.org/document/9519502

https://github.com/uiowa-irl/FP-Inspector


浏览器指纹识别是一种侵入式且不透明的无状态跟踪技术。浏览器供应商、学术界和标准机构长期以来一直在努力针对浏览器指纹识别提供有意义的保护,这些保护既准确又不会降低用户体验。我们提出了 FP-Inspector,这是一种基于机器学习的句法语义方法,可以准确检测浏览器指纹。我们证明 FP-Inspector 表现良好,使我们能够检测到比最先进技术多 26% 的指纹识别脚本。我们表明,基于 FP-Inspector 构建的 API 级指纹识别对策有助于将网站损坏减少 2 倍。我们使用 FP-Inspector 对前 10 万个网站的浏览器指纹识别进行了测量研究。我们发现超过 10% 的前 100K 网站和超过四分之一的前 10K 网站都存在浏览器指纹识别。我们还通过指纹识别脚本发现了以前未报告的 JavaScript API 使用。


Introduction

主流浏览器已经开始提供针对跨站点跟踪的内置保护。例如,Safari阻止所有第三方 cookie,Firefox默认阻止来自已知跟踪器的第三方cookie。随着主流浏览器针对状态跟踪实施反制措施,有人担心它会鼓励跟踪器迁移到更不透明、无状态的跟踪技术,例如浏览器指纹。因此,主流浏览器已经开始探索浏览器指纹识别的缓解措施。

一些浏览器和隐私工具试图通过更改JavaScript API来减轻浏览器指纹识别。例如,Tor浏览器等面向隐私的浏览器限制了Canvas和WebRTC等API的访问,这些API已知会被滥用于浏览器指纹识别。然而,这种全面的API限制会给良性网站带来的副作用。因此,主流浏览器都避免部署全面的API限制。一些浏览器——尤其是 Firefox——试图通过阻止网络请求来减轻浏览器指纹识别。但是,这种方法在很大程度上依赖于手动分析,并且难以限制从第一方域或双重用途第三方(例如 CDN)提供的指纹识别脚本。

Englehardt和 Narayanan[54]手动设计启发式算法,以根据脚本的执行行为检测指纹识别脚本。然而,这种方法依赖于硬编码的启发式方法,这些启发式方法被狭义地定义以避免误报,并且必须不断更新以捕获不断变化的指纹识别和非指纹识别行为。

我们提出了FP-Inspector,一种基于机器学习的方法来检测浏览器指纹。 它训练分类器通过静态和动态分析的组合提取句法和语义特征来学习指纹识别行为,这些特征可以补充彼此的局限性。 更具体地说,静态分析帮助 FP-Inspector 克服了动态分析的覆盖问题,而动态分析克服了静态分析无法处理混淆的问题。

评估表明,FP-Inspector 检测指纹识别脚本的准确率为 99.9%。检测到的指纹脚本比手动设计的启发式方法多 26%。FP-Inspector检测可以将网站上的损坏减少2倍。

我们发现指纹识别的流行率在过去几年中有所增加,10.18%的Alexa前100K网站出现了指纹识别,检测到来自 2000 多个域的指纹识别脚本,包括反广告欺诈供应商和跨站点跟踪器。FP-Inspector还帮助我们发现了几个以前不知道用于指纹识别的新API。发现指纹识别脚本不成比例地使用权限和性能 API 等 API。

我们的主要贡献总结如下:

  • 一种基于ML的句法语义方法,通过结合静态和动态分析来检测浏览器指纹识别行为。

  • 对阻止网络请求或限制API的不同缓解策略造成的网站损坏的评估。

  • Alexa top-100K 网站上浏览器指纹识别脚本的测量研究。

  • JavaScript API 的聚类分析以发现新的浏览器指纹向量。

Background & related Work

用于在线跟踪的浏览器指纹识别。浏览器指纹识别是一种无状态跟踪技术,它使用浏览器通过 JavaScript API和 HTTP标头公开的设备配置信息。浏览器供应商和标准机构 广泛认为浏览器指纹识别是一种滥用行为。浏览器指纹识别比基于 cookie 的跟踪更具侵入性,原因有二:(1) 浏览器指纹对用户来说是不透明的; (2) 用户无法控制浏览器指纹识别。众所周知,浏览器指纹识别用于机器人检测,包括谷歌的reCAPTCHA和一般网络身份验证。有人担心浏览器指纹识别可能会被用于跨站点跟踪。例如,浏览器指纹可用于重新生成或删除重复的cookie。浏览器指纹识别可以用于反欺诈和跨站点跟踪。

浏览器指纹识别的起源。Mayer首先表明可以使用 JavaScript APIS(例如,导航器、屏幕、插件和 MimeType 对象)来利用“古怪”来识别用户。后来,Eckersley 进行了 Panopticlick 实验,使用来自各种 HTTP 标头和 JavaScript APIS 的信息来分析浏览器指纹。随着现代网络浏览器不断通过新的 JavaScript APIS添加功能,浏览器的指纹识别面也在不断扩大。例如,研究人员已经证明 Canvas、WebGL、字体、扩展、音频 API、电池状态 API,甚至移动传感器可以公开可用于构建浏览器指纹的识别设备信息。事实上,许多 APIS 已经被发现在野外被滥用。由于这些担忧,W3C等标准机构提供了指南,以考虑新提议的 JavaScript APIS 的指纹识别潜力。

浏览器指纹识别是否提供唯一且持久的标识符? 浏览器指纹是一种“统计”标识符,这意味着它不能确定性地识别设备。相反,设备的可识别性取决于共享相同配置的设备数量。要用作跟踪标识符,浏览器指纹必须随着时间的推移保持稳定,或者可以以相对较高的置信度进行链接。 Eckersley 测量了对 Panopticlick 测试页面的重复访问,发现 37% 的重复访问者有不止一个指纹。然而,大约 65% 的设备可以通过使用简单的启发式链接指纹来重新识别。同样,Vastel 等人发现 AmIUnique 测试页面的重复访问中有一半在不到 5天的时间内改变了他们的指纹。他们改进了 Eckersley 的链接启发式方法,并表明他们的链接技术可以平均跟踪重复 AmIUnique 访问者 74 天。

浏览器指纹识别对策。现有的指纹保护工具广泛使用三种不同的方法。 一种方法是随机化可被指纹识别的 JavaScript API 的返回值,第二种是规范化可被指纹识别的 JavaScript API 的返回值,第三种是使用启发式检测并阻止指纹识别脚本。 所有这些方法都有不同的优点和缺点。一些方法可以防止主动指纹识别,即探测设备属性(例如已安装的字体)的脚本,而其他方法可以防止被动指纹识别,即收集易于包含在 Web 请求中的信息的服务器,例如 User-Agent 请求标头。随机化和规范化方法可以抵御所有形式的主动指纹识别和某些形式的被动指纹识别(例如,通过随机化用户代理请求标头)。基于启发式的方法可以防御主动和被动指纹识别,例如,通过完全阻止对指纹资源的网络请求。我们进一步讨论这些方法并列出它们的局限性。诸如Canvas Defender之类的随机化方法通过添加噪声来使 Canvas 等 API 的返回值随机化。这些方法不仅影响 API 的功能用例,而且在限制指纹识别方面也无效,因为它们是可逆的。此外,噪声输出本身有时可以用作指纹,允许网站识别启用保护的用户集。

  • JavaScript API 规范化方法,试图让所有用户返回相同的指纹。这是通过限制或欺骗某些 API(例如 Canvas)的返回值,并完全删除对其他 API(例如,电池状态)的访问来实现的。这些方法限制了网站功能并可能导致网站崩溃,即使这些网站出于良性目的使用 API 也是如此。

  • 启发式方法,例如 Privacy Badger和 Disconnect,使用预定义的启发式方法检测指纹识别脚本。这种启发式方法必须严格针对指纹识别器以避免过度阻塞,但有两个局限性。首先,他们可能会错过不符合其狭义检测标准的指纹识别脚本。其次,必须不断维护检测标准以检测新的或不断发展的指纹识别脚本。

  • 基于学习的解决方案来检测指纹。随机化、规范化和基于启发式方法的低效性激发了对基于学习的解决方案的需求。浏览器指纹识别属于更广泛的无状态跟踪类别,即不在用户机器上存储数据的跟踪。无状态跟踪与有状态跟踪形成对比,后者使用浏览器提供的 API 在用户设备上存储标识符。先前的研究已经广泛探索了用于检测有状态跟踪器的基于学习的解决方案。这种方法试图根据脚本的结构和执行来学习脚本的跟踪行为。 Ikram等人的一种此类方法。 [60]使用通过静态代码分析提取的特征。他们将代码语句的n-gram提取为特征,并训练了一个单类机器学习分类器来检测跟踪脚本。在另一项工作中,Wu等人使用通过动态分析提取的特征。他们从脚本的执行痕迹中提取一克Web API方法调用作为特征,并训练机器学习分类器来检测跟踪脚本。先前基于学习的解决方案通常将无状态和有状态跟踪混为一谈。然而,这两种跟踪技术在根本上彼此不同,尝试同时检测有状态和无状态技术的解决方案将取得不同程度的成功。例如,Iqbal 等人最近提出的一种基于图形的机器学习方法来检测广告和跟踪器。 [62]有时成功识别指纹,有时失败。

指纹检测没有像状态跟踪检测那样受到关注。 [39]将具有指纹识别潜力的 17 个手动识别的属性(例如,用户代理)与请求 URL 进行匹配来检测指纹识别供应商。如果 URL 中存在至少一个属性,则该请求被标记为指纹识别。然而,这种简单的方法会错误地检测到指纹等属性的功能使用。此外,当 URL 中的属性值被散列或加密时,这种方法会失败。 Rizzo [91]使用通过静态代码分析提取的特征来训练机器学习分类器。但是,静态代码分析在解释混淆代码和提供清晰的枚举方面具有局限性。

FP-Inspector

FP-Inspector是一种结合静态和动态JavaScript 分析来对抗浏览器指纹识别的机器学习方法。有两个主要组件:检测组件,从脚本中提取句法和语义特征,并训练机器学习分类器来检测指纹识别脚本;缓解组件,它对检测到的指纹识别脚本应用一组分层限制,以对抗浏览器中的被动和/或主动指纹识别。


图 1: FP-Inspector架构
  1. 使用 OpenWPM 的扩展版本抓取网络,提取 JavaScript 源文件及其执行痕迹。
  2. 提取所有脚本的抽象语法树 (AST) 和执行轨迹。
  3. 使用这些表示来提取特征并训练机器学习模型来检测指纹识别脚本。
  4. 使用分层方法来对抗指纹识别脚本。

检测指纹脚本

指纹脚本具有有限数量的API,可用于从设备中提取特定信息。例如,试图检查图形堆栈的脚本必须使用 Canvas 和 WebGL APIS;如果想要收集 2D 渲染(即用于画布指纹识别),必须调用 Canvas API 的 toDataURL() 或 getImageData() 函数来访问渲染的画布图像。过去的研究已经使用这些模式来手动策划启发式方法,以相当高的精度检测指纹识别脚本。我们的工作以它们为基础,并以两种主要方式显着扩展了先前的工作。

还是要用到特征提取技术

首先,FP-Inspector自动学习指纹识别脚本的紧急属性。我们提取了大量低级启发式方法来捕获指纹脚本的句法和语义属性,以训练机器学习分类器。 FP-Inspector 的分类器根据先前研究的指纹脚本的基本事实进行训练,能够泛化以检测新的指纹脚本以及以前未知的指纹方法。

其次,我们同时利用了静态特征(即脚本语法)和动态特征(即脚本执行)。静态表示允许捕获在页面访问期间不会执行的指纹识别脚本。动态表示允许我们捕获混淆或缩小的指纹识别脚本。FP-Inspector 为静态和动态表示训练单独的监督机器学习模型,并结合它们的输出以准确地将脚本分类为指纹识别或非指纹识别。

  • 脚本监控。 通过OpenWPM自动加载网页来收集脚本内容及其执行轨迹。通过收集脚本的原始内容和动态执行痕迹,能够使用静态和动态分析来提取与指纹识别相关的特征。

    • 收集脚本内容:扩展OpenWPM以捕获浏览器加载的所有HTML文档的响应内容。捕获外部和内联 JavaScript,进一步解析 HTML 文档以提取内联脚本。

    • 收集脚本执行痕迹:OpenWPM 记录脚本访问的 Javascript API 的名称、访问的方法名称或属性名称、传递给方法的任何参数或属性设置或返回的值,以及调用时的堆栈跟踪。我们扩展了 OpenWPM 检测的 API 集,以涵盖流行的指纹识别库(即 fingerprintjs2 [16])和脚本(即 Media-Math 的指纹识别脚本 [25])使用的几个附加 API。这些包括 Web 图形库 (WebGL) 和 performance.now,两者以前都不受 OpenWPM 监控。我们还检测了许多用于文档对象模型 (DOM) 交互的 API,包括 createElement 方法以及文档和节点对象。监控对这些 API 的访问使我们能够区分与 DOM 交互的脚本和不与 DOM 交互的脚本。

  • 静态分析。静态分析使我们能够从 JavaScript 文件的内容和结构中捕获信息——包括那些在我们的测量期间没有执行的文件或那些没有被我们的扩展检测覆盖的文件。

    • AST:首先,将脚本表示为抽象语法树 (AST)。这使我们能够忽略脚本之间的编码风格差异和不断变化的 JavaScript 语法。 AST 将脚本编码为语法原语树(例如,VariableDeclaration 和 ForStatement),边表示代码语句之间的语法关系。如果直接从脚本的原始内容构建特征,会对无关信息进行编码,例如,一个脚本作者可能会选择按索引遍历设备属性数组,而另一个脚本作者可能会选择使用同一数组的 forEach 方法。两个脚本都在循环中访问相同的设备信息,并且两个脚本在编码为 AST 时将具有相似的表示。图 2b 提供了一个从简单脚本构建的示例 AST。 AST 中的节点表示脚本中的关键字、标识符和文字,而边表示它们之间的关系。关键字是对解释器有特殊意义的保留字(例如 for、eval),标识符是函数名或变量名(例如 CanvasElem、FPDict),文字是常量值,例如分配给标识符的字符串(例如“例子”)。请注意,空格、注释和编码风格被 AST 抽象掉了。

    • 脚本解包:由于 JavaScript 是一种解释型语言并在运行时编译,因此将脚本表示为 AST 的过程很复杂。这允许部分脚本以纯文本形式到达,稍后用 eval 或 Function 编译和执行。先前的工作表明,指纹识别脚本通常包含用 eval 或 Function [87]“打包”的代码。为了解压包含 eval 或 Function 的脚本,我们将它们嵌入到空的 HTML 网页中,并在经过检测的浏览器 [62] 中打开它们,这样我们就可以在 JavaScript 引擎解析脚本时提取它们。我们捕获解析后的脚本,并在构建 AST 时使用它们代替打包版本。我们也遵循同样的过程来提取内联脚本,这些脚本是直接包含在 HTML 文档中的脚本。脚本 1 显示了一个示例 canvas 字体指纹识别脚本,该脚本已与 eval 一起打包。此脚本循环遍历已知字体列表并测量呈现的宽度以确定是否安装了字体(有关画布字体指纹识别的详尽描述,请参阅 [54])。脚本 2 显示了脚本的解压版本。从这两个片段可以看出,解包后脚本的可解释性明显提高了。图 2 显示了解包对 AST 生成的重要性。脚本的打包版本(即脚本 1)创建了一个通用存根 AST(即图 2a),它将匹配任何使用 eval 的脚本的 AST。图 2b 显示了从脚本的解压版本(即脚本 2)生成的完整 AST。此 AST 捕获传递给 eval 的指纹识别代码的实际结构和内容,并将允许我们从脚本的内容中提取有意义的特征。

    • 静态特征提取:从 AST 生成静态特征。首先分层遍历 AST,将它们分成一对父节点和子节点。父代表上下文(例如,for 循环、try 语句或 if 条件),子代表上下文中的函数(例如,createElement、toDataURL 和 measureText)。 只考虑包含至少一个关键字的父子对,该关键字匹配来自 JavaScript API 之一的名称、方法或属性。将父子组合为所有脚本的特征向量。每个父子组合都被视为二元特征, 1 表示存在特征,0 表示不存在。由于不在静态分析中执行脚本,因此特定于指纹识别的 JavaScript API 方法通常只会在脚本中出现一次。

    图 2b 中的 AST 中提取的特征具有 ForStatement:var 和 MemberExpression:measureText,它们指示存在循环和访问 measureText 方法。这些方法经常用于画布字体指纹识别脚本。直观地,指纹识别脚本向量具有父子对的组合,这些组合特定于指示指纹识别的 API 访问模式(例如,设置新字体并在循环内测量其宽度),这在非指纹识别脚本中不太可能出现。从图 2b 中的 AST 中提取的更全面的特征列表列在附录 IX-B(表 VII)中。

    为了避免过拟合,应用无监督和监督特征选择方法来减少特征数量。首先修剪变化不大的特征(即方差 < 0.01),并使用信息增益来筛选前 1K 个特征。例如,具有最高信息增益的两个特征getSupportedExtensions 和 toDataURL。然后使用这些 top-1K 特征作为输入来训练有监督的机器学习模型。


图2:脚本1和2的截断AST表示。边表示节点之间的句法关系。虚线表示通过截断的节点进行间接连接
  • 动态分析。图 3 显示了从脚本 2 的混淆版本构建的 AST。
    • 动态特征提取:使用两种方法。首先,保留脚本访问单独API或属性的次数和计数。接下来,从传递参数或返回值的 API 构建功能。我们没有直接使用参数或返回值,而是使用派生值来捕获更高级的语义。例如,将计算字符串的长度而不是包括确切的文本,或者将计算元素的面积而不是高度和宽度。这使我们能够避免使用过于具体的特征来训练我们的分类器。例如,从脚本3a的执行轨迹中提取的特征包括(HTMLCanvasElement.getContext,True)和(CanvasRenderingContext2D.measureText,7)True表示HTMLCanvasElement.getContext的使用,7表示文本的大小CanvasRenderingContext2D.measureText。从脚本 3a 的执行跟踪中提取的更全面的特征列表可以在附录 IX-B(表 VIII)中找到。

图3:一个截断的示例显示了 Script 2 中画布字体指纹识别脚本的混淆版本的 AST 表示。边表示节点之间的句法关系。虚线表示通过截断节点的间接连接。
  • 避免过拟合,再次应用无监督和监督特征选择方法来限制特征数量。与静态分析的特征缩减类似,这使我们能够保留代表最常用 API 的特征以进行指纹识别。例如,具有最高信息增益的两个特征表示CanvasRenderingContext2D.fillStyle 和 navigator.platform API 的使用。然后使用top-1K 特征作为输入来训练有监督的机器学习模型。

  • 对指纹识别脚本进行分类。 使用决策树来训练机器学习模型。训练了两个独立的模型,并结合了它们的分类结果。也就是说,如果脚本被使用静态特征作为输入的模型或使用动态特征作为输入的模型分类为指纹识别,则脚本被认为是指纹识别脚本。对页面访问期间加载的所有脚本进行分类。

缓解指纹识别脚本

现有的浏览器指纹对抗措施可以分为两类:内容拦截和API限制。 顾名思义,内容阻止根据网络位置阻止下载指纹识别脚本的请求。API 限制不会阻止指纹识别脚本的加载,而是限制对已知用于浏览器指纹识别的某些 JavaScript API 的访问。以隐私为中心的浏览器,如 Tor 浏览器 [15] 更喜欢全面的 API 限制而不是内容阻止,主要是因为它回避了检测指纹脚本的挑战性问题。虽然 API 限制提供了针对主动指纹识别的可靠保护,但它可能会破坏出于良性目的使用受限 API 的网站的功能。部署 API 限制的浏览器还需要针对被动指纹识别的额外保护(例如,通过 Tor 网络路由流量)。内容阻止可防止主动和被动指纹识别,但当检测到的脚本具有双重用途(即同时实现指纹识别和合法功能)或误报时,它也容易被破坏。

网站损坏是指纹识别对策的重要考虑因素。例如,Mozilla 最近的一项用户试验表明,由于网站损坏Firefox 中的隐私对策可能会对用户参与度产生负面影响。我们有兴趣研究基于 FP-Inspector 的不同指纹识别对策对网站损坏的影响。我们实施以下对策:

  • API 限制。将脚本访问限制为已知由指纹识别脚本使用的 JavaScript API,以下称为“指纹识别 API”。指纹识别 API 包括在 fingerprintjs2 中使用的函数和属性以及由 FP-Inspector 在第 VI 节中发现的函数和属性。请注意,此对策完全不依赖于 FP-Inspector 对指纹识别脚本的检测。

  • 有针对性的 API 限制。限制从 FP-Inspector 检测到的指纹脚本。

  • 请求阻止。阻止从 FP-Inspector 检测到的下载脚本请求,以部署指纹识别脚本。

  • 二者兼有。阻止从 FP-Inspector 检测到的下载脚本以部署指纹识别脚本的请求,第一方脚本和内联脚本除外。此外,限制对检测到的域上的第一方和内联脚本的指纹识别 API 的访问。这可以防止第一方的主动指纹识别以及第三方的主动和被动指纹识别。

Evaluation

根据 FP-Inspector 在检测指纹脚本方面的准确性及其在缓解指纹时对网站损坏的影响来评估 FP-Inspector 的性能。

Accuracy

需要指纹和非指纹脚本样本来训练我们的监督机器学习模型。使用 [54] 中实现的启发式算法的略微修改版本来检测指纹识别脚本。

1)指纹定义:

如果脚本使用 [54] 中定义的 Canvas、WebRTC、Canvas Font 或 AudioContext,将其视为指纹识别。具体来说,如果启发式触发了上述任何行为,我们将脚本标记为指纹识别,否则将其标记为非指纹识别。我们不认为来自导航器的属性集合或来自脚本的屏幕 API 是指纹识别,因为这些 API 经常被不对用户进行指纹识别的脚本以不明显的方式使用。确切细节列在附录 IX-C 中。

2)数据收集:

我们使用Open-WPM 来抓取从 Alexa top-100K 网站中抽取的两万个网站的主页。为了构建这个样本,我们从列表中取出前 10K 个站点,并用 Alexa 排名从 10K 到 100K 的 10K 个站点的随机样本对其进行扩充。抓取期间,允许每个站点在页面访问超时之前有 120 秒的时间完全加载。存储页面上加载的所有文档和脚本的 HTTP 响应正文内容以及所有脚本的执行轨迹。

抓取的数据集包含 17,629 个网站和 153,354 个不同的执行脚本。由于通过分析脚本执行轨迹生成我们的基本事实,我们只能从我们爬行期间实际执行的脚本中收集基本事实。虽然我们无法在爬行期间不执行的脚本上训练我们的分类器,但我们仍然能够对它们进行分类。它们的分类结果将完全取决于从脚本内容中提取的静态特征。对于静态特性,我们成功地为 143,526 个脚本创建了 AST——9,828 个脚本 (6.4%) 由于语法无效而失败。在有效脚本中,我们提取了总共 47,717 个父子组合,并按照第 III 节中的描述进行特征选择。具体来说,我们首先通过 0.01 的方差阈值进行过滤,以将集合减少到 8,597 个父子组合。然后,我们在按信息增益排序时选择前 1K 个特征。对于动态特征,我们从 153,354 个脚本中提取了总共 2,628 个特征。与静态分析类似,我们按照第 III 节所述进行特征选择,并在按信息增益排序时将特征集减少到前 1K。

3) Enhancing Ground Truth:

正如在第二节中所讨论的,启发式方法有两个固有的问题。首先训练一个不完整的基本模型,然后手动分析分类器输出与基本事实之间的差异。每当我们发现我们的分类器做出了正确的决定而没有反映在基本事实中时,我们就会更新基本事实(即,发现基本事实启发式遗漏的指纹识别脚本)。执行此过程的三个迭代。

  • 人工贴标。在迭代再训练期间分析脚本的手动过程如下。我们会为每个需要手动分析的脚本自动创建报告。每份报告包含:(1) 我们的仪器监控的所有 API 方法调用和属性访问,包括参数和返回值,(2) 脚本片段,捕获用于 canvas、WebRTC 的 API 调用的周围上下文、画布字体和 AudioContext 指纹识别,(3) fingerprintjs2 相似度得分, 3 和 (4) 完整脚本的格式化内容。然后,我们根据我们的领域专业知识手动审查报告,以确定分析的脚本是否是指纹识别。具体来说,我们在脚本中寻找类似启发式的行为。启发式行为意味着脚本中的指纹识别代码:

在功能和结构方面类似于已知的指纹识别代码,它伴随着其他指纹识别代码(即大多数指纹识别脚本使用多种指纹识别技术),并且它不与脚本中的功能代码交互。例如,常见的模式包括从多个 API 顺序读取值,将它们存储在数组或字典中,对它们进行哈希处理,并在网络请求中发送它们,而不与脚本或页面的其他部分交互。

研究发现。 我们发现有问题的脚本通常与已知的指纹识别库相似,并且经常使用其他指纹识别脚本使用的 API。如果在脚本中发现任何指纹识别功能,我们将整个脚本标记为指纹识别,否则标记为非指纹识别,无法手动确定(例如,由于混淆)的脚本被认为是非指纹识别。发现基于启发式的真实数据高精度但召回率低。脚本被遗漏有两个主要原因。首先,指纹识别部分驻留在脚本的休眠部分,等待网页中的其他事件或函数调用。

脚本3(附录 IX-D)中的代码片段定义了特定于指纹的原型,并将它们分配给一个窗口对象,该对象可以在以后的某个时间点调用。其次,脚本的指纹识别功能偏离了预定义的启发式方法。例如,脚本 4(附录 IX-D)中的片段调用 CanvasRenderingContext2D 元素上的保存和恢复方法,这是启发式方法用来过滤掉非指纹脚本的两个方法调用。

然而,少数脚本中,启发式算法优于分类器。使用用于指纹识别的 API 且与网页的交互有限的脚本有时会被错误分类。例如,我们发现分类器错误标记了使用 Canvas API 创建动画和图表的非指纹识别脚本,并且在该过程中仅与少数 HTML 元素交互。 由于启发式无法概括指纹识别行为,因此它们不会将部分 API 使用和有限交互归类为指纹识别。在其他情况下,分类器将指纹识别脚本标记为非指纹识别,因为它们包括单一的指纹识别技术和功能代码。

发现分类器错误标记嵌入在登录页面上的指纹识别脚本的情况,这些脚本仅包括 canvas 字体指纹识别和功能代码。由于启发式算法是精确的,因此它们不考虑脚本的功能方面,也不将指纹识别的有限使用归类为非指纹识别。

改进。 表 I 展示了对静态和动态分析的真实数据改进的手动评估结果。从表中可以看出,当分类器将脚本分类为指纹识别与真实数据不一致时,通常是正确的。在每次迭代中都发现了新的指纹识别脚本。此外,从表中还可以看出,我们的模型能够在每次迭代中纠正其错误。通过将额外 240 个脚本标记为指纹识别和 16 个脚本标记为非指纹识别来增强静态分析的真实数据,将 13 个脚本标记为指纹识别和 12 个脚本标记为非指纹识别来增强动态分析的真实数据。我们使用静态分析检测到 1,108 个指纹识别脚本和 142,418 个非指纹识别脚本,并使用动态分析检测到 929 个指纹识别脚本和 152,425 个非指纹识别脚本。


表 I:通过多次迭代保留增强准确性。
Itr.表示静态 (S) 和动态 (D) 模型训练的迭代次数。
New FP表示分类器检测到的额外指纹脚本,NON-FP表示与启发式相比,分类器检测到的新非指纹脚本。
Correct FP 表示手动验证的指纹脚本分类器的正确确定
Correct 检测 (NON-FP) 表示手动验证的非指纹脚本分类器的正确确定。

4)分类准确性:

使用决策树模型对爬取的脚本进行分类。执行10折交叉验证。通过将脚本的预测标签与第 IV-A3 节中描述的增强真实数据进行比较来确定模型的准确性。对于训练有静态特征的模型,达到了 99.8% 的准确度,85.5% 的召回率和 92.7% 的精度。对于训练有动态特征的模型,达到99.9% 的准确度,96.7% 的召回率和 99.1% 的精度。

结合静态和动态模型。在 FP-Inspector 中,训练两个独立的机器学习模型——一个使用从脚本的静态表示中提取的特征,另一个使用从脚本的动态表示中提取的特征。这两个模型都提供了用于检测指纹识别脚本的互补信息。静态特征的模型识别出未被动态捕获的休眠脚本,而动态特征的模型识别出被静态遗漏的混淆脚本。如果任一模型检测到一个脚本为指纹识别,就认为它是一个指纹识别脚本。如果两个模型都没有检测到一个脚本为指纹识别,则认为它是一个非指纹识别脚本。


表 II:检测指纹识别脚本方面的召回率、精度和准确度。
"Heuristics (Scripts/Websites)表示启发式检测到的脚本和网站数量
"Classifiers (Scripts/Websites)"表示分类器检测到的脚本和网站数量。
FPR 表示假阳性率,FNR 表示假阴性率。

从表中可以看出,分类器比启发式多检测了 26% 的脚本,假阳性率(FPR)微不足道,仅为 0.05%,假阴性率(FNR)为 6.1%。总体而言,发现通过结合模型,FP-Inspector 将其检测率提高了近 10%,并达到了 99.9% 的总体准确度,93.8% 的召回率和 93.1% 的精度。

破损

对于 API 限制,我们覆盖指纹识别 API 的函数和属性,并在任何网页上访问它们时返回错误消息。对于针对性 API 限制,我们每次脚本调用指纹识别 API 时遍历堆栈以提取脚本的域。使用 FP-Inspector 的分类器确定来创建域过滤列表。对于请求阻止,使用 webRequest API拦截并阻止与我们的过滤列表匹配的网络请求。

接下来,分析这些强制措施对随机抽取的 50 个加载指纹识别脚本的网站以及 11 个由于指纹识别对策而在 Firefox 中报告为损坏的网站造成的破损情况。我为了使手动破损分析系统化,通过查看 Mozilla 的错误跟踪器上的与破损相关的错误报告,创建了一个常见指纹识别破损模式的分类法。我们将每个测试网站在原始 Firefox上作为控制打开,并在安装了我们扩展的 Firefox 上作为处理打开。值得注意的是,我们在研究的控制和处理分支中都禁用了 Firefox 的默认隐私保护。如果我们仅在处理组中发现缺失内容或损坏的网站功能,则使用以下分类法分配破损标签:

  • 重大:网站的核心功能被破坏。示例包括:登录或注册流程、搜索栏、菜单和页面导航。
  • 次要:网站的次要功能已损坏。示例包括:评论部分、评论、社交媒体小部件和图标。
  • 无:网站的核心和次要功能在处理和控制方面是相同的。我们认为丢失的广告没有损坏。

为了减少编码人员的偏见和主观性,我们要求两位审阅者使用上述指南对全套 61 个测试网站的损坏进行编码。对于总共 244 个实,我们两位评审员之间的编码可靠性为 87.70%。表 III 总结了平均破损结果。总的来说,我们注意到使用 FP-Inspector 检测的有针对性的对策在特别容易损坏的测试网站上将损坏减少了 2 倍。更具体地说,全面的 API 限制受到的影响最大(超过三分之二)的测试网站),而有针对性的 API 限制导致的破坏最少(约 75% 的测试网站没有重大破坏)。

令人惊讶的是,我们发现一揽子 API 限制比请求阻塞导致更多的破坏。我们认为这是由于对页面上的所有脚本都应用了全面的 API 限制,无论它们是否进行指纹识别,因为即使是良性功能也可能受到影响。相比之下,请求阻止只会影响指纹已知的脚本。接下来,我们观察到有针对性的 API 限制破坏最少。这是意料之中的,因为我们不会阻止请求,只会限制涉嫌指纹识别的脚本;良性脚本的功能不受影响。

我们发现混合对策导致的破坏比请求阻塞少,但比目标 API 限制造成的破坏更多。混合对策比请求阻止执行得更好,因为它不会阻止网络请求加载第一方指纹识别资源,而是应用有针对性的 API 限制来防止第一方指纹识别。然而它的性能比有针对性的 API 限制更差,因为它仍然阻止网络请求加载未被有针对性的 API 限制阻止的第三方指纹识别资源。虽然混合阻止比有针对性的 API 限制造成更多破坏,但它提供了最好的保护。混合阻塞减轻了来自第三方资源的主动和被动指纹识别,以及来自第一方资源和内联脚本的主动指纹识别。混合阻止唯一遗漏的东西——被动第一方指纹识别——几乎不可能在不破坏网站的情况下进行阻止,因为浏览器加载的任何第一方资源都可以被动地收集设备信息。

我们发现网站损坏的最常见原因是基本功能对指纹识别代码的依赖。在严重的情况下,网站上的注册/登录或其他核心功能取决于指纹的计算。例如,freelancer.com 上的注册页面是空白的,因为我们限制了来自 f-cdn.com 的指纹识别脚本。在不太严重的情况下,网站会嵌入依赖于指纹识别代码的小部件或广告。例如,ucoz.ru/all/ 上的社交媒体小部件消失了,因为我们对来自 usocial.pro 的指纹脚本应用了限制。


表Ⅲ:不同对策造成的破损明细。结果显示了两位审稿人的平均评估。

Measuring Fingerprinting In The Wild

使用 FP-Inspector 的检测组件来分析 top-100K 网站上的指纹识别状态。首先从第 IV-A2 节中描述的 20K 网站抓取开始,并对未包括在该测量中的其余 80K 网站遵循相同的收集程序。在这额外的 80K 中,我们成功访问了 71,112 个网站。我们发现:(1) 指纹识别的部署仍在增长(2) 指纹识别在新闻网站上的流行率几乎是任何其他类别网站的两倍, (3) 指纹识别用于反广告欺诈和潜在的跨站点跟踪。

A. 超过四分之一的顶级网站现在对用户进行指纹识别

首先检查顶级站点的指纹识别部署,结果总结在表 IV 中。我们发现指纹识别在排名靠前的网站上更为普遍。我们还检测到比之前的工作更多的指纹识别,超过四分之一的顶级网站现在部署了指纹识别。这种使用量的增加适用于所有网站排名——我们观察到即使在不太受欢迎的网站(即 10K - 100K)中也有显着增加。总体而言,我们发现超过 10.18% 的前 100K 网站部署了指纹识别。


表 IV:部署指纹识别的 Alexa 前 100K 网站的分布。结果按网站排名划分。

我们还发现提供指纹识别服务的域明显多于过去的工作——前 10 万个站点中有 2,349 个域(表 V),而前 100 万个站点中有 519 个域。


表 V:在 Alexa top-100K 网站上被归类为指纹识别的顶级供应商的存在。 Tracker 栏根据 Disconnect 的跟踪保护列表显示供应商是否为跨站点跟踪器。 Y 代表是,N 代表否。

B. 指纹识别在新闻网站上最为常见

指纹识别在不同类别的网站上的部署不均衡。 图 4 总结了我们的发现,与传统跟踪方法一样,指纹识别在依赖广告获利的网站上更为常见。因为被归类为指纹识别的最普遍的供应商提供反广告欺诈和跟踪服务。指纹在新闻网站上的特别高的使用率也可能表明指纹被用作付费专区执行的一部分,因为基于 cookie 的付费专区相对容易规避。


图 4 :在不同类别的网站上部署指纹识别脚本。

C. 指纹识别用于打击广告欺诈,但也用于潜在的跨站点跟踪

FP-Inspector 检测到的指纹脚本通常由第三方供应商提供。表 V 中排名前五的供应商中的三个(doubleverify.com、adsafeprotected.com 和 adsco.re)专注于验证广告印象的真实性。他们的隐私政策提到他们使用利用“浏览器类型、版本和功能”的“设备识别技术”。我们的结果还证实了机器人检测服务依赖于指纹,并表明流行的指纹供应商提供反广告欺诈服务。前五名中剩下的两家供应商,即 alicdn.com 和 yimg.com,似乎分别是 Alibaba 和 Oath/Yahoo! 的 CDN。

一些指纹供应商披露使用 cookie“收集有关广告印象机会的信息”,这些信息与“客户和合作伙伴共享以执行和交付广告和流量测量服务”。为了更好地了解这些供应商是否参与跨站点跟踪,我们首先分析指纹供应商与 Disconnect 的跟踪保护列表的重叠。 8 Disconnect 采用仔细的人工审查流程将服务归类为跟踪。例如,Disconnect 将 c3tag 分类为跟踪,将 adsco.re 分类为不跟踪,因为根据他们的隐私政策,前者与其客户共享个人身份信息 (PII),而后者没有。我们发现 3.78% 的指纹供应商被 Disconnect 归类为跟踪。

我们还分析了指纹供应商是否参与 cookie 同步,这是在线广告商和跟踪器提高覆盖率的常见做法。例如,当 cookie 被清除或分区时,跟踪器可能会将来自单个设备的浏览数据关联到多个不同的标识符 cookie。然而,指纹供应商可以使用设备指纹将这些 cookie 标识符链接在一起。如果指纹供应商之前已将 cookie 与其他跟踪器同步,则它可以使用其指纹链接其他跟踪器的 cookie。我们使用 Fouad 等人的列表。 [57]识别也参与 cookie 同步的指纹域。我们发现有 17.28% 的指纹供应商参与了 cookie 同步。更重要的是,我们发现指纹供应商经常与知名广告技术供应商同步 cookie。例如,adsafeprotected.com 与 rubiconproject.com 和 adnxs.com 进行 cookie 同步。我们还发现许多指纹识别供应商与众多第三方进行 cookie 同步。例如,openx.net 与 332 个其他域进行 cookie 同步,其中 14 个被 Disconnect 归类为跟踪。我们将对指纹识别和 cookie 同步之间的相互作用进行深入的大规模调查作为未来的工作。

Analyzing APIs used by Fingerprinters

首先分析指纹识别脚本中 Javascript API 的分布。从源代码中提取 Javascript API 关键字(即 API 名称、属性和方法),并根据它们在指纹识别脚本中出现的比例与在非指纹识别脚本中出现的比例对它们进行排序。与非指纹脚本相比,此比率捕获了 API 关键字在指纹脚本中的相对普遍性。关键字的较高比率值意味着它在指纹识别脚本中比在非指纹识别脚本中更普遍。请注意,∞ 表示该关键字仅出现在指纹识别脚本中。表 VI 列出了一些有趣的 API 关键字,这些关键字在指纹识别脚本中异常普遍。我们在附录 IX-F 中提供了更全面的 API 关键字列表,这些关键字在指纹识别脚本中普遍存在。


表 VI:指纹识别脚本中经常使用的 JavaScript API 关键字示例及其在 20K 网站抓取中的存在。 Scripts (count) 表示使用关键字的不同指纹识别脚本的数量,Websites (count) 表示嵌入这些脚本的网站数量。
由于API关键字数量庞大,人工全部分析几乎不可行。因此,首先将提取的 API 关键字分组到几个集群中,然后手动分析 API 关键字最集中的集群,这些 API 关键字在 FP-Inspector 检测到的指纹识别脚本中不成比例地使用。我们的主要见解是,浏览器指纹识别脚本通常不会单独使用一种技术(例如画布指纹识别),而是将多种技术结合在一起。因此,我们希望与指纹识别相关的 API 关键字作为一个不同的集群分离出来。

为了将 API 关键字分组,首先构建 API 关键字的共现图。具体来说,我们将 API 关键字建模为节点,并在它们之间包含一条边,该边根据脚本中同时出现的频率进行加权。因此,同时出现的 API 关键字一起出现在我们的图形表示中。然后,我们通过识别共现 API 关键字的强连接社区,将 API 关键字共现图划分为集群。具体来说,我们通过使用 Louvain 方法计算最大化模块化的节点分区来提取共现关键字的社区。

我们提取了 25 个具有明显密集的同时出现的 API 关键字的集群。为了识别感兴趣的集群,将 API 关键字在指纹识别脚本中出现的比例分配给非指纹识别脚本中出现的比例,作为节点的权重。根据节点是否出现在 fingerprintjs2中进一步对节点进行分类。

功能指纹识别。此类别涵盖用于探测浏览器支持的不同功能的浏览器指纹识别技术。

  • 权限指纹:权限 API 提供了一种方法来确定是否授予或拒绝访问功能或 API 的权限。我们发现了几个在指纹识别脚本中使用 Permissions API 的案例。具体来说,我们发现了探测通知、地理定位和相机等 API 的状态和权限的情况。浏览器和用户设置之间的权限差异可以用作指纹的一部分。

  • 外设指纹识别:现代浏览器提供与连接到设备的外设进行通信的接口。我们发现了几个案例,其中游戏手柄和虚拟现实设备等外围设备被探测到。在外围设备探测的一个示例中,我们发现了一个使用 getLayoutMap 函数探测键盘布局的情况。键盘的布局(例如,大小、特定键的存在、与特定键关联的字符串)因供应商和型号而异。这些外围设备的存在和支持的各种功能可能会泄漏熵。

  • API 指纹识别:所有浏览器都会向网络公开不同的功能集和 API。此外,一些浏览器扩展会覆盖原生 JavaScript 方法。浏览器中的这种实现不一致和用户安装的扩展的修改可能会泄漏熵 [84]。我们发现了几个案例,其中某些功能(例如 AudioWorklet)被指纹识别脚本探测到。 AudioWorklet 仅在基于 Chromium 的浏览器(例如 Chrome 或 Opera)中从版本 66 开始实现,并且可以探测它的存在以检查浏览器及其版本。我们还发现了几种情况,指纹识别脚本会检查某些函数(如 setTimeout 和 mozRTCSessionDescription)是否被覆盖。函数重写也可能会泄露某些浏览器扩展的存在。例如,Privacy Badger [27] 覆盖了几个已知用于指纹识别的函数原型。

算法指纹识别。 此类别涵盖浏览器指纹识别技术,这些技术不仅仅是简单地探测不同的功能。这些浏览器指纹识别技术使用不同的 JavaScript API 通过算法处理某些输入,并利用不同的实现以不同方式处理这些输入这一事实来泄漏熵。我们讨论了以前在指纹识别脚本中未观察到的新发现的 JavaScript API 用途,以及自最初发现以来似乎已经发展的已知指纹识别技术。

  • 时间指纹:性能 API 提供加载资源生命周期中各个点的高分辨率时间戳,它可以以各种方式用于进行与时间相关的指纹攻击 [29],[82]。我们发现了几个使用 Performance API 记录其所有事件(如 domainLookupStart、domainLookupEnd、domInteractive 和 msFirstPaint)的时间的指纹识别脚本实例。此类测量可用于计算域的 DNS 查找时间、交互式 DOM 的时间以及首次绘制的时间。一个小的 DNS 查找时间可能会显示该 URL 以前曾被访问过,因此可能会泄漏导航历史记录 [29],而交互 DOM 的时间和首次绘制网站的时间可能因不同的浏览器和不同的底层硬件配置而异。时间信息的这种差异可能会泄漏熵。

  • 动画指纹识别:与时间指纹识别类似,我们发现指纹识别脚本使用 requestAnimationFrame 来计算浏览器中内容渲染的帧速率。浏览器保证它会在重绘视图之前执行传递给 requestAnimationFrame 的回调函数。浏览器回调率通常与显示刷新率 [28] 匹配,并且一个时间间隔内的回调数可以捕获帧率。帧速率的差异可能会泄漏熵。

  • 音频指纹识别:Englehardt 和 Narayanan [54] 首先报告了使用 AudioContext API 的音频指纹识别技术。具体来说,使用 AudioContext 生成的音频信号因设备和浏览器而异。音频指纹识别似乎已经进化。我们确定了几种情况,在这些情况下,指纹识别脚本使用 AudioContext API 来捕获其他属性,例如 numberOfInputs、numberOfOutputs 和 destination 等许多其他属性。除了读取 AudioContext 属性外,我们还发现使用 canPlayType 提取设备支持的音频编解码器的情况。 AudioContext API 公开的这些附加信息可能会泄漏熵。

  • 传感器指纹识别:之前的工作表明,设备传感器可能被滥用于浏览器指纹识别 [43]、[47]、[50]。我们发现了几个以前已知和未知的传感器被指纹识别脚本使用的实例。具体来说,我们发现以前已知的传感器 [47],例如 devicemotion 和 deviceorientation,更重要的是,指纹识别脚本使用了以前未知的传感器,例如 userproximity