0

我想覆盖内置方法CanvasRenderingContext2D.getImageData()。我想覆盖实现,以便修改后的函数使用canvas上下文来修改画布,然后调用原始函数,该函数应该返回不同的数据,如果该函数未被覆盖。我这样做的原因是为了防止浏览器指纹。覆盖CanvasRenderingContext2D.getImageData()

canvas.js

(function(){ 
    'use strict'; 

    var originalGetImageData = CanvasRenderingContext2D.prototype.getImageData; 

    // This function just adds 1 to each RGBA component in the array for testing. 
    // Will add random values for the real thing. 
    function randomiseImageData(image) {   
     var imageData = image.data; 

     var imageLength = imageData.length; 

     for (var i = 0; i < imageLength; i++) { 
      imageData[i] += 1; 
     } 

     var modifiedImage = new ImageData(image.width, image.height); 

     return modifiedImage; 
    } 

    CanvasRenderingContext2D.prototype.getImageData = function(sx, sy, sw, sh) { 
     console.log("[ALERT] " + window.location.hostname + " called CanvasRenderingContext2D.getImageData()"); 

     const origin = window.location.hostname; 

     Math.seedrandom(origin); 

     var image = originalGetImageData.call(this, sx, sy, sw, sh); 

     return randomiseImageData(image); 
    }; 
})(); 
+0

向画布内容引入额外的熵级别将使浏览器更加独特,从而更容易识别和跟踪。 – Blindman67

回答

2

你是返回一个新的ImageData对象。

我想你想要的是返回填充的。
由于您已经修改了data数组,您可以简单地返回原始的ImageData,您的修改已经完成。

// shortened version 
 
(function(){ 
 
const ori = CanvasRenderingContext2D.prototype.getImageData; 
 
CanvasRenderingContext2D.prototype.getImageData = function(){ 
 
    let imageData = ori.apply(this, arguments); 
 
    // modify the Uint8Array 
 
    imageData.data.forEach((v, i, a) => a[i]+=1); 
 
    // return the now modified ImageData 
 
    return imageData; 
 
    }; 
 
})() 
 
    
 
var ctx = document.createElement('canvas').getContext('2d'); 
 
console.log(ctx.getImageData(0,0,1,1));

如果你真的想创建一个新的ImageData,那么它的

new ImageData(imageData, image.width, image.height); 
//    ^^ 
//   pass the data to fill the new ImageData object 

但是请注意,浏览器的支持不是很大,而且你不会赢得任何东西这样做。

+0

感谢您的帮助。问题出在我用来测试指纹的代码中,而不是我用来伪造指纹的代码。现在它全部修好了。 – Snapper26

0

您不能删除指纹。

更多The Web never forgets

你不能规避指纹。你可以做的最好的是返回最常见的指纹(这是不容易确定的),增加你可能属于的设备。

返回一组随机的像素(或每个像素通道增加一个像素)是最差的,如果你是唯一一个这样做的话。它绝对会将您的浏览器标记为独一无二的,并让traking软件知道返回更改数据的浏览器只是一个,或者是一个非常小的浏览器。

停止指纹的最好方法是通过一个通用的广泛采用的数据返回策略。如果每个浏览器都返回全零(透明黑色),那么就没有唯一性,因此无法根据画布跟踪设备。

画布指纹只是指纹的一部分,还有更多的数据来源帮助识别设备。浏览器,浏览器版本,操作系统,操作系统版本,屏幕分辨率以及其他一系列清单。即使您将画布消除为唯一的来源,除非您对其余的信息进行相同处理,否则它是毫无意义的。

缓解

所以说这样的代码来返回归零数据如下。

(function() { 
    if (window.CanvasRenderingContext2D) { 
     const gid = CanvasRenderingContext2D.prototype.getImageData; 
     CanvasRenderingContext2D.prototype.getImageData = function (x, y, w, h) { 
      var data = gid.bind(this)(x, y, w, h); 
      data.data.fill(0); // fill with zero 
      return data; 
     } 
     // Token way to avoid JS from finding out that you have overwritten the prototype overwrite 
     // the toString method as well (note ctx.getImageData.toString.toString() will 
     // still show you have changed the prototype but over writing Object.toSting is not worth the problems) 
     CanvasRenderingContext2D.prototype.getImageData.toString = function() { 
      return "function getImageData() { [native code] }"; 
     } 
    } 
}()); 
+0

我同意将每个像素加1的部分都是坏的。也许我应该更清楚地表明这只是为了测试,我会在稍后提出更好的东西。我也同意你不能阻止指纹,但是我打算做的是在每个站点和会话的基础上改变我的指纹。在这种情况下,我的指纹的独特性或共同性如何并不重要。如果您不同意,请告诉我。 – Snapper26

+0

画布指纹使用每种浏览器(和浏览器版本)呈现文本的独特方式。要模拟其他浏览器,您需要知道每个浏览器的字体,字体大小,字体对齐方式,文本使用方式,文本样式,背景像素等,所有这些对每个指纹识别服务都是唯一的。您可以捕获每个浏览器的指纹,并将所渲染的指纹替换为副本,但更智能的指纹会使这种情况变得不切实际(如果他们检测到计数器打印的话)。除非您在每次浏览时使用不同的代理,否则您将被跟踪。 – Blindman67

+0

同意所有这一切。那么如何将密码随机噪声引入每个站点和会话的图像中?由于渲染文本只是最后的像素数据。 – Snapper26