目录
矩形指纹
根据分辨率、字体等其他参数,绘制一个矩形,以getClientRects返回值作为参数计算指纹。该返回值是一个 DOMRect 对象,这个对象是由该元素的 getClientRects() 方法返回的一组矩形的集合,就是该元素的 CSS 边框大小。返回的结果是包含完整元素的最小矩形,并且拥有left, top, right, bottom, x, y, width, 和 height这几个以像素为单位的只读属性用于描述整个边框。除了width 和 height 以外的属性是相对于视图窗口的左上角来计算的。利用的还是不同机器在渲染上的细微差别,使得矩形信息可以作为一个识别指纹。
获取方法
参考browserleaks.com,提取的简易代码。思路很简单:
- 将一段字符串进行几何变形
- 随后获取其矩形信息
- 换算成哈希值。
主要的特征都包含在第一步,字体和字符串的选择,几何变形的参数和方法都会影响该指纹的唯一性。
let I64BIT_TABLE =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-'.split('');
let d = document.createElement("div");
let s = document.createElement("span");
d.style = ' white-space: nowrap;\n' +
' color: #5B5B5B;\n' +
' position: absolute;\n' +
' padding: 1.3333px;\n' +
' left: 10.5555px;\n' +
' top: 28.4444px;\n' +
' font-size: 24.5555px;\n' +
' -ms-transform: scale(1.31123) matrix3d(0.373513, -0.0440105, 0, -0.000202461, -0.0851682, 0.616234, 0, -0.00123197, 2.17, 0.21, 1, 0.02, 13.81, 2.11, 0, 0.98);\n' +
' -moz-transform: scale(1.31123) matrix3d(0.373513, -0.0440105, 0, -0.000202461, -0.0851682, 0.616234, 0, -0.00123197, 2.17, 0.21, 1, 0.02, 13.81, 2.11, 0, 0.98);\n' +
' -webkit-transform: scale(1.31123) matrix3d(0.373513, -0.0440105, 0, -0.000202461, -0.0851682, 0.616234, 0, -0.00123197, 2.17, 0.21, 1, 0.02, 13.81, 2.11, 0, 0.98);\n' +
' transform: scale(1.31123) matrix3d(0.373513, -0.0440105, 0, -0.000202461, -0.0851682, 0.616234, 0, -0.00123197, 2.17, 0.21, 1, 0.02, 13.81, 2.11, 0, 0.98);\n' +
' -ms-transform-origin: 0.1111px 0.2222px 0.3333px;\n' +
' -moz-transform-origin: 0.1111px 0.2222px 0.3333px;\n' +
' -webkit-transform-origin: 0.1111px 0.2222px 0.3333px;\n' +
' transform-origin: 0.1111px 0.2222px 0.3333px;'
s.innerText = 'Element.getClientRects (̿▀̿ ̿Ĺ̯̿̿▀̿ ̿)̄';
d.append(s)
document.body.appendChild(d)
let data = s.getBoundingClientRect()
console.log(data)
console.log(hash(JSON.stringify(data)))
function hash(input){
var hash = 5381;
var i = input.length - 1;
if(typeof input == 'string'){
for (; i > -1; i--)
hash += (hash << 5) + input.charCodeAt(i);
}
else{
for (; i > -1; i--)
hash += (hash << 5) + input[i];
}
var value = hash & 0x7FFFFFFF;
var retValue = '';
do{
retValue += I64BIT_TABLE[value & 0x3F];
}
while(value >>= 6);
return retValue;
}
干扰方法
-
修改默认字体
在chrome://settings/fonts中修改其中的默认配置
-
修改强制缩放比例
例如ctrl+滚轮,修改浏览器显示比例后,指纹会改变。而 puppeteer 启动参数可设置 --force-device-scale-factor=1.1
-
注入css
如修改缩放比例,不过该方法具有针对性,如browserleaks.com中,要在iframe onload之前往里面注入css。
transform: scale(0.999999);
//or
// box-sizing: border-box; //修改盒子模型会导致改指纹改变
-
重写getBoundingClientRect方法
Object.defineProperty(DOMRect.prototype, "width", {get () {return Math.random();},enumerable:true});
能起到防追踪效果,对于有指纹防伪的并不适用。暂时不知道怎么写出一个只加噪音的方式。
-
getClientRects
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];
},
'get':function(e,fun,name,index){
let d
try{
if(typeof index =="undefined"){
d = Math.floor(e[fun]()[name]);
}else{
d = Math.floor(e[fun]()[index][name]);
}
}catch (e){
console.log(e)
}
const valid = d && rand.sign() === 1;
const result = valid ? d + rand.noise() : d;
return result;
},
'value':function(d){
const valid = d && rand.sign() === 1;
const result = valid ? d + rand.noise() : d;
return result;
}
};
Object.defineProperty(HTMLElement.prototype, "getBoundingClientRect", {
value() {
let rects = this.getClientRects()[0];
console.log(rects)
let _rects = JSON.parse(JSON.stringify(rects));
let _json = {}
for (let k in _rects){
let d = rand.value(_rects[k])
_json[k] = d
Object.defineProperty(rects.__proto__, k, {get() {return d}})
}
Object.defineProperty(rects.__proto__, "toJSON", {value() {return _json}})
return rects;
},
});
相关
https://browserleaks.com/rects
getBoundingClientRect