Whitelist-подход в контексте библиотеки Marked подразумевает строгий контроль над тем, какие элементы Markdown разрешены к обработке и преобразованию в HTML. Это ключевой механизм безопасности, предотвращающий внедрение нежелательного или опасного кода, включая XSS-атаки.
В Marked настройка whitelist достигается через конфигурацию
параметров renderer и sanitize, а также через
собственные фильтры токенов и тегов.
Marked предоставляет возможность полностью контролировать процесс
рендеринга с помощью кастомного объекта Renderer. Пример
базового подхода:
const { marked } = require('marked');
const renderer = new marked.Renderer();
// Разрешение только определенных заголовков
renderer.heading = (text, level) => {
if ([1, 2, 3].includes(level)) {
return `<h${level}>${text}</h${level}>`;
}
return '';
};
// Разрешение только безопасных ссылок
renderer.link = (href, title, text) => {
if (href.startsWith('http://') || href.startsWith('https://')) {
return `<a href="${href}" title="${title || ''}">${text}</a>`;
}
return text;
};
marked.setOptions({ renderer });
В этом примере используются жёсткие фильтры, позволяющие рендерить только определённые заголовки и безопасные ссылки. Все остальное игнорируется, что снижает риск внедрения небезопасного HTML.
Whitelist-подход требует явного перечисления разрешённых Markdown-элементов. В Marked это достигается через комбинацию:
Пример фильтрации списков и параграфов:
const lexer = new marked.Lexer();
const tokens = lexer.lex(markdownString);
const allowedTypes = ['paragraph', 'list', 'list_item'];
const filteredTokens = tokens.filter(token => allowedTypes.includes(token.type));
const html = marked.parser(filteredTokens, { renderer });
Здесь сначала Markdown разбивается на токены с помощью
Lexer, затем остаются только разрешённые типы, после чего
происходит рендеринг.
Whitelist-подход также включает ограничение атрибутов тегов.
Например, можно разрешить только href для ссылок и
запретить любые другие атрибуты:
renderer.link = (href, title, text) => {
const allowedProtocols = ['http:', 'https:'];
try {
const url = new URL(href);
if (!allowedProtocols.includes(url.protocol)) return text;
} catch {
return text;
}
return `<a href="${href}">${text}</a>`;
};
Это предотвращает использование jav * ascript: или других
потенциально опасных схем URL.
Marked поддерживает опцию sanitize, но она ограничена и
не покрывает всех кейсов. Более надёжно использовать whitelist вместе с
внешними библиотеками очистки HTML, например DOMPurify:
const DOMPurify = require('dompurify');
const html = marked(markdownString, { renderer });
const safeHtml = DOMPurify.sanitize(html, { ALLOWED_TAGS: ['p','a','ul','li','h1','h2','h3'] });
Такой подход объединяет возможности Marked с проверкой whitelist на уровне HTML, что обеспечивает максимальную безопасность.
<style> и inline-стилей через фильтры токенов.Пример фильтрации изображений:
renderer.image = (href, title, text) => {
if (href.startsWith('https://trusted.com/')) {
return `<img src="${href}" alt="${text}" title="${title || ''}"/>`;
}
return '';
};
Renderer + токен-фильтры +
внешняя очистка HTML.Whitelist-подход превращает Marked в безопасный инструмент для рендеринга Markdown, позволяя точно контролировать, что попадает в HTML, и минимизировать потенциальные риски безопасности.