Экранирование пользовательского контента — ключевой аспект безопасности при работе с текстом, вводимым пользователями, особенно в веб-приложениях, где текст может содержать HTML или Markdown-разметку. Библиотека Marked для JavaScript предоставляет удобные инструменты для обработки Markdown, но требует тщательного контроля ввода для предотвращения XSS-атак и других уязвимостей.
Внедрение HTML и скриптов Markdown позволяет
вставлять HTML-теги напрямую. Без экранирования
<script>, <img onerror> или
<iframe> могут быть выполнены в браузере
пользователя, что представляет серьезную угрозу.
Атрибуты с вредоносным кодом Даже безопасные
теги, такие как <a> или <img>,
могут содержать опасные атрибуты (href="jav * ascript:...",
onmouseo ver="..."), которые активируют выполнение
скриптов.
Разделение контента и разметки Markdown создаёт структуру документа, но для безопасности необходимо отделять контент пользователя от разметки, либо корректно экранировать опасные элементы.
1. Встроенные опции безопасности
Marked предоставляет опцию sanitize, которая
автоматически фильтрует HTML-теги в Markdown. Пример:
import { marked } from 'marked';
const rawMarkdown = 'Пример <script>alert("XSS")</script>';
const html = marked(rawMarkdown, { sanitize: true });
console.log(html); // Выведет "Пример "
Важно: начиная с версии 1.x, опция
sanitize считается устаревшей. Вместо неё рекомендуется
использовать внешний санитайзер, например,
DOMPurify.
2. Использование кастомных рендереров
Marked позволяет определить собственный рендерер для элементов Markdown:
import { marked } from 'marked';
const renderer = new marked.Renderer();
renderer.link = function(href, title, text) {
const safeHref = DOMPurify.sanitize(href);
return `<a href="${safeHref}" title="${title || ''}">${text}</a>`;
};
const markdown = '[Google](jav * ascript:alert("XSS"))';
const html = marked(markdown, { renderer });
console.log(html); // Ссылка безопасна
Этот подход позволяет экранировать опасные атрибуты и контролировать генерацию HTML на уровне каждого элемента.
3. Преобразование HTML в безопасный текст
Если не требуется HTML-разметка, а Markdown нужен только для форматирования, можно использовать функцию экранирования:
function escapeHtml(str) {
return str
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
const rawMarkdown = 'Пример <b>текста</b>';
const html = escapeHtml(rawMarkdown);
console.log(html); // Превратит <b> в безопасный текст
Комбинация escapeHtml и Marked без включения HTML-тегов
гарантирует, что весь пользовательский контент останется безопасным.
Marked позволяет гибко настраивать парсер через опции:
gfm: включает расширенный синтаксис
GitHub Flavored Markdown, полезен для форматирования таблиц и
чекбоксов.headerIds: управление генерацией
идентификаторов заголовков; важно для предотвращения конфликтов и XSS
через id.mangle: автоматическое преобразование
email в безопасные ссылки, защищает от спам-ботов.smartypants: преобразует кавычки и
тире, не влияя на безопасность, но улучшает читаемость текста.Пример безопасного парсинга с DOMPurify:
import DOMPurify from 'dompurify';
import { marked } from 'marked';
const markdown = 'Пример [ссылки](jav * ascript:alert("XSS"))';
const rawHtml = marked(markdown);
const safeHtml = DOMPurify.sanitize(rawHtml);
console.log(safeHtml); // Безопасный HTML для вставки на страницу
Экранирование пользовательского контента — фундамент для безопасного веб-приложения. При работе с Markdown важно комбинировать функции Marked с внешними санитайзерами, контролировать рендеринг ссылок и изображений и никогда не доверять сырому вводу напрямую.