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

pop*_*850 88 javascript html5 canvas cross-domain

我睡眠不足还是什么?以下代码

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"));
}
Run Code Online (Sandbox Code Playgroud)

抛出这个错误:

SECURITY_ERR: DOM Exception 18
Run Code Online (Sandbox Code Playgroud)

这不可能不起作用!请问有人解释一下吗?

Bob*_*Bob 67

规格中它说:

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

如果图像来自另一台服务器,我认为你不能使用toDataURL()

  • 如果攻击者能够猜出你在私人网站上拥有的图片的名称,他就可以通过在画布上绘画并将新图像发送到他的网站来获得它的副本.从我的观点来看,主要限制是避免绘制另一个站点的内容,但安全性太复杂,因为攻击者可以在任何意外站点中找到漏洞. (6认同)
  • @kilianc这个限制的存在是为了防止攻击者使用*your*浏览器(带有身份验证cookie)来获取图像并将其内容发送给攻击者; 攻击者没有你的cookie,所以他不能使用curl来获得你被授权获得的相同资源."公共URL,公共内容"是一种相当有缺陷的思维方式:我的Facebook页面具有面向公众的组件,但有很多只能通过正确的身份验证令牌访问. (5认同)
  • @ pop850即使我使用数据URL,我也面临这个问题.有没有办法解决这个数据网址? (4认同)
  • 请注意,子域也很重要.根据我的经验,至少在Chrome中,在进行跨子域的调用时会引发SECURITY_ERR:DOM异常18:1.在http://www.example.com/some/path/index.html中foo.example.com中的视频或图像2.当转到与1中相同的页面但输入URL http://example.com/some/path/index.html然后尝试调用toDataUrl() www.example.com上的视频或图片 (3认同)
  • @AlfonsoML,也许我错了,但是"如果攻击者能够猜到你在私人网站上拥有的图片的名称",他可能会用浏览器非卷曲来抓取图像.我的观点:公共URL公共内容. (3认同)

Phi*_*nyy 17

在图像对象上设置cross origin属性对我有用(我使用的是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';
Run Code Online (Sandbox Code Playgroud)

对于那些使用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;
};
Run Code Online (Sandbox Code Playgroud)


Jam*_*ter 16

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

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

如果有更多替代解决方案,我会有兴趣听到它们.


Dit*_*Sky 13

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

access-control-allow-origin: *
access-control-allow-credentials: true

这里说明:http://www.w3.org/TR/cors/#use-cases