Безопасная работа с атрибутами

Библиотека Marked — это мощный парсер Markdown в JavaScript, который позволяет преобразовывать текст в HTML. При работе с Markdown необходимо учитывать безопасность вывода, особенно при генерации HTML с пользовательским вводом. Неправильная обработка атрибутов элементов может привести к XSS-уязвимостям и другим проблемам безопасности.


Основные принципы безопасной работы с атрибутами

  1. Экранирование специальных символов Любые атрибуты, вставляемые в HTML, должны проходить экранирование символов &, <, >, ", '. Например:

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

    Это предотвращает внедрение вредоносного кода через атрибуты тегов.

  2. Использование встроенных опций Marked для безопасности Marked предоставляет несколько параметров для безопасной обработки ввода:

    • sanitize (устаревший, лучше использовать DOMPurify вместе с Marked)
    • mangle и headerIds — помогают избежать подмены идентификаторов заголовков и скрытых ссылок.

    Пример безопасной генерации HTML:

    const marked = require('marked');
    const DOMPurify = require('dompurify');
    const { JSDOM } = require('jsdom');
    
    const window = new JSDOM('').window;
    const purify = DOMPurify(window);
    
    const markdown = '[Click me](jav * ascript:alert("XSS"))';
    const html = marked.parse(markdown);
    const safeHtml = purify.sanitize(html);
    
    console.log(safeHtml); // Ссылка будет безопасно очищена

Работа с пользовательскими атрибутами

Иногда требуется добавить нестандартные атрибуты к HTML-элементам, генерируемым Marked. Это можно делать через renderer.

Пример кастомного рендерера для ссылок:

const renderer = {
    link(href, title, text) {
        // Экранирование атрибутов
        const safeHref = escapeAttribute(href);
        const safeTitle = title ? escapeAttribute(title) : '';
        return `<a href="${safeHref}" title="${safeTitle}" rel="noopener noreferrer">${text}</a>`;
    }
};

marked.use({ renderer });

const markdown = '[OpenAI](https://openai.com)';
console.log(marked.parse(markdown));

Ключевые моменты:

  • Все атрибуты должны быть экранены.
  • Использование rel="noopener noreferrer" предотвращает уязвимости при открытии внешних ссылок в новом окне.
  • Любые JavaScript-схемы (jav * ascript:) должны быть заблокированы.

Валидация и фильтрация значений атрибутов

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

function validateImgSrc(src) {
    const allowedProtocols = ['http:', 'https:'];
    try {
        const url = new URL(src);
        if (!allowedProtocols.includes(url.protocol)) {
            return '';
        }
        return src;
    } catch {
        return '';
    }
}

const renderer = {
    image(href, title, text) {
        const safeHref = escapeAttribute(validateImgSrc(href));
        const safeTitle = title ? escapeAttribute(title) : '';
        return `<img src="${safeHref}" alt="${text}" title="${safeTitle}" />`;
    }
};

marked.use({ renderer });

Этот подход гарантирует, что вредоносные схемы (jav * ascript:, data:) не попадут в src атрибуты.


Настройка глобальных опций Marked для безопасности

  • mangle: false — отключает маскировку email-адресов. Полезно при контроле вывода ссылок.
  • headerIds: false — предотвращает автоматическую генерацию id для заголовков.
  • smartypants: false — отключает автоматическую замену символов, что может повлиять на обработку пользовательских данных.

Пример конфигурации:

marked.setOptions({
    mangle: false,
    headerIds: false,
    smartypants: false
});

Рекомендации по безопасной работе с атрибутами

  1. Всегда экранировать значения атрибутов перед вставкой в HTML.
  2. Использовать кастомный рендерер для контроля генерации HTML.
  3. Применять фильтры и валидацию значений.
  4. По возможности, использовать сторонние библиотеки для санитизации (DOMPurify, sanitize-html).
  5. Избегать доверия к пользовательскому вводу в ссылках, изображениях и формах.

Безопасная работа с атрибутами в Marked сочетает экранирование, валидацию и фильтрацию, что снижает риск XSS и обеспечивает корректное отображение контента.