浏览器指纹技术简介

浏览器指纹技术简介

人的指纹千变万化,具有唯一性,可以作为人的身份标识。同时人的姓名、身份证号、相貌特征也可以作为唯一的身份标识。

设备指纹或机器指纹是为了识别而收集的有关远程计算设备的软件和硬件的信息。比如设备的硬件ID,像手机在生产过程中都会被赋予一个唯一的IMEI(International Mobile Equipment Identity)编号,用于唯一标识该台设备。像电脑的网卡,在生产过程中会被赋予唯一的MAC地址。

通常使用指纹算法将信息同化为一个简短的标识符。

而浏览器指纹就是指通过与设备的web浏览器交互而专门收集的信息。

浏览器指纹的用处

理论上,无登录的状态下,并且浏览器中无法读取或存储持久cookie,无法读取客户端的IP,或同一个设备上切换不同的浏览器的情况下,我们仍然可以通过浏览器指纹完全或者部分识别单个设备。

  • 使服务提供商能够检测并防止身份盗窃和一些欺诈行为
  • 组成个人浏览历史的长期记录(并提供有针对性的广告甚至是对目标发起相对应的攻击行为)

浏览器指纹的使用模拟场景

针对性的广告推送

在网站上浏览某个商品,了解了相关的商品信息,但并没有下单购买,甚至没有进行登录操作。过两天用同台电脑访问其他网站的时候却发现很多同类商品的广告。

协助识别同一设备

在某博客中你有多个小号(水军),这些小号的存在就是为了刷某个帖子的热度或者进行舆论引导,即便你在切换账号的时候清空了cookie、本地缓存,重开路由器甚至使用vpn来进行操作,但是管理人员可能还是知道这是同一个人在操作,从而被打击

浏览器基本指纹

基本指纹是任何浏览器都具有的特征标识,比如硬件类型(Apple)、操作系统(Mac OS)、用户代理(User agent)、系统字体、语言、屏幕分辨率、浏览器插件 (Flash, Silverlight, Java, etc)、浏览器扩展、浏览器设置 (Do-Not-Track, etc)、时区差(Browser GMT Offset)等众多信息,这些指纹信息“类似”人类的身高、年龄等,有很大的冲突概率,只能作为辅助识别。

基本指纹特征分类

所属分类 分类内容
浏览器特征 userAgent、浏览器的语言、浏览器的插件等
系统特征 操作系统
时区特征 格林威治时间和本地时间之间的时差、时区所属、地区经纬度、地区、IP地址等
硬件特征 webgl vendor、webgl renderer、设备能够支持的最大同时触摸的点数、可用的逻辑处理器核心数、设备屏幕的宽高与色彩信息

基本指纹的获取

浏览器特征指纹获取

指纹内容 获取指纹的方式
userAgent(用户代理) navigator.userAgent
浏览器的语言 navigator.language
浏览器的插件 Array.from(navigatorObj.plugins).map(item => item.name).join(',')

系统特征指纹获取

指纹内容 获取指纹的方式
操作系统 navigator.platform

时区特征指纹获取

指纹内容 获取指纹的方式
格林威治时间和本地时间之间的时差 new Date().getTimezoneOffset()
时区所属 需查询服务器获取相应信息
地区经纬度 navigator.geolocation.getCurrentPosition(需在https安全环境下才能调用)或查询服务器获取相应信息
地理地区名称 需查询服务器获取相应信息
IP地址 需查询服务器获取相应信息

可供查询的一些免费和测试服务资源

stackoverflow.com/questions/3…

硬件特征指纹获取

指纹内容 获取指纹的方式
设备能够支持的最大同时触摸的点数 navigator.maxTouchPoints
可用的逻辑处理器核心数 navigator.hardwareConcurrency
设备屏幕的宽高与色彩信息 ${ screen.width }*${ screen.height }*${ screen.colorDepth }
webgl vendor: 通过canvas创建的WebGLRenderingContext 三维渲染上下文对象获取
webgl renderer 通过canvas创建的WebGLRenderingContext 三维渲染上下文对象获取

