Canvas 靠同一段绘图指令在不同软硬件上的渲染差异形成标识,很少单独使用。合理的应对不是追求每次都变,而是让环境内的各项特征互相自洽。
Canvas 指纹的原理不复杂,但围绕它流传的应对办法里,有一半是反着做的。
同一段指令,不同机器画出不同结果
Canvas 是 HTML5 提供的绘图组件,网页可以用脚本在上面画图形和文字。同样的绘图指令,在不同设备上渲染出来的结果会有细微差别,差别来自操作系统、浏览器版本、字体库、显卡驱动这些底层差异。肉眼基本看不出来,但把画布内容导出成一串数据之后,差异就变成了可以比较的值。
流程大致是这样:网页先画一段图形和文字,再用 toDataURL() 把结果导出成 Base64 字符串,这个字符串就拿来当标识用。不同设备的导出结果不同,所以多数情况下它是唯一的。清 Cookie 对它没有影响,清缓存也没有。
它很少单独使用
单独一个 Canvas 值能做的事有限,而且它会随浏览器升级、驱动更新而漂移。实际使用中,Canvas 通常和一批特征打包在一起,互相校验:
- 图形相关的 WebGL、字体列表、显卡型号
- 环境相关的 UA、时区、语言、屏幕分辨率
- 会话相关的 Cookie、本地存储、网络出口
打包的原因是校验一致性。每一项单独看都可能落在正常范围内,组合起来互相矛盾就会很显眼:时区设在美国、语言列表里全是中文、Canvas 值对应的是集成显卡而 UA 报的是新款高端机型。平台不需要证明你是谁,它只需要找出这一组特征不像一台真机器。
禁用是把自己挑出来
很多人的第一反应是把 Canvas 关掉,结果正好相反。
正常用户的浏览器几乎都支持 Canvas,一个明确不支持 Canvas 的环境在统计上就是少数派,等于主动把特殊处理写在脸上。更现实的问题是,不少网站的图片裁剪、图表、验证码渲染都依赖 Canvas,关掉之后页面功能跟着出问题,异常又多一条。
还有一种做法是每次访问都换一套随机值。这个方向同样有问题:真实设备的指纹是稳定的,一个每次都在变的环境,行为模式和人不一样,反而更容易被单独拎出来标记。随机化本身就是一个可被识别的信号。
合理的方向是自洽
把目标定成环境内部各项一致、整体不异常,比每次都不同更接近真实情况。
落到操作上,是让各项特征互相支持:时区、语言、出口 IP 的地理位置要能对上,UA 声明的设备和 Canvas、WebGL 表现出的图形能力要在同一个档位。同一个账号的环境要长期稳定,重复访问时不该有明显变化。不要依赖关掉某个功能这类插件,它们往往带来更明显的特征。能少跑的第三方脚本就少跑,减少被采集的面。
几组环境之间需要彼此区分,那是环境隔离要解决的事。像 PurpleMark 这类工具做多账号环境隔离时,通常是给每个账号一套固定的环境,而不是让参数随机跳动,因为平台侧真正在意的是这组特征稳不稳定、说不说得通。
小结
Canvas 能追踪,是因为它把软硬件的细微差异变成了一串稳定可比的数字。有效的应对不是把它关掉,也不是让它乱跳,而是让它和同一环境里的其他特征讲同一个故事。看起来普通,比看起来特殊安全得多。


