Почему canvas.toDataURL () выдает исключение безопасности?

90

Я не выспался что ли? Этот следующий код

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

выдает эту ошибку:

SECURITY_ERR: DOM Exception 18

Это не должно работать! Кто-нибудь может объяснить это, пожалуйста?

поп850
источник
2
Это решение не кажется полезным людям, не использующим Adobe AIR.
ObscureRobot

Ответы:

68

В спецификациях сказано:

Каждый раз, когда вызывается метод toDataURL () элемента холста, чей флаг очистки источника установлен в значение false, метод должен вызывать исключение SECURITY_ERR.

Если изображение поступает с другого сервера, я не думаю, что вы можете использовать toDataURL ()

Боб
источник
6
Если злоумышленник сможет угадать название изображения, которое есть у вас на частном сайте, он сможет получить его копию, нарисовав на холсте и отправив новое изображение на свой сайт. Основное ограничение, с моей точки зрения, - избегать рисования содержимого другого сайта, но безопасность слишком сложна, так как злоумышленник может найти брешь в любом неожиданном сайте.
AlfonsoML 05
3
Обратите внимание, что субдомен также имеет значение. По моему опыту, по крайней мере, в Chrome SECURITY_ERR: DOM Exception 18 возникает при выполнении вызова, который воспринимается как находящийся между субдоменами: 1. в example.com/some/path/index.html для видео или изображения в foo .example.com 2. при переходе на ту же страницу, что и в 1, но путем ввода URL-адреса example.com/some/path/index.html и последующей попытки вызвать toDataUrl () для видео или изображения на www.example.com
Сэм Даттон
3
@AlfonsoML, возможно, я ошибаюсь, но «Если злоумышленник может угадать имя изображения, которое у вас есть на частном сайте», вероятно, он захватит изображение с помощью curl non в браузере. Моя точка зрения: Публичный URL Публичный контент.
kilianc
4
@ pop850 Я сталкиваюсь с этой проблемой, даже когда использую URL-адрес данных. Есть ли способ обойти это для URL-адресов данных?
Суджай
6
@kilianc Это ограничение существует для того, чтобы злоумышленник не заставил ваш браузер (с файлами cookie проверки подлинности) получить изображение и отправить его содержимое злоумышленнику; у злоумышленника нет ваших файлов cookie, поэтому он не может использовать curl для получения тех же ресурсов, которые вам разрешено получать. «Общедоступный URL-адрес, общедоступный контент» - это довольно ошибочный способ мышления: моя страница в Facebook имеет общедоступные компоненты, но многие из них доступны только с правильным токеном аутентификации.
apsillers 06
18

У меня сработала установка атрибута 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';

Для тех, кто использует 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;
};
Филипп Нужный
источник
Спасибо, у меня работает в Chrome. Однако я не использую fabric.js
Philip007 02
Я использую fabricjs, но не могу решить эту проблему. Как бы вы сделали это с помощью этого кода? функция wtd_load_bg_image (img_url) {если (img_url) {var bg_img = новое изображение (); 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.
vanowm 01
16

Если изображение размещено на хосте, который устанавливает либо Access-Control-Allow-Origin, или Access-Control-Allow-Credentials, вы можете использовать Cross Origin Resource Sharing (CORS). Подробнее см. Здесь (атрибут crossorigin).

Другой вариант - иметь на сервере конечную точку, которая выбирает и обслуживает изображение. (например, http: // your_host / endpoint? url = URL ) Обратной стороной этого подхода является задержка и теоретически ненужная выборка.

Если есть другие альтернативные решения, мне было бы интересно о них услышать.

Джеймс
источник
Привет, я так и сделал, у меня есть Access-Control-Allow-Origin: * на изображениях, у меня есть crossorigin = 'anonymous', затем я рисую изображение на холсте, затем вызываю toDataUrl и все еще получаю SECURITY_ERR : Исключение DOM 18
skrat
13

Кажется, есть способ предотвратить это, если хостинг изображений может предоставлять следующие HTTP-заголовки для ресурсов изображений, а браузер поддерживает CORS:

доступ-контроль-разрешение-происхождение: *
доступ-контроль-разрешить учетные данные: правда

Это указано здесь: http://www.w3.org/TR/cors/#use-cases

DitherSky
источник
1
access-control-allow-credentials: true не будет работать с access-control-allow-origin: *. Когда установлено первое, второе должно иметь значение происхождения, а не подстановочное значение из developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS
Сильвер Гонсалес
4

Наконец я нашел решение. Просто нужно добавить crossOriginтретий параметр в fromURLfunc

fabric.Image.fromURL(imageUrl, function (image) {
            //your logic
    }, { crossOrigin: "Anonymous" });
jose920405
источник
2

У меня была такая же проблема, и все изображения размещены в одном домене ... Итак, если у кого-то такая же проблема, вот как я решил:

У меня было две кнопки: одна для создания холста, а другая для создания изображения из холста. Это сработало только у меня, и извините, что я не знаю почему, когда я написал весь код на первой кнопке. Поэтому, когда я щелкаю по нему, генерируем холст и изображение одновременно ...

У меня всегда эта проблема с безопасностью, когда коды были на разных функциях ... = /

КаринаПилар
источник
2

Я смог заставить его работать, используя это:

Напишите это в первой строке вашего .htaccessисходного сервера

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

Затем при создании <img>элемента сделайте следующее:

// 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');
Qwerty
источник
1

Вы не можете ставить пробелы в своем удостоверении личности

Обновить

Я предполагаю, что изображение находится не на том сервере, где вы выполняете скрипт. Мне удалось продублировать вашу ошибку, когда я запустил ее на своей странице, но она работала нормально, когда я использовал изображение, размещенное в том же домене. Так что это связано с безопасностью - поместите изображение на свой сайт. Кто-нибудь знает, почему это так?

Майк Робинсон
источник
0

Если вы просто рисуете несколько изображений на холсте, убедитесь, что вы загружаете изображения из одного домена.

www.example.com отличается от example.com

Поэтому убедитесь, что ваши изображения и URL-адрес в адресной строке совпадают, www или нет.

JonathanC
источник
0

Я использую fabric.js и могу решить эту проблему, используя toDatalessJSON вместо toDataURL:

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

Изменить: Забудь. Это приводит к тому, что в JPG экспортируется только фоновое изображение, без рисунка сверху, так что в конце концов это не совсем полезно.

Horstwilhelm
источник