Чому 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

Це ніяк не може спрацювати! Хто-небудь може пояснити це, будь ласка?



2
Це рішення не здається корисним для людей, які не використовують Adobe AIR.
ObscureRobot

Відповіді:


68

У специфікаціях написано:

Кожного разу, коли викликається метод toDataURL () елемента полотна, для якого прапорець чистого джерела встановлено значення false, метод повинен викликати виняток SECURITY_ERR.

Якщо зображення надходить з іншого сервера, я не думаю, що ви можете використовувати toDataURL ()


6
Якщо зловмисник зможе вгадати назву картинки, яка є у вас на приватному сайті, він зможе отримати її копію, намалювавши на полотні та надіславши нове зображення на свій сайт. Основне обмеження з моєї точки зору полягає в тому, щоб уникнути малювання вмісту іншого сайту, але безпека занадто складна, оскільки зловмисник може знайти діру на будь-якому несподіваному сайті.
AlfonsoML 05.03.10

3
Зверніть увагу, що субдомен також має значення. На моєму досвіді, принаймні в Chrome, під час здійснення дзвінка, який, як вважається, знаходиться між субдоменами: 1. у example.com/some/path/index.html для відео чи зображення у foo, застосовується виняток SECURITY_ERR: DOM. .example.com 2. при переході на ту ж сторінку, що і в 1, але шляхом введення URL-адреси example.com/some/path/index.html, а потім спроби зателефонувати доDataUrl () для відео чи зображення на www.example.com
Сем Даттон,

3
@AlfonsoML, можливо, я помиляюся, але "Якщо зловмисник зможе вгадати назву картинки, яка є у вас на приватному сайті", ймовірно, він схопить зображення із завитками, не використовуючи браузер. Моя точка зору: Загальнодоступна URL-адреса Загальнодоступний вміст.
kilianc

4
@ pop850 Я стикаюся з цією проблемою, навіть коли використовую URL-адресу даних. Чи є спосіб, як я можу обійти це для URL-адрес даних?
Sujay

6
@kilianc Це обмеження існує для запобігання зловмисникові змушувати ваш браузер (з файлами cookie автентифікації) отримувати зображення та надсилати його вміст зловмиснику; у зловмисника немає ваших файлів cookie, тому він не може використовувати curl для отримання тих самих ресурсів, які ви маєте право отримати. "Загальнодоступна URL-адреса, загальнодоступний вміст" - це досить помилковий спосіб мислення: моя сторінка у Facebook має загальнодоступні компоненти, але є багато такого, що доступно лише за допомогою правильного маркера автентифікації.
apsillers

18

Встановлення атрибуту перехресного походження для об’єктів зображення, які працювали у мене (я використовував 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,

Я використовую fabricjs, але не можу його вирішити. Як би ви зробили це за допомогою цього коду? функція 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; }}
ГОЙ

Працює також у Firefox.
vanowm

16

Якщо зображення розміщено на хості, який встановлює або Access-Control-Allow-Origin, або Access-Control-Allow-Credentials, ви можете використовувати спільний доступ до ресурсів (CORS). Докладніше див. Тут (атрибут crossorigin).

Інший варіант - це те, що ваш сервер має кінцеву точку, яка отримує та обслуговує зображення. (наприклад, http: // your_host / endpoint? url = URL ) Недоліком цього підходу є затримка та теоретично непотрібне отримання.

Якщо є більше альтернативних рішень, мені було б цікаво про них почути.


Привіт, я зробив саме це, у мене є Access-Control-Allow-Origin: * на зображеннях, у мене є crossorigin = 'anonymous', потім я малюю зображення на полотні, потім дзвоню вDataUrl і все ще отримую SECURITY_ERR : DOM Exception 18
skrat

13

Здається, існує спосіб запобігти цьому, якщо хостинг зображень може забезпечити такі заголовки HTTP для графічних ресурсів, а браузер підтримує CORS:

access-control-allow-origin: *
access-control-allow-credentials: істина

Про це йдеться тут: http://www.w3.org/TR/cors/#use-cases


1
access-control-allow-credentials: true не працюватиме з access-control-allow-origin: *. Коли встановлено перше, друге повинно мати значення походження, а не підстановочне значення з developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS
Silver Gonzales

4

Нарешті я знайшов рішення. Просто потрібно додати crossOriginяк третій параметр у fromURLfunc

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

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

1

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

Оновлення

Я припускаю, що зображення знаходиться на іншому сервері, ніж там, де ви виконуєте сценарій. Мені вдалося продублювати вашу помилку, запустивши її на власній сторінці, але вона спрацювала нормально в той момент, коли я використав зображення, розміщене в тому ж домені. Тож це пов’язано з безпекою - розмістіть зображення на своєму сайті. Хтось знає, чому це так?


0

Якщо ви просто малюєте деякі зображення на полотні, переконайтеся, що завантажуєте зображення з того самого домену.

www.example.com відрізняється від example.com

Тож переконайтеся, що ваші зображення та URL-адреси, які ви маєте в адресному рядку, однакові, www чи ні.


0

Я використовую fabric.js і міг би вирішити це, використовуючи toDatalessJSON замість toDataURL:

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

Редагувати: Неважливо. Це призводить до того, що лише фонове зображення експортується у JPG, без креслення зверху, тож врешті-решт воно було не зовсім корисним.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.