Why does canvas.toDataURL() throw a security exception?

72,307

Solution 1

In the specs it says:

Whenever the toDataURL() method of a canvas element whose origin-clean flag is set to false is called, the method must raise a SECURITY_ERR exception.

If the image is coming from another server I don't think you can use toDataURL()

Solution 2

Setting cross origin attribute on the image objects worked for me (i was using 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';

For those using fabricjs, here's how to patch 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;
};

Solution 3

If the image is hosted on a host that sets either of Access-Control-Allow-Origin or Access-Control-Allow-Credentials, you can use Cross Origin Resource Sharing (CORS). See here (the crossorigin attribute) for more details.

Your other option is for your server to have an endpoint that fetches and serves an image. (eg. http://your_host/endpoint?url=URL) The downside of that approach being latency and theoretically unnecessary fetching.

If there are more alternate solutions, I'd be interested in hearing about them.

Solution 4

Seems there is a way to prevent that if image hosting able to provide the following HTTP headers for the image resources and browser supports CORS:

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

It is stated here: http://www.w3.org/TR/cors/#use-cases

Solution 5

Finally i found the solution. Just need add the crossOrigin as third param in fromURL func

fabric.Image.fromURL(imageUrl, function (image) {
            //your logic
    }, { crossOrigin: "Anonymous" });
Share:
72,307
pop850
Author by

pop850

Updated on February 03, 2020

Comments

  • pop850
    pop850 over 4 years

    Did I not get enough sleep or what? This following code

    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"));
    }
    

    is throwing this error:

    SECURITY_ERR: DOM Exception 18
    

    There's no way this shouldn't work! Can anyone explain this, please?

  • pop850
    pop850 about 14 years
    thanks so much! like Mike R. I can't imagine how this could be security-related! :)
  • AlfonsoML
    AlfonsoML about 14 years
    If an attacker is able to guess the name of a picture that you have in a private site, he would be able to get a copy of it by painting in on a canvas and sending the new image to his site. The main restriction from my point of view is to avoid drawing the contents of another site, but security is too complex as the attacker can find a hole in any unexpected site.
  • Sam Dutton
    Sam Dutton almost 14 years
    Note that the subdomain matters as well. In my experience, in Chrome at least, a SECURITY_ERR: DOM Exception 18 is raised when making a call that is perceived to be across subdomains: 1. in example.com/some/path/index.html for a video or image in foo.example.com 2. when going to the same page as in 1 but by entering the URL example.com/some/path/index.html and then attempting to call toDataUrl() for a video or image in www.example.com
  • kilianc
    kilianc over 12 years
    @AlfonsoML, maybe I'm wrong, but "If an attacker is able to guess the name of a picture that you have in a private site" probably he will grab the image with a curl non with a browser. My point of view: Public URL Public Content.
  • Sujay
    Sujay almost 12 years
    @pop850 I'm facing this issue even when I use a data URL. Is there a way that I can workaround this for data URLs?
  • skrat
    skrat almost 12 years
    Hi, I did just that, I have Access-Control-Allow-Origin: * on the images, I have crossorigin='anonymous', then I paint the image on canvas, then I call toDataUrl and I'm still getting the SECURITY_ERR: DOM Exception 18
  • Silver Gonzales
    Silver Gonzales almost 11 years
    access-control-allow-credentials: true will not work with access-control-allow-origin: *. When the former is set, the latter should have an origin value, not a wildcard value from developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS
  • chinna_82
    chinna_82 almost 11 years
    @Bob let say i have a canvas to hold my clipboard image. Are you saying that i cant use toDataURL()? Please advice.
  • apsillers
    apsillers almost 11 years
    @kilianc This restriction exists to prevent an attacker from causing your browser (with authentication cookies) to fetch an image and send its contents to an attacker; the attacker doesn't have your cookies, so he can't use curl to get the same resources you are authorized to get. "Public URL, Public Content" is a rather flawed way of thinking: my Facebook page has public facing components, but there is much that is only accessible with the right authentication token.
  • Philip007
    Philip007 over 10 years
    Thanks, it works for me in Chrome. I am not using fabric.js though
  • HOY
    HOY about 7 years
    I do use fabricjs but could not solve it. How would you do this with this code? function 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; } }
  • vanowm
    vanowm over 6 years
    Works in Firefox as well.
  • metamagikum
    metamagikum over 4 years
    This is the reason bur where is the soloution?