Canvas.toDataURL () neden bir güvenlik istisnası atıyor?


90

Yeterince uyumadım mı ne? Bu aşağıdaki kod

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

bu hatayı atıyor:

SECURITY_ERR: DOM Exception 18

Bunun işe yaramamasına imkan yok! Biri bunu açıklayabilir mi lütfen?



2
Bu çözüm, Adobe AIR kullanmayanlar için yararlı görünmüyor.
ObscureRobot

Yanıtlar:


68

Gelen özellikleri şöyle der:

Origin-clean bayrağı false olarak ayarlanmış bir tuval öğesinin toDataURL () yöntemi her çağrıldığında, yöntemin bir SECURITY_ERR istisnası oluşturması gerekir.

Görüntü başka bir sunucudan geliyorsa, toDataURL () kullanabileceğinizi sanmıyorum


6
Bir saldırgan, özel bir sitede sahip olduğunuz bir resmin adını tahmin edebilirse, bir tuvale boyayarak ve yeni resmi sitesine göndererek bir kopyasını elde edebilir. Benim bakış açıma göre ana kısıtlama, başka bir sitenin içeriğini çizmekten kaçınmaktır, ancak saldırgan beklenmedik herhangi bir sitede bir delik bulabileceğinden güvenlik çok karmaşıktır.
AlfonsoML

3
Alt alan adının da önemli olduğunu unutmayın. Tecrübelerime göre, en azından Chrome'da, alt etki alanlarında olduğu algılanan bir arama yapılırken SECURITY_ERR: DOM İstisnası 18 ortaya çıkıyor: 1. foo'daki bir video veya resim için example.com/some/path/index.html .example.com 2. 1'deki ile aynı sayfaya giderken, ancak example.com/some/path/index.html URL'sini girip ardından www.example.com'daki bir video veya görüntü için toDataUrl () 'yi çağırmaya çalışırken
Sam Dutton

3
@AlfonsoML, belki yanılıyorum, ama "Eğer bir saldırgan özel bir sitede sahip olduğunuz bir resmin adını tahmin edebiliyorsa" muhtemelen bir tarayıcı ile bir curl non ile görüntüyü yakalayacaktır. Benim bakış açım: Genel URL Genel İçerik.
kilianc

4
@ pop850 Bir veri URL'si kullandığımda bile bu sorunla karşılaşıyorum. Veri URL'leri için bunu geçici olarak çözebilmemin bir yolu var mı?
Sujay

6
@kilianc Bu kısıtlama yol açmasını ataklara karşı korumak için var senin bir görüntü alıp bir saldırgana içeriğini göndermek için (kimlik doğrulama kurabiye) tarayıcısını; saldırgan sizin tanımlama bilgilerinize sahip değildir, bu yüzden almaya yetkili olduğunuz kaynakları almak için curl'yi kullanamaz. "Genel URL, Herkese Açık İçerik" oldukça kusurlu bir düşünme biçimidir: Facebook sayfamın herkese açık bileşenleri var, ancak yalnızca doğru kimlik doğrulama jetonuyla erişilebilen pek çok şey var.
apsillers

18

Benim için çalıştı görüntü nesnelerinde çapraz başlangıç ​​niteliği ayarlama (fabricjs kullanıyordum)

    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 kullananlar için Image.fromUrl'ye nasıl yama yapacağınız aşağıda açıklanmıştır.

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

Teşekkürler, Chrome'da benim için çalışıyor. Yine de
fabric.js

Fabricjs kullanıyorum ama çözemedim. Bunu bu kodla nasıl yaparsınız? 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; }}
HOY

Firefox'ta da çalışıyor.
vanowm

16

Görüntü Erişim-Kontrol-İzin Verme veya Erişim-Kontrol-İzin Verme-Kimlik Bilgilerini ayarlayan bir ana bilgisayarda barındırılıyorsa, Çapraz Kaynak Paylaşımı'nı (CORS) kullanabilirsiniz. Daha fazla ayrıntı için buraya bakın (crossorigin niteliği).

Diğer seçeneğiniz, sunucunuzun bir görüntüyü getiren ve sunan bir uç noktaya sahip olmasıdır. (ör. http: // your_host / endpoint? url = URL ) Bu yaklaşımın dezavantajı gecikme ve teorik olarak gereksiz getirmedir.

Daha alternatif çözümler varsa, bunları duymak isterim.


Merhaba, tam da bunu yaptım, Access-Control-Allow-Origin: * görüntülerde crossorigin = 'anonymous' var, sonra resmi tuval üzerine boyadım, sonra toDataUrl'yi çağırıyorum ve hala SECURITY_ERR alıyorum : DOM İstisnası 18
skrat

13

Görünüşe göre, görüntü barındırma, görüntü kaynakları için aşağıdaki HTTP başlıklarını sağlayabiliyorsa ve tarayıcı CORS'u desteklediğinde bunu engellemenin bir yolu var gibi görünüyor:

erişim denetimi izin ver: *
erişim denetimi izin verme kimlik bilgileri: doğru

Burada belirtilmiştir: http://www.w3.org/TR/cors/#use-cases


1
access-control-allow-credentials: true, access-control-allow-origin: * ile çalışmaz. Birincisi ayarlandığında, ikincisi bir başlangıç ​​değerine sahip olmalı, developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS
Silver Gonzales

4

Sonunda çözümü buldum. Sadece eklemek gerek crossOriginüçüncü param olarak fromURLfonk

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

2

Aynı sorunu yaşadım ve tüm resimler aynı etki alanında barındırılıyor ... Yani, biri aynı sorunu yaşıyorsa, işte böyle çözdüm:

İki düğmem vardı: biri tuvali oluşturmak için, diğeri ise tuvalden görüntü oluşturmak için. Sadece benim için çalıştı ve ilk düğmedeki tüm kodu yazdığımda nedenini bilmediğim için üzgünüm. Yani tıkladığımda tuvali ve resmi aynı anda oluştur ...

Kodlar farklı işlevlerdeyken her zaman bu güvenlik sorununu yaşarım ... = /


2

Bunu kullanarak çalışmasını sağlayabildim:

Bunu .htaccesskaynak sunucunuzun ilk satırına yazın

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

Daha sonra bir <img>eleman oluştururken aşağıdaki gibi yapın:

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

Kimliğinize boşluk koyamazsınız

Güncelleme

Tahminimce bu görüntü, komut dosyasını çalıştırdığınız yerden farklı bir sunucuda. Kendi sayfamda çalıştırırken hatanızı tekrarlayabildim, ancak aynı etki alanında barındırılan bir resmi kullandığım anda sorunsuz çalıştı. Yani güvenlikle ilgili - resmi sitenize yerleştirin. Bunun neden böyle olduğunu bilen var mı?


0

Bir tuval üzerine basitçe bazı resimler çiziyorsanız, resimleri aynı etki alanından yüklediğinizden emin olun.

www.example.com , example.com'dan farklıdır

Bu nedenle, resimlerinizin ve adres çubuğunuzdaki url'nin aynı, www olup olmadığından emin olun.


0

Fabric.js kullanıyorum ve bunu toDataURL yerine toDatalessJSON kullanarak çözebilirim:

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

Düzenleme: Nevermind. Bu, arka plan görüntüsünün üstte çizim olmadan JPG'ye dışa aktarılmasına neden olur, bu nedenle sonuçta tamamen kullanışlı olmadı.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.