context.getImageData() 操作不安全

Posted

技术标签:

【中文标题】context.getImageData() 操作不安全【英文标题】:context.getImageData() operation is insecure 【发布时间】:2013-06-06 18:30:48 【问题描述】:

我想为 html5 画布实现一个简单的灰度过滤器,但我无法将图像数据作为像素抓取。我收到来自 FF 和 Chrome 的安全警告。最后过滤器不会使图像变灰。

JS FIDLE CODE

js:

    var canvas = document.getElementById('canvas');       
var context = canvas.getContext('2d');  

var image = new Image();
image.onload = function () 
  if (image.width != canvas.width)
    canvas.width = image.width;
  if (image.height != canvas.height)
    canvas.height = image.height;
  context.clearRect(0, 0, canvas.width, canvas.height);
  context.drawImage(image, 0, 0, canvas.width, canvas.height);
  var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
  filter(imageData);
  context.putImageData(imageData, 0, 0);

image.src = "http://i0.gmx.net/images/302/17520302,pd=2,h=192,mxh=600,mxw=800,w=300.jpg";

function filter(imageData)
 var d = imageData.data;
   for (var i = 0; i < d.length; i += 4) 
     var r = d[i];
     var g = d[i + 1];
     var b = d[i + 2];
     d[i] = d[i + 1] = d[i + 2] = (r+g+b)/3;
   
return imageData;

【问题讨论】:

顺便说一句,如果你想正确处理这个错误,你应该使用try catch 【参考方案1】:

这是一项安全功能。来自W3:

getImageData(sx, sy, sw, sh) 方法必须,如果 canvas 元素的 origin-clean 标志设置为 false,则抛出 SecurityError 异常

这是为了防止恶意网站所有者将用户浏览器有权访问的潜在私人图像加载到画布上,然后将数据发送到他们自己的服务器。如果出现以下情况,可以关闭 origin-clean:

元素的 2D 上下文的 drawImage() 方法被调用的 HTMLImageElement 或 HTMLVideoElement 的来源不相同 与拥有 canvas 元素的 Document 对象一样。

元素的 2D 上下文的 drawImage() 方法是使用其 origin-clean 标志为 false 的 HTMLCanvasElement 调用的。

元素的 2D 上下文的 fillStyle 属性设置为从 HTMLImageElement 或 来源与 Document 不同的 HTMLVideoElement 创建模式时拥有画布元素的对象。

元素的 2D 上下文的 fillStyle 属性设置为 CanvasPattern 对象,该对象是从 HTMLCanvasElement 创建的,其 创建模式时 origin-clean 标志为 false。

元素的 2D 上下文的 strokeStyle 属性设置为从 HTMLImageElement 或 来源与 Document 不同的 HTMLVideoElement 创建模式时拥有画布元素的对象。

元素的 2D 上下文的 strokeStyle 属性设置为一个 CanvasPattern 对象,该对象是从一个 HTMLCanvasElement 创建的,其 创建模式时 origin-clean 标志为 false。

元素的 2D 上下文的 fillText() 或 strokeText() 方法被调用,最终使用的字体不是 与拥有 canvas 元素的 Document 对象相同。

Source

【讨论】:

那么我现在如何获取数据呢? @daisy:通过从正在加载页面的服务器获取远程图像,并让 javascript 从该服务器加载图像。这可确保您访问的是非私有图像。 添加 crossorigin="anonymous" 为我解决了这个问题 应该是image.crossOrigin = "anonymous"(大写O)。【参考方案2】:

这是一个真正解决问题的答案:

创建新图像后,使用

image.crossOrigin = "anonymous";

【讨论】:

以上是关于context.getImageData() 操作不安全的主要内容,如果未能解决你的问题,请参考以下文章

在画布getImageData周围画一个框

CORS:PHP绕过不起作用

离屏 Canvas 原理与 SpriteBuffer

有啥方法可以克隆 HTML5 画布元素及其内容?

从 wasm 修改画布

设置canvas的背景成白色