1 Canvas指紋的簡介
很多網站通過Canvas指紋來跟蹤用戶。browserleaks[1]是一個在線檢測canvas指紋的網站。一般的指紋實現原理即通過canvas畫布繪製一些圖形,填寫一些文字,隨後獲取圖形的base64編碼,再經過hash後得到最終的指紋。
下面是一個簡單的例子,最終調用toDataUrl會生成一段編碼。
var getCanvasFp = function (options) {
var result = []
// Very simple now, need to make it more complex (geo shapes etc)
var canvas = document.createElement('canvas')
canvas.width = 2000
canvas.height = 200
canvas.style.display = 'inline'
var ctx = canvas.getContext('2d')
// detect browser support of canvas winding
// http://blogs.adobe.com/webplatform/2013/01/30/winding-rules-in-canvas/
// https://github.com/Modernizr/Modernizr/blob/master/feature-detects/canvas/winding.js
ctx.rect(0, 0, 10, 10)
ctx.rect(2, 2, 6, 6)
result.push('canvas winding:' + ((ctx.isPointInPath(5, 5, 'evenodd') === false) ? 'yes' : 'no'))
ctx.textBaseline = 'alphabetic'
ctx.fillStyle = '#f60'
ctx.fillRect(125, 1, 62, 20)
ctx.fillStyle = '#069'
// https://github.com/Valve/fingerprintjs2/issues/66
if (options.dontUseFakeFontInCanvas) {
ctx.font = '11pt Arial'
} else {
ctx.font = '11pt no-real-font-123'
}
ctx.fillText('Cwm fjordbank glyphs vext quiz, \ud83d\ude03', 2, 15)
ctx.fillStyle = 'rgba(102, 204, 0, 0.2)'
ctx.font = '18pt Arial'
ctx.fillText('Cwm fjordbank glyphs vext quiz, \ud83d\ude03', 4, 45)
// canvas blending
// http://blogs.adobe.com/webplatform/2013/01/28/blending-features-in-canvas/
// http://jsfiddle.net/NDYV8/16/
ctx.globalCompositeOperation = 'multiply'
ctx.fillStyle = 'rgb(255,0,255)'
ctx.beginPath()
ctx.arc(50, 50, 50, 0, Math.PI * 2, true)
ctx.closePath()
ctx.fill()
ctx.fillStyle = 'rgb(0,255,255)'
ctx.beginPath()
ctx.arc(100, 50, 50, 0, Math.PI * 2, true)
ctx.closePath()
ctx.fill()
ctx.fillStyle = 'rgb(255,255,0)'
ctx.beginPath()
ctx.arc(75, 100, 50, 0, Math.PI * 2, true)
ctx.closePath()
ctx.fill()
ctx.fillStyle = 'rgb(255,0,255)'
// canvas winding
// http://blogs.adobe.com/webplatform/2013/01/30/winding-rules-in-canvas/
// http://jsfiddle.net/NDYV8/19/
ctx.arc(75, 75, 75, 0, Math.PI * 2, true)
ctx.arc(75, 75, 25, 0, Math.PI * 2, true)
ctx.fill('evenodd')
if (canvas.toDataURL) { result.push('canvas fp:' + canvas.toDataURL()) }
return result
}
2 防止被追蹤
通過1的介紹,爲了防止被追蹤,需要對生成進行調整,這樣避免暴露自己的數據。變化的形式有很多,例如變換顏色,透明度及字體。此外canvas提供了getImageData[2]得到一個圖形的像素數據,對這裏的數據進行變化也能對結果進行變化。這裏以anticanvas[3]爲例,其它的處理方法原理類似。 下面的樣例代碼原理很簡單,就是通過對原始方法進行攔截來對當前結果改變。在編碼中通過閉包[4]保存原始方法。最終實現代理的效果,原始方法調用前對參數進行修改。
(function(){
CanvasRenderingContext2D.prototype.getImageData = function(a) {
return function() {
console.log("Context");
spoofFromContext(this,a);
return a.apply(this, arguments);
};
}(CanvasRenderingContext2D.prototype.getImageData);
HTMLCanvasElement.prototype.toDataURL=(function(){
var original = HTMLCanvasElement.prototype.toDataURL;
return function() {
spoof(this);
return original.apply(this,arguments);
};
})();
function spoof(canvas){
var ctx = canvas.getContext("2d");
spoofFromContext(ctx);
}
function spoofFromContext(ctx,a){
if(!a) a = ctx.getImageData;
var data = a.call(ctx,0, 0, ctx.canvas.width, ctx.canvas.height);
for(var c=0; c<data.data.length; c=c+4){
var r = data.data[c];
var g = data.data[c+1];
var b = data.data[c+2];
var a = data.data[c+3];
if(a!=0){
data.data[c]=r-Math.random();
data.data[c+1]=g-Math.random();
data.data[c+2]=b-Math.random();
data.data[c+3]=a-Math.random();
}
}
ctx.putImageData(data, 0, 0);
console.log("Spoofed");
}
})();
3參考
[1].canvas指紋,https://browserleaks.com/canvas#how-does-it-work
[2].getImageData使用簡介,https://blog.csdn.net/FE_dev/article/details/82586698
[3].anticanvas,https://github.com/WolfspiritM/AntiCF/blob/master/anticanvas.js
[4].JS閉包http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html