2010-03-05 8 views
86

Habe ich nicht genug Schlaf oder was? Dieser folgende CodeWarum verursacht canvas.toDataURL() eine Sicherheitsausnahme?

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

wirft diesen Fehler:

SECURITY_ERR: DOM Exception 18 

Es gibt keine Möglichkeit, dies sollte nicht funktionieren! Kann mir das bitte erklären?

+0

Hier finden Sie eine Lösung: [Wie verwendet man canvas.toDataURL(), um base64 des Bildes in Adobe AIR zu erhalten?] (Http://stackoverflow.com/q/3672332) –

+2

Diese Lösung scheint nicht sinnvoll zu sein Personen, die Adobe AIR nicht verwenden – ObscureRobot

Antwort

67

Im specs heißt es:

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.

Wenn das Bild von einem anderen Server kommt Ich glaube nicht, Sie toDataURL verwenden können()

+0

Und da ist es –

+0

Vielen Dank! wie Mike R. Ich kann mir nicht vorstellen, wie das sicherheitsbezogen sein könnte! :) – pop850

+6

Wenn ein Angreifer in der Lage ist, den Namen eines Bildes auf einer privaten Site zu erraten, könnte er eine Kopie davon erhalten, indem er sich auf eine Leinwand malt und das neue Bild an seine Site sendet. Die Haupteinschränkung besteht meines Erachtens darin, den Inhalt einer anderen Site nicht zu zeichnen, aber die Sicherheit ist zu komplex, da der Angreifer ein Loch in einer unerwarteten Site finden kann. – AlfonsoML

1

Sie können keine Leerzeichen in Ihrer ID setzen

aktualisieren

Meine Vermutung ist, dass Bild ist auf einem anderen Server als dem Sie das Skript sind ausführen. Ich konnte Ihren Fehler bei der Ausführung auf meiner eigenen Seite kopieren, aber es funktionierte in dem Moment, in dem ich ein Bild verwendete, das auf der gleichen Domain gehostet wurde. Also ist es sicherheitsbezogen - setze das Bild auf deine Seite. Wer weiß warum das so ist?

+0

Ich änderte dies und testete es, aber bekam den gleichen Fehler ... – pop850

+0

@ pop850: siehe bearbeiten – Matchu

13

scheint es eine Möglichkeit, das zu verhindern, wenn Bild Hosting der Lage, die folgenden HTTP-Header für die Bildressourcen und Browser zur Verfügung zu stellen unterstützt CORS:

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

Es sei hier erwähnt wird: http://www.w3.org/TR/cors/#use-cases

+1

access-control-allow-credentials: true funktioniert nicht mit access-control-allow-origin: *. Wenn ersteres gesetzt ist, sollte letzteres einen Ursprungswert haben, kein Wildcard-Wert von https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS –

16

Wenn das Image auf einem Host gehostet wird, der Access-Control-Allow-Origin oder Access-Control-Allow-Credentials festlegt, können Sie die Cross-Origin-Ressourcenfreigabe (CORS) verwenden. See here (the crossorigin attribute) for more details.

Ihre andere Option besteht darin, dass Ihr Server über einen Endpunkt verfügt, der ein Image abruft und bereitstellt. (z. B. http://your_host/endpoint?url=URL) Der Nachteil dieses Ansatzes ist Latenz und theoretisch unnötiges Abrufen.

Wenn es alternative Lösungen gibt, wäre ich daran interessiert, von ihnen zu hören.

+0

Hi, ich habe genau das getan, ich habe Access- Control-Allow-Origin: * auf den Bildern habe ich crossorigin = 'anonymous', dann male ich das Bild auf Canvas, dann rufe ich DataUrl auf und bekomme immer noch die SECURITY_ERR: DOM Exception 18 – skrat

+0

In Ordnung, benutze stattdessen setAttribute von img.crossorigin – skrat

17

Einstellung Quer Herkunft Attribut auf den Bildobjekten gearbeitet für mich (ich war mit 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'; 

Für die Verwendung fabricjs hier, wie 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; 
}; 
+0

Danke, es funktioniert für mich in Chrome. Ich benutze fabric.js nicht, obwohl – Philip007

+0

ich Fabricjs verwende, aber es nicht lösen konnte. Wie würdest du das mit diesem Code machen? Funktion wtd_load_bg_image (img_url) { if (img_url) { var bg_img = neues Image(); bg_img.onload = function() { canvasObj.setBackgroundImage (bg_img.src, canvasObj.renderAll.bind (canvasObj), { originX: 'links', originY: 'top', links: 0, oben : 0 }); }; bg_img.src = img_url; } } – HOY

+0

Funktioniert auch in Firefox. – vanowm

2

ich hatte patchen das gleiche Problem und alle Bilder sind in der gleichen Domäne gehostet ... Also, wenn jemand das gleiche Problem hat, hier ist, wie ich gelöst:

Ich hatte zwei Tasten: eine zu erzeugen die Leinwand und eine andere, um das Bild von der Leinwand zu erzeugen. Es hat nur für mich funktioniert, und tut mir leid, dass ich nicht weiß warum, als ich den ganzen Code auf der ersten Taste geschrieben habe. Also, wenn ich es anklicke, erzeuge die Leinwand und das Bild zur gleichen Zeit ...

Ich habe immer dieses Sicherheitsproblem, wenn die Codes auf verschiedenen Funktionen waren ...=/

0

Wenn Sie nur einige Bilder auf einer Leinwand zeichnen, stellen Sie sicher, dass Sie die Bilder aus derselben Domäne laden.

www.example.com unterscheidet sich example.com

So stellen Sie sicher, dass Ihre Bilder und die URL in der Adressleiste haben die gleichen sind, www oder nicht.

1

konnte ich es, dies mit machen arbeiten:

schreiben diese auf erste Zeile Ihres .htaccess auf Ihrem Quellserver

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

Dann, wenn ein <img> Element zu schaffen, tun Sie es wie folgt:

// 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'); 
2

Endlich fand ich die Lösung. Nur müssen die crossOrigin als dritte param in fromURL func hinzufügen

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

Wirklich hat mir mit Fabric JS geholfen, danke! – hcabral

0

ich fabric.js bin mit und könnte dies lösen, indem toDatalessJSON statt toDataURL mit:

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

Edit: Nevermind. Dies führt dazu, dass nur das Hintergrundbild in JPG exportiert wird, ohne dass die Zeichnung oben angezeigt wird, so dass es schließlich nicht ganz nützlich ist.