为什么canvas.toDataURL()抛出安全异常?


90

我睡眠不足吗?以下代码

var frame=document.getElementById("viewer");
frame.width=100;
frame.height=100;

var ctx=frame.getContext("2d");
var img=new Image();
img.src="http://www.ansearch.com/images/interface/item/small/image.png"

img.onload=function() {
    // draw image
    ctx.drawImage(img, 0, 0)

    // Here's where the error happens:
    window.open(frame.toDataURL("image/png"));
}

抛出此错误:

SECURITY_ERR: DOM Exception 18

这是绝对不可能的!有人可以解释一下吗?



2
对于不使用Adobe AIR的人来说,该解决方案似乎没有用。
ObscureRobot 2013年

Answers:


67

规格中它说:

每当调用其origin-clean标志设置为false的canvas元素的toDataURL()方法时,该方法都必须引发SECURITY_ERR异常。

如果图像来自其他服务器,我认为您不能使用toDataURL()


6
如果攻击者能够猜出您在私人站点中拥有的图片名称,则可以通过在画布上绘画并将新图像发送到他的站点来获得该副本的副本。在我看来,主要限制是避免绘制其他站点的内容,但是安全性太复杂了,因为攻击者可以在任何意外站点中发现漏洞。
AlfonsoML 2010年

3
请注意,子域也很重要。以我的经验,至少在Chrome中,进行跨子域的通话时会引发SECURITY_ERR:DOM异常18:1.在example.com/some/path/index.html中,用于foo中的视频或图像.example.com 2.转到与1中相同的页面时,但输入URL example.com/some/path/index.html,然后尝试在www.example.com中为视频或图像调用toDataUrl()
山姆·达顿 Sam Dutton)2010年

3
@AlfonsoML,也许我是错的,但是“如果攻击者能够猜出您在私人站点中拥有的图片的名称”,他可能会使用浏览器而不是curl来获取图片。我的观点:公共URL公共内容。
kilianc 2012年

4
@ pop850即使使用数据URL,我也面临此问题。有没有一种方法可以解决此数据URL?
Sujay 2012年

6
@kilianc存在此限制是为了防止攻击者导致您的浏览器(带有身份验证Cookie)获取图像并将其内容发送给攻击者;攻击者没有您的cookie,因此他无法使用curl获得您被授权获取的相同资源。“公共URL,公共内容”是一种相当有缺陷的思维方式:我的Facebook页面具有面向公众的组件,但是只有使用正确的身份验证令牌才能访问很多内容。
apsillers 2013年

18

在对我有用的图像对象上设置跨原点属性(我正在使用fabricjs)

    var c = document.createElement("img");
    c.onload=function(){
        // add the image to canvas or whatnot
        c=c.onload=null
    };
    c.setAttribute('crossOrigin','anonymous');
    c.src='http://google.com/cat.png';

对于使用fabricjs的用户,以下是修补Image.fromUrl的方法

// patch fabric for cross domain image jazz
fabric.Image.fromURL=function(d,f,e){
    var c=fabric.document.createElement("img");
    c.onload=function(){
        if(f){f(new fabric.Image(c,e))}
        c=c.onload=null
    };
    c.setAttribute('crossOrigin','anonymous');
    c.src=d;
};

谢谢,它在Chrome中对我有效。我没有使用fabric.js
Philip007

我确实使用fabricjs,但无法解决。您将如何使用此代码执行此操作?函数wtd_load_bg_image(img_url){if(img_url){var bg_img = new Image(); bg_img.onload = function(){canvasObj.setBackgroundImage(bg_img.src,canvasObj.renderAll.bind(canvasObj),{originX:'left',originY:'top',left:0,top:0}); }; bg_img.src = img_url; }
HOY

也可以在Firefox中使用。
vanowm

16

如果映像托管在设置了Access-Control-Allow-Origin或Access-Control-Allow-Credentials的主机上,则可以使用跨源资源共享(CORS)。有关更多详细信息,请参见此处(crossorigin属性)。

您的另一个选择是使服务器具有可获取并提供映像的端点。(例如,http:// your_host / endpoint?url = URL)这种方法的缺点是延迟和理论上不必要的获取。

如果还有其他替代解决方案,那么我很想听听它们。


嗨,我就是这样做的,我有Access-Control-Allow-Origin:*在图像上,我有crossorigin ='anonymous',然后将图像绘制在画布上,然后调用toDataUrl,但仍然得到SECURITY_ERR :DOM例外18
skrat 2012年

13

似乎有一种方法可以防止如果图像托管能够为图像资源提供以下HTTP标头并且浏览器支持CORS:

访问控制允许来源:*
访问控制允许凭证:true

声明如下:http : //www.w3.org/TR/cors/#use-cases


1
access-control-allow-credentials:true不适用于access-control-allow-origin:*。设置前者后,后者应具有原始值,而不是来自developer.mozilla.org/zh-CN/docs/HTTP/Access_control_CORS
Silver Gonzales 2013年

4

终于我找到了解决方案。只需要crossOriginfromURLfunc中添加as作为第三个参数

fabric.Image.fromURL(imageUrl, function (image) {
            //your logic
    }, { crossOrigin: "Anonymous" });

2

我遇到了同样的问题,所有图像都托管在同一个域中...因此,如果有人遇到同样的问题,请按照以下步骤解决:

我有两个按钮:一个用于生成画布,另一个用于从画布生成图像。它只对我有用,很抱歉,当我在第一个按钮上编写所有代码时,我不知道为什么。因此,当我单击它时,会同时生成画布和图像...

当代码具有不同的功能时,我总是会遇到此安全问题... = /


2

我可以使用以下方法使其工作:

将其写在.htaccess源服务器的第一行

Header add Access-Control-Allow-Origin "*"

然后,在创建<img>元素时,请执行以下操作:

// jQuery
var img = $('<img src="http://your_server/img.png" crossOrigin="anonymous">')[0]

// or pure
var img = document.createElement('img');
img.src='http://your_server/img.png';
img.setAttribute('crossOrigin','anonymous');

1

您不能在ID中放置空格

更新资料

我的猜测是图像与执行脚本的位置不同。在我自己的页面上运行该错误时,我能够复制该错误,但是当我使用在同一域中托管的映像时,它可以正常工作。因此,这与安全性相关-将图片放在您的网站上。有人知道为什么会这样吗?


0

如果只是在画布上绘制一些图像,请确保从同一域中加载图像。

www.example.comexample.com不同

因此,请确保您的图片和地址栏中的网址相同,无论www与否。


0

我正在使用fabric.js,可以通过使用toDatalessJSON而不是toDataURL来解决此问题:

canvas.toDatalessJSON({ format: 'jpeg' }).objects[0].src

编辑:没关系。这导致仅将背景图像导出为JPG,而顶部则没有图形,因此它毕竟不是完全有用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.