覆盖 CanvasRenderingContext2D.getImageData()
Overriding CanvasRenderingContext2D.getImageData()
我正在尝试覆盖内置方法 CanvasRenderingContext2D.getImageData()。我想覆盖实现,以便修改后的函数使用 canvas 上下文来修改 canvas,然后调用原始函数,如果函数未被覆盖,该函数应该 return 不同的数据.我这样做的原因是为了防止浏览器指纹识别。
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);
};
})();
您正在 return 创建一个新的 空 ImageData 对象。
我猜你想要的是 return 填充的。
由于您已经修改了 data
数组,您可以简单地 return 原始 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
但请注意,浏览器支持不是很好,这样做您不会有任何收获。
您无法删除指纹。
您无法绕过指纹识别。你能做的最好的事情是 return 最常见的指纹(不容易确定)增加你可能属于的设备集。
返回一组随机像素(或将每个像素通道递增一个)如果您是唯一一个这样做的人,那将是您能做的最糟糕的事情。它绝对会将您的浏览器标记为唯一,并让追踪软件知道 return 更改数据的浏览器只是其中一个,或者是极少数浏览器中的一个。
阻止指纹识别的最佳方法是通过一种通用且广泛采用的数据 return 策略。如果每个浏览器 return 全部归零(透明黑色),那么将没有唯一性,因此无法根据 canvas.
跟踪设备
Canvas 指纹只是指纹的一部分,还有更多的数据来源可以帮助识别设备。浏览器、浏览器版本、OS、OS 版本、屏幕分辨率和一长串其他内容。即使您消除了 canvas 作为唯一性来源,它也毫无意义,除非您对其余信息执行相同的操作。
缓解
所以说 return 归零数据的代码如下。
(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] }";
}
}
}());
我正在尝试覆盖内置方法 CanvasRenderingContext2D.getImageData()。我想覆盖实现,以便修改后的函数使用 canvas 上下文来修改 canvas,然后调用原始函数,如果函数未被覆盖,该函数应该 return 不同的数据.我这样做的原因是为了防止浏览器指纹识别。
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);
};
})();
您正在 return 创建一个新的 空 ImageData 对象。
我猜你想要的是 return 填充的。
由于您已经修改了 data
数组,您可以简单地 return 原始 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
但请注意,浏览器支持不是很好,这样做您不会有任何收获。
您无法删除指纹。
您无法绕过指纹识别。你能做的最好的事情是 return 最常见的指纹(不容易确定)增加你可能属于的设备集。
返回一组随机像素(或将每个像素通道递增一个)如果您是唯一一个这样做的人,那将是您能做的最糟糕的事情。它绝对会将您的浏览器标记为唯一,并让追踪软件知道 return 更改数据的浏览器只是其中一个,或者是极少数浏览器中的一个。
阻止指纹识别的最佳方法是通过一种通用且广泛采用的数据 return 策略。如果每个浏览器 return 全部归零(透明黑色),那么将没有唯一性,因此无法根据 canvas.
跟踪设备Canvas 指纹只是指纹的一部分,还有更多的数据来源可以帮助识别设备。浏览器、浏览器版本、OS、OS 版本、屏幕分辨率和一长串其他内容。即使您消除了 canvas 作为唯一性来源,它也毫无意义,除非您对其余信息执行相同的操作。
缓解
所以说 return 归零数据的代码如下。
(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] }";
}
}
}());