webgl vendor和renderer的获取代码示例

  const glCanvas = document.createElement('canvas')
  const gl = glCanvas.getContext("webgl2");
  const webglMsg = getHardwareInfo(gl)
  webglString.vendor = webglMsg.vendor
  webglString.renderer = webglMsg.renderer  
  function getHardwareInfo(gl) {
    var debugInfo = gl.getExtension("WEBGL_debug_renderer_info");
    if (!debugInfo) {
      return null;
    }
    var vendor = gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL);
    var renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
    return {
      vendor: vendor,
      renderer: renderer,
    };
  }

复制代码

canvas指纹

Canvas是HTML5中的动态绘图标签,也可以用它生成图片或者处理图片。即便使用Canvas绘制相同的元素,但是由于系统的差别,字体渲染引擎不同,对抗锯齿、次像素渲染等算法也不同,canvas将同样的文字转成图片,得到的结果也是不同的。

由于指纹主要基于浏览器、操作系统和已安装的图形硬件,因此还是无法完全做到唯一识别用户(重复率很低)。

canvas指纹的生成

一般直接使用离屏canvas就可以

const outScreenCanvas = document.createElement('canvas')
const ctx = outScreenCanvas.getContext("2d");
// Text with lowercase/uppercase/punctuation symbols
const txt = "BrowserLeaks,com <canvas> 1.0";
ctx.textBaseline = "top";
// The most common type
ctx.font = "14px 'Arial'";
ctx.textBaseline = "alphabetic";
ctx.fillStyle = "#f60";
ctx.fillRect(125,1,62,20);
// Some tricks for color mixing to increase the difference in rendering
ctx.fillStyle = "#069";
ctx.fillText(txt, 2, 15);
ctx.fillStyle = "rgba(102, 204, 0, 0.7)";
ctx.fillText(txt, 4, 17);
const canvasImageData = outScreenCanvas.toDataURL()
复制代码

接着将获取到的canvasImageData通过hash算法得出唯一值(md5或者sha256等),就是我们所得到的canvas指纹了 一般我们会用到crypto-js

import sha256 from 'crypto-js/sha256';
const canvasFinger = sha256(canvasImageData)
复制代码

音频指纹

AudioContext指纹和Canvas类似也是基于硬件设备或者软件的差别,来产生不同的音频输出,然后计算得到不同的hash来作为标志。

音频指纹的生成

方法一:生成音频信息流(三角波),对其进行FFT变换,计算SHA值作为指纹。

方法二:生成音频信息流(正弦波),进行动态压缩处理,计算MD5值。

两种方法都是在音频输出到音频设备之前进行清除,用户根本就毫无察觉就被获取了指纹。

