Встроенное кодирование данных изображения в нескольких поддоменах - PullRequest
2 голосов
/ 30 ноября 2011

Я пытаюсь заменить все теги img на веб-странице данными в кодировке base64, содержащимися в изображении.

Изображение, представленное как:

<img src="http://a.example.com" />

будет изменено на:

<img src="data:image/png;base64,iVBORw0KGg..." />

Веб-страница содержит изображения из нескольких поддоменов, например,

<img src="http://a.example.com" />
<img src="http://b.example.com" />

На одном поддомене я могу использовать:

var images = document.getElementsByTagName('img');
for(var i=0; i<images.length; i++){
 var img = new Image();
 img.src = images[i].src;
 // Create canvas tag to represent img
 var canvas = document.createElement("canvas"); 
 canvas.width = img.width; 
 canvas.height = img.height;
 var context = canvas.getContext("2d");
 context.drawImage(img,0,0);

 img.src = canvas.toDataURL("image/png");
 $(images[i]).replaceWith(img);
}

однако, когда изображения находятся в поддомене, отличном от домена HTML, я получаю:

Uncaught Error: SECURITY_ERR: DOM Exception 18

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

Ответы [ 3 ]

2 голосов
/ 30 ноября 2011

Вы нарушаете законы спецификации, которые гласят, что если вы используете drawImage с изображением, которое не имеет того же происхождения, что и документ холста, тогда устанавливается флаг orgin-clean ложно. С этого момента вы не можете использовать toDataURL. Полные слова спецификации по этому вопросу: здесь.

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

Скажем, вы в рабочей сети и у вас есть доступ к внутренним, частным сайтам компании и вашему (частному!) Жесткому диску из вашего браузера. Частные сайты могут быть похожи на www.internal.myCompany.com, а ваш жесткий диск будет доступен по URL-адресам, таким как file:///C:/SomeOfMyPhotos/.

Теперь предположим, что вы посетили веб-сайт со скрытым холстом и во время просмотра сайта этот холст постоянно вызывал drawImage() на этот холст с URL-адресами, которые, как он предполагал, могли существовать. Эти URL будут такими же, как изображение на частном поддомене:

www.internal.myCompany.com/secret/secret-plans.jpg

Или изображение на жестком диске:

file:///C:/SomeOfMyPhotos/thatEmbarassingPhoto.png

Вредоносный сайт будет пытаться использовать различные комбинации приватных URL-адресов, пока не найдет тот, который на самом деле является файлом. Тогда он будет рисовать его на холсте. Затем он получит imageData с холста и отправит его на сервер.

Вуаля! Они украли ваши секретные планы и ваши неловкие фотографии, но без вашего согласия.

Теперь мы знаем, что приведенный выше сценарий не очень вероятен: в конце концов, секретные планы почти всегда в формате PNG, тогда как смущающие фотографии почти всегда в формате JPG. Но вполне вероятно, что подобные ситуации могут произойти, поэтому последствия для безопасности должны это учитывать.

1 голос
/ 30 ноября 2011

Как правило, вы не можете прочитать данные изображения из других доменов .Это нарушает модель безопасности Cross-Origin Resource Sharing ( CORS ).Тем не менее, вы можете обойти эту проблему, заставив каждый поддомен использовать заголовок управления доступом HTTP (здесь пример с node.js ), а также установитьcrossorigin атрибут use-credentials для каждого тега изображения.Обратите внимание, что не все браузеры поддерживают атрибут crossorigin.

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

Другой обходной путь требует использованияплагин jquery под названием $.getImageData.Под прикрытием этот плагин использует стороннюю службу под названием img-to-json и JSONP , чтобы обойти проблемы безопасности.Вот конкретный пример использования img-to-json:

"//img-to-json.appspot.com/?url=" + escape(img_url) + "&callback=" + callback

По сути, служба принимает два параметра: URL-адрес загружаемого изображения (который должен быть экранирован) иимя обратного вызова, который вы хотите выполнить, когда изображение будет загружено.Обратному вызову передается возражение с версией изображения url , а также с некоторыми метаданными, такими как высота и ширина изображения.

Кроме того, обратите внимание, что приведенный выше URL является примеромпротокола относительно URL (т. е. он начинается с //), что означает, что он будет работать как на http, так и на https страницах.

Надеюсь, это поможет.

1 голос
/ 30 ноября 2011

Песочница безопасности не позволит вам вызвать toDataURL на холсте, если на нем нарисовано изображение из другого домена. Точная логика ускользает от меня, но она существует, чтобы помешать вам сделать именно это.

...