Библиотека Marked — это мощный парсер Markdown в JavaScript, который позволяет преобразовывать текст в HTML. При работе с Markdown необходимо учитывать безопасность вывода, особенно при генерации HTML с пользовательским вводом. Неправильная обработка атрибутов элементов может привести к XSS-уязвимостям и другим проблемам безопасности.
Экранирование специальных символов Любые
атрибуты, вставляемые в HTML, должны проходить экранирование символов
&, <, >,
", '. Например:
function escapeAttribute(value) {
return value
.replace(/&/g, "&")
.replace(/"/g, """)
.replace(/'/g, "'")
.replace(/</g, "<")
.replace(/>/g, ">");
}
Это предотвращает внедрение вредоносного кода через атрибуты тегов.
Использование встроенных опций 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" предотвращает
уязвимости при открытии внешних ссылок в новом окне.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 атрибуты.
mangle: false — отключает маскировку
email-адресов. Полезно при контроле вывода ссылок.headerIds: false — предотвращает
автоматическую генерацию id для заголовков.smartypants: false — отключает
автоматическую замену символов, что может повлиять на обработку
пользовательских данных.Пример конфигурации:
marked.setOptions({
mangle: false,
headerIds: false,
smartypants: false
});
DOMPurify,
sanitize-html).Безопасная работа с атрибутами в Marked сочетает экранирование, валидацию и фильтрацию, что снижает риск XSS и обеспечивает корректное отображение контента.