Для начала необходимо установить библиотеку marked и
библиотеку sanitize-html, которая будет отвечать за
безопасную обработку HTML:
npm install marked sanitize-html
После установки подключение библиотек в проекте на Node.js выполняется следующим образом:
const marked = require('marked');
const sanitizeHtml = require('sanitize-html');
В случае использования ES-модулей:
import { marked } from 'marked';
import sanitizeHtml from 'sanitize-html';
marked преобразует Markdown в HTML. Проблема
безопасности возникает из-за возможности внедрения вредоносного HTML или
скриптов. Для предотвращения XSS-атак используется
sanitize-html, который очищает результат, оставляя только
разрешённые теги и атрибуты.
Типовой поток обработки выглядит так:
marked → HTML.sanitize-html → безопасный HTML.const markdown = `
# Пример заголовка
Текст с [ссылкой](https://example.com) и **жирным текстом**.
<script>alert('Опасно');</script>
`;
const html = marked(markdown);
const cleanHtml = sanitizeHtml(html, {
allowedTags: sanitizeHtml.defaults.allowedTags.concat(['h1', 'h2']),
allowedAttributes: {
a: ['href', 'name', 'target']
}
});
console.log(cleanHtml);
В этом примере:
marked преобразует Markdown в HTML.sanitizeHtml удаляет тег <script> и
любые запрещённые атрибуты.<h1>, <h2>
и ссылки с атрибутами href, name,
target.sanitize-html предоставляет гибкую настройку:
http, https, mailto).Пример расширенной настройки:
const cleanHtml = sanitizeHtml(html, {
allowedTags: ['b', 'i', 'em', 'strong', 'a', 'p', 'ul', 'li', 'h1', 'h2', 'h3'],
allowedAttributes: {
a: ['href', 'target', 'rel']
},
allowedSchemes: ['http', 'https', 'mailto'],
transformTags: {
'a': (tagName, attribs) => {
attribs.rel = 'noopener noreferrer';
return { tagName, attribs };
}
}
});
Здесь:
rel="noopener noreferrer",
что защищает от уязвимости tabnabbing.Если Markdown поступает из внешних источников (например, API или файловой системы), безопасная обработка может быть встроена в асинхронный поток данных:
import fs from 'fs/promises';
async function renderMarkdownFile(filePath) {
const markdown = await fs.readFile(filePath, 'utf-8');
const html = marked(markdown);
return sanitizeHtml(html, {
allowedTags: sanitizeHtml.defaults.allowedTags,
allowedAttributes: {
a: ['href', 'target']
}
});
}
renderMarkdownFile('example.md').then(cleanHtml => console.log(cleanHtml));
Такой подход позволяет безопасно рендерить Markdown из файлов или запросов пользователей без риска внедрения вредоносного кода.
<iframe> или
<object>, которые могут внедрять внешние
ресурсы.sanitize-html, настройка CSP в заголовках HTTP повышает
уровень безопасности.marked и
очищается через sanitize-html.marked позволяет настраивать собственный рендерер, что
позволяет дополнительно фильтровать или модифицировать элементы перед
передачей в sanitize-html:
const renderer = {
link(href, title, text) {
// Все ссылки открываются в новом окне
return `<a href="${href}" target="_blank" rel="noopener noreferrer">${text}</a>`;
}
};
const html = marked(markdown, { renderer });
const cleanHtml = sanitizeHtml(html);
Такой подход объединяет преимущества пользовательского контроля рендеринга и надёжной очистки HTML.
Интеграция marked и sanitize-html
обеспечивает безопасное отображение Markdown, сохраняя при этом
функциональность ссылок, форматирования текста и заголовков.