JavaScript Вопросы безопасности Canvas toDataURL - PullRequest
0 голосов
/ 16 марта 2020

Мне любопытно, если кто-нибудь мог бы сообщить мне, насколько безопасно использовать toDataURL на предоставленном пользователем изображении. Основная идея c заключается в том, что пользователь A будет загружать изображение в свой браузер, и оно будет преобразовано в URL, а затем игнорируя промежуточные шаги, в конечном итоге пользователь B (а также другие пользователи) получит формат URL, в котором он будет преобразован обратно в изображение и отображен в браузере пользователя B.

Так что мой вопрос вращается вокруг того, может ли кто-нибудь злоупотребить системой, чтобы ввести код в браузер пользователя B, или иным образом вызвать havo c. В общем, какие соображения безопасности необходимо учитывать при использовании toDataURL и последующем преобразовании его обратно?

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

Что я нашел в моем исследовании до сих пор:

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

Ничто из вышеперечисленного не подошло к нему достаточно с точки зрения того, что один пользователь нападает на другого пользователя посредством загрузки изображение (которое не остается загруженным, а преобразуется в URL-адрес данных), которое затем загружает и просматривает другой пользователь (с img sr c, для которого задан URL-адрес, а не исходная загрузка злоумышленника). 2 близок к ответу на мой вопрос, но, насколько я понимаю, подробные методы не сработают, если злоумышленник не вставит какой-либо скрипт в браузер просматривающего пользователя.

Кому go вместе с этим вопросом - пример того, что я хотел бы сделать, включая загрузку файла / преобразование в URL данных вместе с примером URL данных, чтобы попробовать импортировать (этот пример URL безопасен для импорта и небольшой, поэтому он быстро импортируется ):

window.onload = function() {
    document.getElementById("convert").onclick = convert;
    document.getElementById("import").onclick = importF;

    let imageLoader = document.getElementById("imageLoader");
    let canvas = document.getElementById("imageCanvas");
    let ctx = canvas.getContext("2d");

    imageLoader.addEventListener('change', e => {
      let reader = new FileReader();

      reader.onload = (ee) => {
          loadImage("imageCanvas", ee.target.result);
      }

      reader.readAsDataURL(e.target.files[0]);  
    }, false);
};

function loadImage(id, src) {
  let canvas = document.getElementById(id);
  let ctx = canvas.getContext("2d");
  let img = new Image();
  
  img.onload = () => {
      canvas.width = img.width;
      canvas.height = img.height;
      ctx.drawImage(img, 0, 0);
  }
  
  img.src = src;
}

function convert() {
  let canvas = document.getElementById("imageCanvas");
  console.log(canvas.toDataURL());
}

function importF() {
  let imageImport = document.getElementById("imageImport");
  let url = imageImport.value;
  loadImage("imageCanvas", url);
}
<label>Upload Image:</label>
<input type="file" id="imageLoader" name="imageLoader"/>
<br/>

<label>Import Image:</label>
<input type="text" id="imageImport" name="imageImport"/>
<br/>

<label>Sample URL:</label>
<code style="user-select: all;"> data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAOCAYAAAAmL5yKAAAApUlEQVQ4T2NkQALyKu5GjP8Z01kZ/1n/+s+kjSyHi80Ik1BQdvf4z8C4nYPx/z819t9M+py/GRj+MzAwgFTgocEGyCl75DEyMEz04f3OEC34lUGY+R8xloPVMMopeTgzMjLsMeb8xdAu8YFojTCFjPJKblNlWf+lTpV5z8rBCHIraYBRQ9Xtoi3XL70S0U+k6YSqZpRX9vgfK/CVIVbw66gBIzcMAHB4Ryt6jeYXAAAAAElFTkSuQmCC </code>
<br/>

<button id="import"> Import from URL </button>
<button id="convert"> Convert to URL </button>
<br/>

<canvas id="imageCanvas"></canvas>

1 Ответ

1 голос
/ 17 марта 2020

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

Испорченный холст

