被跨域数据污染的画布

Posted

技术标签:

【中文标题】被跨域数据污染的画布【英文标题】:Canvas tainted by cross-origin data 【发布时间】:2012-11-20 10:07:46 【问题描述】:

我正在从我可以信任的第三方网站加载动态 jpeg。我正在尝试getImageData(),但浏览器(Chrome 23.0)抱怨说:

Unable to get image data from canvas because the canvas has been tainted by
cross-origin data.

关于 SO 有一些类似的问题,但他们使用的是本地文件,而我使用的是第三方媒体。我的脚本在共享服务器上运行,我不拥有远程服务器。

我尝试了img.crossOrigin = 'Anonymous'img.crossOrigin = ''(参见this post on the Chromium blog about CORS),但没有帮助。关于如何在具有跨域数据的画布上getImageData 的任何想法?谢谢!

【问题讨论】:

也许你信任那个 3rd 方网站,但是用户没有办法告诉 3rd 方网站信任你。您的脚本可以从 3rd 方网站中提取图像,该图像仅供用户访问而您无法访问(可能是因为它仅对注册用户可用且用户已登录)。然后,该脚本可以将该图像数据转发到您自己的服务器并为您提供非法访问权限。 【参考方案1】:

crossOrigin 标志一旦被污染就无法重置,但如果您事先知道图像是什么,则可以将其转换为数据 url,请参阅Drawing an image from a data URL to a canvas

但是不,您不能也不应该使用来自不支持 CORS 的外部来源的 getImageData()

【讨论】:

感谢您的回复。不确定我们是否可以将toDataURL() 应用于mjpeg,但我会试一试。为什么没有?安全原因?是否有具体配置外部服务器应该做的?或者即使他们没有那个配置,我也可以使用 toDataURL 来做到这一点。 这是一个相当全面的 CORS 支持指南html5rocks.com/en/tutorials/cors。是的,这是一个很大的安全问题。 即使使用 CORS 也能工作吗?我没有成功。 我如何事先了解?想象一下,你有一个<img> 标签,但你不知道它是什么......你怎么知道你是否可以绘制它,或者你是否需要使用crossorigin="anonymous" 加载它? @TomášZato 你不知道,因为这正是 CORS 试图阻止的。它应该只允许如果您事先知道图像是什么以及它是否安全。【参考方案2】:

虽然这个问题已经很老了,但问题仍然存在,而且网络上几乎没有什么可以解决的。我想出了一个我想分享的解决方案:

您可以先使用不设置crossorigin 属性的图像(或视频),然后测试您是否可以通过AJAX 向同一资源发送HEAD 请求。如果失败,您将无法使用该资源。如果成功,您可以添加属性并重新设置图像/视频的来源,并附上时间戳以重新加载它。

此解决方法允许您向用户显示您的资源,并在不支持 CORS 时简单地隐藏一些功能。

HTML:

<img id="testImage" src="path/to/image.png?_t=1234">

javascript

var target = $("#testImage")[0];
    currentSrcUrl = target.src.split("_t=").join("_t=1"); // add a leading 1 to the ts
$.ajax(
    url: currentSrcUrl,
    type:'HEAD',
    withCredentials: true
)
.done(function() 
    // things worked out, we can add the CORS attribute and reset the source
    target.crossOrigin = "anonymous";
    target.src = currentSrcUrl;
    console.warn("Download enabled - CORS Headers present or not required");
    /* show make-image-out-of-canvas-functions here */
)
.fail(function() 
    console.warn("Download disabled - CORS Headers missing");
    /* ... or hide make-image-out-of-canvas-functions here */
);

在 IE10+11 和当前的 Chrome 31、FF25、Safari 6(桌面)中测试和工作。 在 IE10 和 FF 中,当且仅当您尝试从 https 脚本访问 http 文件时,您可能会遇到问题。我还不知道有什么解决方法。

2014 年 1 月更新:

为此所需的 CORS 标头应如下所示(Apache 配置语法):

Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Headers "referer, range, accept-encoding, x-requested-with"

仅 ajax 请求需要 x-header。据我所知,大多数浏览器都没有使用它

【讨论】:

感谢您的回复。所以对于“工作”,你的意思是可以在这个外部资源上做getImageData?如果我们按照您提到的解决方法。 旧答案,但请注意,反过来似乎更容易:首先设置 img 标签的 crossOrigin,监听其error 事件处理程序,设置远程 src,如果它触发,你知道你会污染画布。【参考方案3】:

另外值得注意的是,如果您在本地工作,无论资源是否与您正在使用的 index.html 文件位于同一目录中,CORS 都将适用。对我来说,这意味着当我将它上传到我的服务器时,CORS 问题就消失了,因为它有一个域。

【讨论】:

这是正确的,因为我遇到了同样的问题。我正在使用 phpstorm 来查看它,它本身使用了一个模拟服务器并且可以工作。 我在本地工作,在我的工作文件夹中使用python -m http.server port 8080,然后访问http://localhost:8080 对于 PHP,您可以使用 php --server localhost:8080 @Noumenon,为 python 服务器提示 +1【参考方案4】:

您可以在画布上使用 base64 的图像, 转换为 base64 时,您可以在图像路径前使用代理 URL (https://cors-anywhere.herokuapp.com/) 以避免跨域问题

在此处查看完整的详细信息

https://***.com/a/44199382/5172571

var getDataUri = function (targetUrl, callback) 
    var xhr = new XMLHttpRequest();
    xhr.onload = function () 
        var reader = new FileReader();
        reader.onloadend = function () 
            callback(reader.result);
        ;
        reader.readAsDataURL(xhr.response);
    ;
    var proxyUrl = 'https://cors-anywhere.herokuapp.com/';
    xhr.open('GET', proxyUrl + targetUrl);
    xhr.responseType = 'blob';
    xhr.send();
;
getDataUri(path, function (base64) 
    // base64 availlable here
)

【讨论】:

以上是关于被跨域数据污染的画布的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法确定跨域图像是不是会在不绘制画布的情况下污染画布?

使用 Chrome 在画布上本地绘制图像

Firefox 跨域图像被污染

json跨域解决方案-jsonp

Spring Boot 中处理跨域

跨域资源共享(Cross-Origin Resource Sharing)