Безопасное использование HTML

Noty — это библиотека для отображения уведомлений в веб-приложениях. Одним из важных аспектов работы с уведомлениями является безопасное использование HTML внутри них. Библиотека поддерживает возможность вставки HTML-контента через опцию text, однако некорректная работа с пользовательским вводом может привести к XSS-уязвимостям.

Для безопасного отображения HTML необходимо разделять два сценария: статический HTML-контент и контент, полученный от пользователя. Статический HTML, определяемый в коде разработчика, безопасен по умолчанию. Вставка пользовательского контента требует обработки через функции экранирования специальных символов: <, >, ", ', &.

Пример базового уведомления с HTML:

new Noty({
    type: 'success',
    layout: 'topRight',
    text: '<strong>Успех!</strong> Данные сохранены.',
    timeout: 3000
}).show();

В этом примере HTML безопасен, так как строка задаётся разработчиком и не зависит от внешнего ввода.


Экранирование пользовательского ввода

Если необходимо вставить пользовательский текст, его нужно обязательно экранировать, чтобы теги <script> или другие потенциально опасные конструкции не выполнялись. Простая функция экранирования может выглядеть так:

function escapeHTML(str) {
    return str
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#39;');
}

const userInput = '<img src=x oner ror=alert(1)>';
new Noty({
    type: 'alert',
    layout: 'topRight',
    text: escapeHTML(userInput),
    timeout: 4000
}).show();

После экранирования все специальные символы заменяются на безопасные HTML-сущности, что предотвращает выполнение скриптов.


Использование шаблонов с HTML

Noty поддерживает кастомные шаблоны уведомлений через опцию template. Для безопасного внедрения HTML рекомендуется использовать шаблонизаторы, которые автоматически экранируют пользовательские данные.

Пример шаблона с динамическим контентом:

const template = (title, message) => `
    <div class="noty_message">
        <h4>${escapeHTML(title)}</h4>
        <p>${escapeHTML(message)}</p>
    </div>
`;

new Noty({
    type: 'information',
    layout: 'topRight',
    text: template('Внимание', userInput),
    timeout: 5000
}).show();

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


Опции dangerouslyUseHTMLString и их ограничения

В Noty существует возможность принудительного отображения HTML через опцию dangerouslyUseHTMLString. Она предназначена исключительно для контента, полностью контролируемого разработчиком.

new Noty({
    type: 'success',
    layout: 'topRight',
    text: '<em>Операция завершена</em>',
    dangerouslyUseHTMLString: true
}).show();

Использование этой опции с пользовательским вводом категорически не рекомендуется, так как она полностью отключает экранирование и делает уведомление уязвимым для XSS.


Стилизация HTML в уведомлениях

Для безопасного HTML можно применять CSS-стили без использования style внутри пользовательских тегов. Например, отдельный CSS-класс позволяет задавать оформление текста:

.noty_message strong {
    color: green;
}

.noty_message p {
    font-size: 14px;
}

В уведомлении:

new Noty({
    type: 'success',
    layout: 'topRight',
    text: '<div class="noty_message"><strong>Успех!</strong><p>Данные сохранены.</p></div>',
    timeout: 3000
}).show();

Такой подход обеспечивает визуальное оформление без риска внедрения вредоносного кода через инлайновые атрибуты.


Поддержка динамического контента

При работе с динамическими данными, например, сообщениями с сервера, рекомендуется всегда экранировать HTML на клиенте или на сервере. Даже если данные передаются с HTTPS, нельзя доверять их содержимому.

fetch('/api/notifications')
    .then(res => res.json())
    .then(data => {
        data.forEach(item => {
            new Noty({
                type: 'info',
                layout: 'topRight',
                text: escapeHTML(item.message),
                timeout: 4000
            }).show();
        });
    });

Каждое уведомление проходит через функцию экранирования перед отображением.


Практические рекомендации

  • Всегда использовать escapeHTML для пользовательского ввода.
  • Не применять dangerouslyUseHTMLString для динамических данных.
  • Использовать CSS-классы вместо инлайновых стилей для оформления.
  • При работе с шаблонами экранировать все переменные, включая заголовки и подписи.
  • Для уведомлений, полностью контролируемых разработчиком, безопасно вставлять статический HTML.

Следование этим правилам позволяет использовать возможности Noty с HTML без риска XSS и других уязвимостей.