Подтвердить что ты не робот

Является ли создание Javascript/jQuery DOM безопасным до тех пор, пока оно не добавится в документ?

Пожалуйста, внимательно прочитайте это утверждение: допустим, что до того, как будут добавлены какие-либо элементы в document все небезопасные элементы в $dom, были удалены. Но они были изначально созданы. Ok let continue....


Если часть текста пользователя обрабатывается и может быть загружена так:

var comment = 'I\'m a naughty person!!' +
              '<script src="http://blah.com/some_naughty_javascript.js">';
var $dom = $('<div>' + comment + '</div>');

Является ли это само по себе опасным каким-либо образом? Моя точка зрения, может просто простой акт создания DOM каким-то образом впрыскивать что-либо или просто обрабатывается и структура создается?

Например:

var $dom = $('<script>alert("hi");</script>');

Очевидно, что сообщение hi не появляется, пока оно не добавлено в document. Но:

  • Может ли любой тэг или что-нибудь, созданное таким образом, быть опасным?
  • Могут ли какие-либо функции в javascript/jquery "наблюдать" за создаваемыми элементами таким образом и воздействовать на него, прежде чем он лишится плохих элементов и наденет документ?

Bounty Edit

Итак, как указано в ответах ниже, кажется, что этот метод не очень безопасен, особенно по одной причине:

  • var $dom = $('<img src="blah.jpg"/>') - это будет запрашивать изображение сразу, независимо от того, был ли объект добавлен в документ.

Это создает серьезную проблему для обработки запросов HTML ajax. Например, если мы хотим получить значения из входов формы:

$.ajax({
  url: 'test.php',
  success: function(responseHTML) {
    var inputs = $(responseHTML).find('form input');
  }
});

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

Bounty присуждается всем:

  • Кто может обеспечить хороший, безопасный способ обращения с ajax-запросами без указанной выше проблемы.
  • В идеале не предоставляется ответ регулярного выражения... то есть, если мы хотим сделать $(responseHTML).find('img') - удаление тегов изображений с помощью регулярного выражения не может быть вариантом, поэтому для остановки src потребуется ненавязчивый способ загрузка, но все же имеют те же атрибуты, структуру и т.д.
4b9b3361

Ответ 1

Это само по себе опасно в любом путь? Моя точка зрения, может просто простой акт создания DOM как-то вводить что угодно, или просто просто и структура создан?

Просто создание элемента без добавления его в dom не приведет к запуску любого script, поскольку он является чисто объектом в этой точке (HtmlScriptElement). Когда он фактически добавляется к dom, элемент script будет оцениваться и запускаться браузером. С учетом сказанного я полагаю, что возможно, что очень хитрый человек может использовать ошибку, которая присутствует в некоторых фреймворках или браузере, которые вы могли бы использовать, чтобы вызвать нежелательный результат.

Рассмотрим следующий пример:

<p>
    <input type="button" value="Store 'The Script' In Variable" id="store"/>
    <input type="button" value="Append 'The Script' To Dom" id="append"/>
</p>
<br/>
<p>
    <input type="button" value="Does nothing"/>
</p>
<h1>The Script</h1>
<pre id="script">
    $(function(){
        function clickIt(){
            $(this).clone().click(clickIt).appendTo("body");
        }
        $("input[type='button']").val("Now Does Something").click(clickIt);
    });
</pre>

var theScript;

$("#store").click(function() {
    theScript = document.createElement('script');
    var scriptText = document.createTextNode($("#script").text());
    theScript.appendChild(scriptText);
});

$("#append").click(function() {
    var head = document.getElementsByTagName('head')[0];
    head.appendChild(theScript);
});

Когда вы нажмете store, он создаст элемент HtmlScriptElement и сохранит его в переменной. Вы заметите, что ничего не запускается, даже если объект создан. Как только вы нажмете append, script добавляется к dom и сразу же оценивается, а кнопки делают что-то другое.

Пример кода в jsfiddle


Могут ли какие-либо функции в javascript/jquery "смотреть" для элементов создаются таким образом и действуют на нем ПЕРЕД тем, как он был лишен плохих элементов и положить на документ?

jQuery вроде делает это для вас уже, поскольку он выполняет некоторые внутренние script eval


Из Карл Сведберг опубликуйте .append()

Все методы вставки jQuery используют функция domManip внутри чистых/технологических элементов до и после того, как они вставлены в DOM. Одна из вещей domManip функция делает вывод из любого scriptэлементы, которые нужно вставить и запустить их через "процедуру evalScript", вместо того, чтобы вводить их с остальными фрагмента DOM. Он вставляет скрипты отдельно, оценивает их, а затем удаляет их из DOM....

Вы можете изменить поведение jQuery, чтобы удалить все <script/> и дезинфицировать другие элементы с помощью встроенного javascript onclick, mouseover, etc при вызове append(), однако это повлияет только на jQuery, поскольку кто-то может легко использовать javascript для ванилин, чтобы добавить <script/> элемент.

События мутации Dom

Уровень Dom 2 определил некоторые события мутации Dom для захвата элементов, которые добавлены в dom, который будет выглядеть в отношении события, DOMNodeInserted. Однако он запускается после того, как элемент уже добавлен. примечание, за Raynos они в настоящее время устарели.

DOMNodeInserted Сработал, когда nodeбыл добавлен как ребенок другого node. Это событие отправляется после вставка. Цель этого события является nodeвставлено. Пузыри: Да Отменяется: Нет Контекстная информация: relatedNode содержит parent node

В конце концов, кажется, что нет полной остановки a <script/>, которая добавляется к dom через какой-либо другой javascript. (по крайней мере, не то, что я могу найти).

