trust(html)
Описание
Преобразует HTML или SVG строку в HTML или SVG без экранирования. Не используйте m.trust
для необработанного пользовательского ввода.
Всегда старайтесь использовать альтернативные методы, прежде чем рассматривать использование m.trust
.
Сигнатура
vnode = m.trust(html)
Аргумент | Тип | Обязательный | Описание |
---|---|---|---|
html | String | Да | Строка, содержащая HTML или SVG текст |
возвращает | Vnode | Доверенный HTML виртуальный DOM-узел, представляющий входную строку |
Как это работает
По умолчанию Mithril.js экранирует все значения для предотвращения XSS-инъекций.
var userContent = "<script>alert('evil')</script>";
var view = m('div', userContent);
m.render(document.body, view);
// эквивалентный HTML
// <div><script>alert('evil')</script></div>
Однако иногда необходимо отображать форматированный текст и разметку. Чтобы удовлетворить эту потребность, m.trust
создает доверенные HTML виртуальные DOM-узлы, которые отображаются как HTML.
var view = m('div', [m.trust("<h1>Here's some <em>HTML</em></h1>")]);
m.render(document.body, view);
// эквивалентный HTML
// <div><h1>Here's some <em>HTML</em></h1></div>
Доверенные HTML виртуальные DOM-узлы являются объектами, а не строками; поэтому их нельзя объединять с обычными строками напрямую.
Вопросы безопасности
Необходимо очищать ввод перед использованием m.trust
, чтобы исключить наличие вредоносного кода, сгенерированного пользователем, в HTML-строке. Если не очистить HTML строку и пометить её как доверенную, любые асинхронные вызовы JavaScript внутри этой строки будут запущены и выполнены с правами пользователя, просматривающего страницу.
Наиболее распространенные способы внедрения атак безопасности включают добавление атрибутов onload
или onerror
в теги <img>
или <iframe>
, а также использование незакрытых кавычек, например " onerror="alert(1)
, для внедрения исполняемого кода в неочищенные строковые интерполяции.
var data = {};
// Пример уязвимой HTML-строки
var description =
"<img alt='" + data.title + "'> <span>" + data.description + '</span>';
// Атака с использованием атрибутов, связанных с JavaScript
data.description = "<img onload='alert(1)'>";
// Атака с использованием несбалансированных тегов
data.description = "</span><img onload='alert(1)'><span";
// Атака с использованием несбалансированных кавычек
data.title = "' onerror='alert(1)";
// Атака с использованием другого атрибута
data.title = "' onmouseover='alert(1)";
// Атака, не использующая JavaScript
data.description =
"<a href='https://evil.com/login-page-that-steals-passwords.html'>Click here to read more</a>";
Существует множество неочевидных способов создания вредоносного кода, поэтому настоятельно рекомендуется использовать белый список разрешенных HTML тегов, атрибутов и значений атрибутов, в отличие от черного списка для очистки пользовательского ввода. Также настоятельно рекомендуется использовать полноценный HTML парсер вместо регулярных выражений для очистки, потому что регулярные выражения чрезвычайно трудно протестировать на все крайние случаи.
Скрипты, которые не запускаются
Несмотря на то, что существует много неясных способов заставить HTML строку запускать JavaScript, теги <script>
не запускаются, когда появляются в HTML строке, переданной в m.trust
.
По историческим причинам браузеры игнорируют теги <script>
, которые вставляются в DOM через innerHTML
. Это связано с тем, что как только элемент готов (и, следовательно, имеет доступное свойство innerHTML
), механизмы рендеринга не могут вернуться к этапу парсинга, если скрипт вызывает что-то вроде document.write("</body>")
.
Это поведение браузера может показаться неожиданным разработчику, знакомому с jQuery, потому что jQuery реализует код специально для поиска тегов script и их запуска в этом сценарии. Mithril.js придерживается поведения браузера. Если требуется поведение jQuery, вам следует либо переместить код из HTML строки в метод жизненного цикла oncreate
, либо использовать jQuery (или повторно реализовать его код разбора скриптов).
Избегайте доверия HTML
В общем случае, следует избегать использования m.trust
, если только вам не требуется отображать форматированный текст и нет других способов добиться желаемого результата.
// НЕ РЕКОМЕНДУЕТСЯ
m('div', m.trust('hello world'));
// РЕКОМЕНДУЕТСЯ
m('div', 'hello world');
Избегайте слепого копирования и вставки
Распространенная ошибка при использовании m.trust
- это работа со сторонними сервисами, в учебных материалах которых предлагается копировать и вставлять HTML код. В большинстве случаев HTML следует создавать с использованием виртуальных DOM-узлов (обычно с помощью утилиты m()
).
Вот пример фрагмента для кнопки Facebook Like:
<!-- Load Facebook SDK for JavaScript -->
<div id="fb-root"></div>
<script>
(function (d, s, id) {
var js,
fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s);
js.id = id;
js.src = '//connect.facebook.net/en_US/sdk.js#xfbml=1';
fjs.parentNode.insertBefore(js, fjs);
})(document, 'script', 'facebook-jssdk');
</script>
<!-- Your like button code -->
<div
class="fb-like"
data-href="https://www.your-domain.com/your-page.html"
data-layout="standard"
data-action="like"
data-show-faces="true"
></div>
А вот как реорганизовать в компонент Mithril.js, чтобы избежать m.trust
:
var FacebookLikeButton = {
oncreate: function () {
(function (d, s, id) {
var js,
fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s);
js.id = id;
js.src = '//connect.facebook.net/en_US/sdk.js#xfbml=1';
fjs.parentNode.insertBefore(js, fjs);
})(document, 'script', 'facebook-jssdk');
},
view: function () {
return [
m('#fb-root'),
m(
'.fb-like[data-href=https://www.your-domain.com/your-page.html][data-layout=standard][data-action=like][data-show-faces=true]'
),
];
},
};
Компонент Mithril.js выше просто копирует код тега script в хук oncreate
и объявляет оставшиеся HTML теги, используя синтаксис m()
Mithril.js.
Избегайте HTML сущностей
Распространенная ошибка - использование m.trust
для HTML-сущностей. Лучший подход - использовать соответствующие символы unicode:
// НЕ РЕКОМЕНДУЕТСЯ
m('h1', 'Coca-Cola', m.trust('™'));
// РЕКОМЕНДУЕТСЯ
m('h1', 'Coca-Cola™');
Символы Unicode для символов с диакритическими знаками можно вводить с помощью раскладки клавиатуры для соответствующего языка, а также можно использовать сочетания клавиш для часто используемых символов (например, Alt+0153
в Windows или Option+2
на Mac для символа ™). Другой простой способ их создания - просто скопировать и вставить нужный символ из таблицы символов unicode. Еще один связанный метод - ввести экранированную кодовую точку unicode (например, "\u2122"
для символа ™).
Все символы, которые можно представить в виде HTML сущностей, имеют аналоги unicode, включая невидимые символы, такие как
и ­
.
Чтобы избежать проблем с кодировкой, следует установить кодировку файла в UTF-8 в файле JavaScript, а также добавить метатег <meta charset="utf-8">
в хост-файл HTML.