如何修复 getImageData() 错误画布已被跨域数据污染?

IT技术 javascript html html5-canvas
2021-01-21 06:05:25

我的代码在我的本地主机上运行良好,但在站点上不起作用。

对于这一行,我从控制台收到此错误.getImageData(x,y,1,1).data

Uncaught SecurityError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data. 

我的代码的一部分:

jQuery.Event.prototype.rgb=function(){
        var x =  this.offsetX || (this.pageX - $(this.target).offset().left),y =  this.offsetY || (this.pageY - $(this.target).offset().top);
        if (this.target.nodeName!=="CANVAS")return null;
        return this.target.getContext('2d').getImageData(x,y,1,1).data;
    }

注意:我的图像 url (src) 来自子域 url

6个回答

正如其他人所说,您通过从跨域域加载来“污染”画布。

https://developer.mozilla.org/en-US/docs/HTML/CORS_Enabled_Image

但是,您可以通过简单地设置来防止这种情况:

img.crossOrigin = "Anonymous";

这仅在远程服务器适当设置以下标头时才有效:

Access-Control-Allow-Origin "*"

使用“直接链接”选项时Dropbox 文件选择器就是一个很好的例子。我在oddprints.com使用它来将远程保管箱图像url 中的图像缓存到我的画布中,然后将图像数据提交回我的服务器。全部在 JavaScript 中

如果它是本地文件,而您的应用根本不使用互联网怎么办?就像 android webview 应用程序一样,图像与 html 文件位于同一文件夹中。这解决不了。
2021-03-20 06:05:25
这有助于在将 imgur 图像加载到 jsfiddle.net 时修复此错误
2021-03-21 06:05:25
如果我先放置 crossorigin 然后设置源然后访问数据 onload 对我有用
2021-04-07 06:05:25

我发现我必须使用.setAttribute('crossOrigin', '')并且必须在 URL 的查询字符串中附加一个时间戳,以避免 304 响应缺少Access-Control-Allow-Origin标头。

这给了我

var url = 'http://lorempixel.com/g/400/200/';
var imgObj = new Image();
imgObj.src = url + '?' + new Date().getTime();
imgObj.setAttribute('crossOrigin', '');
只需使用即可imgObj.setAttribute('crossOrigin', '')为我解决 - 谢谢!img.crossOrigin = "Anonymous"也能工作(正如这里提到的)。@SanfordStaab 浏览器将本地文件视为位于不同域中,否则网站所有者可以读取您的本地文件。您需要从同一个域请求图像,或者响应您请求的标头需要告诉浏览器其他域的代码可以读取该文件。
2021-04-09 06:05:25
在没有本地文件服务器的情况下尝试此操作会得到:从源“null”访问“file:///C:/.../img/colorPaletteCtrl.png?1507058959277”的图像已被 CORS 策略阻止:无效响应. 因此,不允许访问 Origin 'null'。
2021-04-10 06:05:25

您将无法直接从另一台服务器将图像绘制到画布中,然后使用getImageData. 这是一个安全问题,画布将被视为“受污染”。

使用 PHP 将图像的副本保存到服务器然后加载新图像对您有用吗?例如,您可以将 URL 发送到 PHP 脚本并将其保存到您的服务器,然后将新文件名返回到您的 javascript,如下所示:

<?php //The name of this file in this example is imgdata.php

  $url=$_GET['url'];

  // prevent hackers from uploading PHP scripts and pwning your system
  if(!@is_array(getimagesize($url))){
    echo "path/to/placeholderImage.png";
    exit("wrong file type.");
  }

  $img = file_get_contents($url);

  $fn = substr(strrchr($url, "/"), 1);
  file_put_contents($fn,$img);
  echo $fn;

?>

您将使用带有一些 ajax javascript 的 PHP 脚本,如下所示:

xi=new XMLHttpRequest();
xi.open("GET","imgdata.php?url="+yourImageURL,true);
xi.send();

xi.onreadystatechange=function() {
  if(xi.readyState==4 && xi.status==200) {
    img=new Image;
    img.onload=function(){ 
      ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
    }
    img.src=xi.responseText;
  }
}

如果您getImageData之后在画布上使用,它将正常工作。

或者,如果您不想保存整个图像,您可以将 x 和 y 坐标传递给您的 PHP 脚本并计算该侧像素的 rgba 值。我认为有很好的库可以在 PHP 中进行这种图像处理。

如果您想使用这种方法,请告诉我您是否需要帮助实现它。

编辑 1:peeps 指出 php 脚本已暴露并允许互联网潜在地恶意使用它。有一百万种方法可以解决这个问题,最简单的方法之一是某种 URL 混淆......我认为安全的 php 实践值得单独的谷歌;P

编辑 2:根据大众需求,我添加了一个检查以确保它是图像而不是 php 脚本(来自:PHP 检查文件是否为图像)。

这不是很安全,有人可能会使用 php 脚本恶意地用大文件淹没您的服务器,这会很糟糕
2021-03-22 06:05:25
您需要验证用户提供的上传文件名、文件/mime 类型、位置和大小。此代码容易受到多种攻击。我将把它留给读者作为练习,但我相信可以使用此代码将 .php 文件上传到网络服务器的根目录。
2021-03-24 06:05:25
由于这种方法,还可以在不使用 node.js 的情况下将图像传递给 tesseract.js OCR 引擎(只需在 img.onload() 函数中添加对 Tesseract.recognize(img) 的调用。
2021-04-03 06:05:25
另外 - 从本地文件系统加载图像和脚本,会产生同样的问题。
2021-04-04 06:05:25
@LAX1DUDE 通过简单的安全检查改进了答案
2021-04-08 06:05:25

我在Chrome本地测试我的代码时看到了这个错误我切换到Firefox,我不再看到错误。也许切换到另一个浏览器是一个快速解决方案。

如果您使用的是第一个答案中给出的解决方案,请确保img.crossOrigin = "Anonymous";在声明img变量后立即添加(例如。var img = new Image();)。

在本地工作时添加服务器

我在本地工作时遇到了类似的问题。您的 url 将成为本地文件的路径,例如 file:///Users/PeterP/Desktop/folder/index.html。

请注意,我使用的是 MAC。

我通过在全球安装 http-server 来解决这个问题。https://www.npmjs.com/package/http-server

脚步:

  1. 全局安装: npm install http-server -g
  2. 运行服务器: http-server ~/Desktop/folder/

PS:我假设你已经安装了节点,否则你将无法运行 npm 命令。

我很欣赏这个。很好的工作。糟糕的是,如果您只想将编码作为一种爱好并让您的生活更轻松,更美好,那么必须有一个解决方法。这么多看起来没有必要的箍。这只是一个例子。叹...
2021-03-16 06:05:25