Лучший способ, который я могу предложить, - это никогда не доверять пользовательскому вводу, поскольку все пользовательские данные являются злыми. Когда вы выполняете двойную проверку dom, убедитесь, что нет запрещенных тегов, будь то <script/> или даже простые элементы <p/> и дезинфицируйте все входные данные до их сохранения.

Также, как указывает Джон, вам нужно беспокоиться о любом элементе, который может присоединить событие onclick или любой встроенный обработчик событий javascript.

Ответ 2

Обязательный ответ на ваш первый пример

var comment = 'I\'m a naughty person!!' +
              '<script src="http://blah.com/some_naughty_javascript.js">';
var $dom = $('<div>' + comment + '</div>');

Не делай этого. Вместо этого вы должны использовать API, который обрабатывает текст как текст и вообще не подвергает вас инъекции. В этом примере вы должны сделать следующее:

var $dom = $('<div>').text(comment);

... который создает div, а затем устанавливает его текстовое содержимое. comment никогда не анализируется как HTML, поэтому нет никаких шансов, что браузер когда-либо сделает с ним что-нибудь опасное.

Переходя к вопросу

Если я правильно вас понимаю, вам нужно разбирать информацию из произвольного HTML, не готовясь к ее отображению (скажем, при загрузке изображений).

Это сложно, поскольку DOM, встроенные в веб-браузеры, созданы для обработки контента, который в какой-то момент будет отображаться. jQuery (и любая библиотека, которая создает узлы DOM) ограничена этим.

DOM Level 2 определяет API для создания документов, которые полностью отделены от активного: document.implementation.createHTMLDocument(title). В моем тестировании ничего не загружается, когда в одном из этих документов создается img:

var doc = document.implementation.createHTMLDocument(''),
    img = doc.createElement('img');
img.src = 'http://example.com/image.jpg'; // Nothing happens.
// Alternatively…
doc.body.innerHTML = '<img src="http://example.com/image.jpg">'; // Nope.

Итак, созданный таким образом документ выглядит как хорошая песочница для анализа и изучения HTML. Вы даже можете создать обертку jQuery вокруг узлов в другом документе ($(doc.body)) и изучить его через API jQuery. Когда вы найдете нужные вам узлы, вы можете преобразовать их обратно в HTML для вставки в активный документ или использовать методы , такие как importNode() и adoptNode() для переноса их непосредственно в активный документ.

К сожалению, поддержка всего этого является новой. Firefox поддерживает createHTMLDocument в версии 4 и выше (аналогичный метод createDocument, который имеет дело с XML, доступен в более старых версиях), и Internet Explorer поддерживает его в версии 9 и выше. Кроме того, насколько я могу судить, спецификация не гарантирует, что изображения и сценарии не будут предварительно загружены в эти документы.

Лучшее решение - избегать анализатора HTML-браузера. Несколько JavaScript HTML в последнее время появились парсеры. Простейший, вероятно, John Resigs Чистый JavaScript HTML Parser. Вы можете подавать HTML-код, и он вызывает обратные вызовы при попадании на новые теги, атрибуты и текст. Из этих обратных вызовов вы можете создавать новый HTML, создавать узлы DOM или хранить документ в любой форме, какой вам нравится, - и вы можете игнорировать атрибуты и узлы, которые считаете опасными.

Вы можете найти пример этой в Dan Kaminskys Interpolique, доказательство концепции, которая направлена ​​на то, чтобы убить XSS и SQL-инъекцию раз и навсегда. Проект не снял, но если вы загрузите Interpolique, вы найдете функцию safeParse(), застрявшую в нижней части htmlparser.js, которая использует белый список имен и атрибутов тегов и отбрасывает все остальное.

jsdom является полным (до уровня DOM уровня 2, с некоторым уровнем 3) HTML DOM, написанным на JavaScript, - вы можете использовать его для безопасной работы с HTML, Вы даже можете загрузить свою собственную копию jQuery. Тем не менее, он написан для CommonJS, без учета совместимости с браузером. Я не знаю, будет ли он работать в большинстве веб-браузеров без изменений. Его также большая библиотека.

Если это вообще возможно, идеальным решением является обслуживание ответов AJAX в формате, отличном от HTML. Нужно ли вообще включать дополнительный, небезопасный HTML? Если вы выполняете работу на сервере, возвращаете только то, что вам нужно...

{
    "inputs": [
        '<input …>',
        '<input …>'
    ],
}

... ваша работа на стороне клиента становится намного проще.

Ответ 3

Отличный вопрос. По-видимому, можно ввести script и разместить в нем обработчики событий. Я протестировал с помощью следующего HTML:

<!DOCTYPE html>
<html lang="en">
    <head>  
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
        <script type="text/javascript"> 
            <!-- 
            $(function() {
                var $dom = $('<script>$(".testbutton").live("click", function() { alert("hi") });</script>');

                $(".firstbutton").click(function() {
                    $("BODY").append($dom);
                });
            });
            -->
        </script>
    </head>

    <body style="padding:0">            
        <button class="firstbutton">Click this first</button>

        <button class="testbutton">Then this</button>
    </body>
</html>

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

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

Это то, о чем я никогда не думал - спасибо, что поднял его.

Ответ 4

Похоже, что script не будет работать, пока он не добавлен к DOM.

$(function ()
{
    var ss = document.createElement('script');
    var scr = 'alert("bah");';
    var tt = document.createTextNode(scr);
    ss.appendChild(tt);
    var hh = document.getElementsByTagName('head')[0];
    //hh.appendChild(ss);
});

и

$(function ()
{
    var ss = document.createElement('script');
    var scr = 'alert("bah");';
    var tt = document.createTextNode(scr);
    ss.appendChild(tt);
    var hh = document.getElementsByTagName('head')[0];
    hh.appendChild(ss);
});