"Tainting the canvas" - это безопасность операция, которая блокирует .toDataURL() и любой другой метод экспорта, такой как .toBlob(), .captureStream() или 2D-контекст .getImageData().
. Есть только несколько случаев, когда эта операция выполняется:

  • Ресурсы из разных источников : это наиболее распространенное явление в сети. Сайт A нарисовал ресурс, как изображение с Сайт B , на холсте. Если Сайт B не сообщил браузеру, что он разрешает Сайт A - прочитать этот контент, передав соответствующие заголовки Allow-Origin Затем браузер должен «испортить» холст.
    Это защищает только ресурс . В этом случае к сайту A не добавляется никакой реальной безопасности.

  • утечка информации : это скорее исключение, но все же это предмет. Браузеры могут самостоятельно решить, что некоторые действия могут привести к утечке информации о конфиденциальности их пользователя. Например, наиболее распространенный случай - «испортить» холст, когда на холсте нарисовано изображение SVG, содержащее . Поскольку этот тег может отображать HTML, он также может пропускать, например, какую ссылку посещали. Браузеры должны позаботиться об анонимизации этих ресурсов, но, тем не менее, Safari по-прежнему портит любое такое изображение SVG, Chrome с ошибками по-прежнему портит те, которые обслуживаются из blob: URI, IE испортил любое изображение SVG (не только с ), и все в какой-то момент испортили холст при использовании некоторых внешних элементов filter.

  • Утечка информации II : Существует также кое-что, с чем не может бороться ни один браузер при чтении растрового изображения, созданного на холсте. Каждое аппаратное и программное обеспечение будет давать немного разные результаты, когда его попросят выполнить одинаковые операции рисования. Это можно использовать для отпечатка пальца текущего браузера. Таким образом, некоторые расширения браузера также блокируют эти методы или возвращают фиктивные результаты.

Теперь, ничто из этого не защищает от вредоносных изображений.


Изображения, содержащие вредоносный код

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

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


Риски, связанные с загрузкой контента на сервер

При загрузке чего-либо на ваш сервер существует много рисков. Я не могу подчеркнуть это достаточно, но Читать OW ASP рекомендации внимательно.


Особые риски при загрузке data: URL

data: URL - хороший вектор для XSS-атак . Действительно, очень вероятно, что вы создадите код HTML напрямую, используя этот data: URL. Если вы не применили правильные шаги санации, вы можете загрузить скрипт злоумышленника вместо изображения:

const dataURIFromServer = `data:image/png,"' onerror="alert('nasty script ran')"`;

const makeImgHTML = ( uri ) => `<img src="${uri}">`;

document.getElementById('container').innerHTML = makeImgHTML(dataURIFromServer);
<div id="container"></div>

Последнее слово в data: URLs

data: URL-адреса служат для хранения данных в URL-адресе, чтобы их можно было передавать напрямую без необходимости использования сервера.
Хранение URL-адреса data: на сервере неэффективно.
Для представления двоичных данных эти данные должны быть закодированы в base64, чтобы все небезопасные символы можно было по-прежнему представлять в большинстве кодировок. Эта операция приведет к росту примерно на 34% от исходного размера данных, и вам придется хранить его как строку, что неудобно для большинства баз данных.

Действительно, data: URL-адреса взяты из другая эпоха. Там действительно мало случаев, когда вы хотите его использовать. Большая часть того, что вы хотите сделать с URL-адресом data:, вы должны делать это с BLOB-объектами и URL-адресом blob:. Например, загрузите ваше изображение как Blob прямо на ваш сервер. Используйте метод canvas .toBlob(), если вам нужно экспортировать его содержимое. Используйте img.src = URL.createObjectURL(file), если вы хотите представить изображение, выбранное вашим пользователем.



TL; DR

- В вашем сценарии toDataURL() само по себе будет не создавайте никаких рисков и не предотвратите их.
- Используйте хорошо известные методы для очистки загрузок ваших пользователей (никогда им не доверяйте и помните, что они могут даже не быть используя пользовательский интерфейс для общения с сервером).
- Избегайте data: URL. Они неэффективны.

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