以fingerprintjs2的音频指纹源码为例

  var each = function(obj, iterator) {
    if (Array.prototype.forEach && obj.forEach === Array.prototype.forEach) {
        obj.forEach(iterator)
    } else if (obj.length === +obj.length) {
        for (var i = 0, l = obj.length; i < l; i++) {
            iterator(obj[i], i, obj)
        }
    } else {
        for (var key in obj) {
            if (obj.hasOwnProperty(key)) {
                iterator(obj[key], key, obj)
            }
        }
    }
  }
  
  var AudioContext = window.OfflineAudioContext || window.webkitOfflineAudioContext

  var context = new AudioContext(1, 44100, 44100)

  var oscillator = context.createOscillator()
  oscillator.type = 'triangle'
  oscillator.frequency.setValueAtTime(10000, context.currentTime)

  var compressor = context.createDynamicsCompressor()
  each([
    ['threshold', -50],
    ['knee', 40],
    ['ratio', 12],
    ['reduction', -20],
    ['attack', 0],
    ['release', 0.25]
  ], function (item) {
    if (compressor[item[0]] !== undefined && typeof compressor[item[0]].setValueAtTime === 'function') {
      compressor[item[0]].setValueAtTime(item[1], context.currentTime)
    }
  })
  
  oscillator.connect(compressor)
  compressor.connect(context.destination)
  oscillator.start(0)
  context.startRendering()
  
  var audioTimeoutId = setTimeout(function () {
    console.warn('Audio fingerprint timed out. Please report bug at https://github.com/Valve/fingerprintjs2 with your user agent: "' + navigator.userAgent + '".')
    context.oncomplete = function () { }
    context = null
    return done('audioTimeout')
  }, 100)
  
  context.oncomplete = (event) => {
    try {
      clearTimeout(audioTimeoutId)
      audioFingerprint.value = event.renderedBuffer.getChannelData(0).slice(4500, 5000)
        .reduce(function (acc, val) { return acc + Math.abs(val) }, 0)
        .toString()
      oscillator.disconnect()
      compressor.disconnect()
      audioFingerprintHash.value = sha256(audioFingerprint.value)
    } catch (error) {
      console.log(error)
      return
    }
  }

复制代码

综合指纹

虽然以上介绍的基本指纹都不能完全唯一识别设备,但是如果我们组合他们其中的几种(取决于你的使用群体和你想识别的指纹类型)信息来再产生一个综合的指纹,这个指纹就可以近乎99%以上的准确率定位标识用户。

防范指纹技术

如果你没有足够专业的知识或者非常频繁更换浏览器信息的话,几乎100%可以通过浏览器指纹定位到一个用户 有不同的方法可以减轻浏览器指纹识别的影响,并通过防止不必要的跟踪来改善用户的隐私,但没有一种最终的方法可以防止指纹识别,同时保持现代网络浏览器的丰富性。

提供简化指纹

用户可以通过选择一种将识别信息的可用性降至最低web浏览器,如浏览器字体、设备ID、画布元素呈现、WebGL信息和本地IP地址。 截至2017年,微软Edge被认为是最具指纹识别能力的浏览器,紧随其后的是Firefox和Google Chrome、Internet Explorer和Safari。在移动浏览器中,谷歌Chrome和Opera Mini是最能识别指纹的浏览器,其次是移动Firefox、移动Edge和移动Safari。 Tor Browser禁用可指纹识别功能,如canvas和WebGL API,并通知用户指纹识别的行为。

提供伪造的指纹

在每次访问站点时,以不同的方式伪造或者干扰暴露的信息,达到降低获取指纹的稳定性。 例如使用少量随机噪声干扰声音和canvas渲染,这项技术在2020年被Brave browser采用。

屏蔽javascript脚本

盲目地阻止来自第三方域的客户端脚本,也可能是来自第一方域的脚本(例如,通过禁用JavaScript或使用NoScript),有时会导致网站无法使用。 首选的方法是只屏蔽那些似乎在跟踪人们的第三方域名,要么是因为他们被发现在跟踪域名的黑名单上。(大多数广告屏蔽插件遵循的方法)

切换不同的浏览器

同一台机器上的不同浏览器通常会有不同的指纹。

但如果两个浏览器都没有进行相关的防范指纹技术,那么这两个浏览器生成的指纹可能会被识别为来自同一台机器。

附加参考资料

测试你自己的基本指纹

你可以访问以下网址查看自己的基本指纹信息

www.whatismybrowser.com/

测试你自己的canvas指纹

你可以访问以下网址查看自己的canvas指纹信息和一些基本原理解释

browserleaks.com/canvas#how-…

一篇关于canvas指纹的文章

hovav.net/ucsd/dist/c…

测试你自己的音频指纹

你可以访问以下网址查看自己的音频指纹信息和一些基本原理解释

audiofingerprint.openwpm.com/

目前比较流行的指纹库

fingerprintjs

fingerprintjs.com/demo/

猜你喜欢

转载自juejin.im/post/7039635796495712287