目录
字体指纹技术
字体指纹技术基于测量填充文本片段或单个 Unicode 字形的 HTML 元素的屏幕尺寸。Web 浏览器中的字体渲染受许多因素影响,这些测量值可能略有不同。
获取方法
字体枚举
使用 CSS 回退机制将准备好的字体列表与默认的字体系列进行比较。渲染元素的大小与默认值不同,则表示系统中存在替换字体。通过此方法可以获取尺寸和系统字体列表,以此构建对应标识。
干扰思路
-
修改默认字体
在chrome://settings/fonts中修改其中的默认配置
-
在HTMLElement.offsetHeight和HTMLElement.offsetWidth上添加噪声
如chrome反字体指纹插件Font Fingerprint Defender所用的方法
var rand = {
"noise": function () {
var SIGN = Math.random() < Math.random() ? -1 : 1;
return Math.floor(Math.random() + SIGN * Math.random());
},
"sign": function () {
const tmp = [-1, -1, -1, -1, -1, -1, +1, -1, -1, -1];
const index = Math.floor(Math.random() * tmp.length);
return tmp[index];
}
};
Object.defineProperty(HTMLElement.prototype, "offsetHeight", {
get () {
const height = Math.floor(this.getBoundingClientRect().height);
const valid = height && rand.sign() === 1;
const result = valid ? height + rand.noise() : height;
return result;
}
});
-
修改缩放比例
例如ctrl+滚轮,修改浏览器显示比例后,指纹会改变。而 puppeteer 启动参数可设置 --force-device-scale-factor=1.1
-
字体别名
@font-face {
font-family: Alias;
src: local('Arial');
}
对于不存在的字体,可以将其名字设置成一个存在的非默认字体的别名。由于在渲染时字体大小不为默认值,会被认为存在该字体
-
引入字体
chrome在windows上启动,引用命令参数 –register-font-files 注册字体,或通过css引入字体。但需要准备好字体库。
@font-face {
font-family: Alias;
src: url('Alias font path');
}
Unicode 字形
与前者稍微不同,该方法仅使用默认字母形式作为字体系列,使用单个、专门选择的具有大字体大小的 Unicode 字符进行绘制,同样测量绘制大小,以此构建对应标识。
干扰思路
- 方法2可以复用
- 方法2可以复用
- 方法3可以复用。
- 修改窗口宽度
意外发现的,修改高度并不会影响。
经过自己测试这应该是browserleaks.com网站示例的一个失误,计算Unicode 字形宽度时,使用的时span的offsetWidth,该值在窗口宽度变化时在进行四舍五入的计算上会出现变化,使得指纹会发生变化。
(S = C[a]).textContent = l;
var u = S.offsetWidth
, s = s.offsetHeight
U+20B9 874,2112 874,2112 874,1939 710,1576 874,1939 874,1952
U+20B9 873,2112 873,2112 873,1939 709,1576 873,1939 873,1952
(S = C[a]).textContent = l;
var u = Math.round(S.getBoundingClientRect()['width'])
, s = s.offsetHeight
经测试,通过浏览器Math.round(S.getBoundingClientRect()[‘width’]) 值很稳定
Flash 接口
Flash 有一个方法可以简单地返回一组可用的系统字体。不过目前主流浏览器已经不支持,没继续了解。
参考
https://webemulator.com/tag/clientrect
https://browserleaks.com/fonts