Perché canvas.toDataURL () genera un'eccezione di sicurezza?


90

Non ho dormito abbastanza o cosa? Questo codice seguente

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

sta generando questo errore:

SECURITY_ERR: DOM Exception 18

Non è possibile che questo non funzioni! Qualcuno può spiegarlo, per favore?



2
Questa soluzione non sembra utile alle persone che non utilizzano Adobe AIR.
ObscureRobot

Risposte:


67

Nelle specifiche dice:

Ogni volta che viene chiamato il metodo toDataURL () di un elemento canvas il cui flag origin-clean è impostato su false, il metodo deve sollevare un'eccezione SECURITY_ERR.

Se l'immagine proviene da un altro server non penso che tu possa usare toDataURL ()


6
Se un utente malintenzionato è in grado di indovinare il nome di un'immagine che hai in un sito privato, potrebbe ottenerne una copia dipingendo su una tela e inviando la nuova immagine al suo sito. Il limite principale dal mio punto di vista è evitare di disegnare i contenuti di un altro sito, ma la sicurezza è troppo complessa in quanto l'attaccante può trovare un buco in qualsiasi sito imprevisto.
AlfonsoML

3
Nota che anche il sottodominio è importante. Nella mia esperienza, almeno in Chrome, viene sollevata un'eccezione SECURITY_ERR: DOM 18 quando si effettua una chiamata che viene percepita come attraverso sottodomini: 1. in example.com/some/path/index.html per un video o un'immagine in foo .example.com 2. quando si accede alla stessa pagina di 1 ma inserendo l'URL example.com/some/path/index.html e quindi tentando di chiamare toDataUrl () per un video o un'immagine in www.example.com
Sam Dutton

3
@AlfonsoML, forse mi sbaglio, ma "Se un attaccante riesce a indovinare il nome di un'immagine che hai in un sito privato" probabilmente afferrerà l'immagine con un ricciolo non con un browser. Il mio punto di vista: URL pubblico Contenuto pubblico.
kilianc

4
@ pop850 Sto affrontando questo problema anche quando utilizzo un URL di dati. C'è un modo per risolvere questo problema per gli URL di dati?
Sujay

6
@kilianc Questa restrizione esiste per impedire a un utente malintenzionato di far sì che il browser (con cookie di autenticazione) recuperi un'immagine e invii il suo contenuto a un utente malintenzionato; l'attaccante non ha i tuoi cookie, quindi non può utilizzare curl per ottenere le stesse risorse che sei autorizzato a ottenere. "URL pubblico, contenuto pubblico" è un modo di pensare piuttosto imperfetto: la mia pagina Facebook ha componenti rivolti al pubblico, ma c'è molto che è accessibile solo con il giusto token di autenticazione.
apsillers

18

L'impostazione dell'attributo cross origin sugli oggetti immagine ha funzionato per me (stavo usando 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';

Per coloro che utilizzano fabricjs, ecco come applicare la patch a 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;
};

Grazie, funziona per me in Chrome. Tuttavia, non sto usando fabric.js
Philip007

Uso fabricjs ma non sono riuscito a risolverlo. Come faresti con questo codice? funzione 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

Funziona anche in Firefox.
vanowm

16

Se l'immagine è ospitata su un host che imposta Access-Control-Allow-Origin o Access-Control-Allow-Credentials, puoi utilizzare Cross Origin Resource Sharing (CORS). Vedi qui (l'attributo crossorigin) per maggiori dettagli.

L'altra opzione è che il tuo server abbia un endpoint che recupera e fornisce un'immagine. (es. http: // your_host / endpoint? url = URL ) Lo svantaggio di questo approccio è la latenza e il recupero teoricamente non necessario.

Se ci sono più soluzioni alternative, sarei interessato a saperne di più.


Ciao, ho fatto proprio questo, ho Access-Control-Allow-Origin: * sulle immagini, ho crossorigin = 'anonymous', quindi dipingo l'immagine su tela, quindi chiamo toDataUrl e ottengo ancora SECURITY_ERR : Eccezione DOM 18
skrat

13

Sembra che ci sia un modo per impedirlo se l'hosting di immagini è in grado di fornire le seguenti intestazioni HTTP per le risorse di immagine e il browser supporta CORS:

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

È indicato qui: http://www.w3.org/TR/cors/#use-cases


1
access-control-allow-credentials: true non funzionerà con access-control-allow-origin: *. Quando il primo è impostato, il secondo dovrebbe avere un valore di origine, non un valore jolly da developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS
Silver Gonzales

4

Finalmente ho trovato la soluzione. Basta aggiungere il crossOriginterzo parametro in fromURLfunc

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

2

Ho avuto lo stesso problema e tutte le immagini sono ospitate nello stesso dominio ... Quindi, se qualcuno sta avendo lo stesso problema, ecco come ho risolto:

Avevo due pulsanti: uno per generare la tela e un altro per generare l'immagine dalla tela. Ha funzionato solo per me, e mi dispiace di non sapere perché, quando ho scritto tutto il codice sul primo pulsante. Quindi, quando lo clicco, generi la tela e l'immagine allo stesso tempo ...

Ho sempre questo problema di sicurezza quando i codici erano su funzioni diverse ... = /


2

Sono stato in grado di farlo funzionare usando questo:

Scrivilo sulla prima riga del tuo .htaccess server di origine

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

Quindi, quando crei un <img>elemento, fallo come segue:

// 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

Non puoi inserire spazi nel tuo ID

Aggiornare

La mia ipotesi è che l'immagine si trovi su un server diverso da quello in cui stai eseguendo lo script. Sono stato in grado di duplicare il tuo errore eseguendolo sulla mia pagina, ma ha funzionato bene nel momento in cui ho utilizzato un'immagine ospitata sullo stesso dominio. Quindi è legato alla sicurezza: metti l'immagine sul tuo sito. Qualcuno sa perché questo è il caso?


0

Se stai semplicemente disegnando alcune immagini su una tela, assicurati di caricare le immagini dallo stesso dominio.

www.example.com è diverso da example.com

Quindi assicurati che le tue immagini e l'URL che hai nella barra degli indirizzi siano gli stessi, www o no.


0

Sto usando fabric.js e potrei risolverlo usando toDatalessJSON invece di toDataURL:

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

Modifica: non importa. Ciò si traduce in solo l'immagine di sfondo esportata in JPG, senza il disegno in alto, quindi non è stato del tutto utile, dopotutto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.