XSS (Cross-Site Scripting) представляет собой класс уязвимостей веб-приложений, при котором злоумышленник может внедрять вредоносный JavaScript-код в страницы, отображаемые пользователям. В контексте использования библиотеки Marked, основной риск связан с рендерингом Markdown, который может содержать потенциально опасный HTML-код.
Любой Markdown-контент, получаемый из ненадёжного источника
(например, пользовательский ввод или внешние API), может включать
<script>-теги или встроенные обработчики событий
(onclick, onmouseover и другие). Если Marked
рендерит такой контент без фильтрации, это приведёт к выполнению
вредоносного скрипта в браузере посетителя.
Библиотека Marked предоставляет несколько способов контролировать безопасный рендеринг:
Опция sanitize До версии 1.0.0
существовала встроенная опция sanitize: true, которая
автоматически экранировала HTML-теги. В современных версиях Marked этот
подход удалён, что делает необходимым использование сторонних средств
фильтрации HTML.
Опция mangle Опция отвечает за
защиту email-адресов от спама. Она также влияет на обработку текста и
может частично препятствовать внедрению некоторых видов
HTML-инъекций.
Опция breaks Позволяет управлять
разрывами строк, но не влияет на XSS напрямую. Важно понимать, что
Markdown-разрывы сами по себе безопасны.
Экранирование HTML-кода Вместо того чтобы
полностью доверять Marked, необходимо предварительно экранировать все
HTML-теги. Например, с использованием сторонней библиотеки вроде
DOMPurify:
import { marked } from 'marked';
import DOMPurify from 'dompurify';
const rawMarkdown = "<img src=x oner ror=alert('XSS')>";
const html = marked(rawMarkdown);
const safeHtml = DOMPurify.sanitize(html);
Здесь DOMPurify удаляет все опасные теги и атрибуты,
оставляя безопасный HTML.
Отключение встроенного HTML в Marked Marked
позволяет полностью игнорировать HTML, используя опцию gfm
и специальный токенизатор:
marked.setOptions({
gfm: true,
headerIds: false,
mangle: false
});
const lexer = new marked.Lexer({ sanitize: false, walkTokens: (token) => {
if (token.type === 'html') {
token.type = 'text';
}
}});
const html = marked.parser(lexer.lex(rawMarkdown));
Такой подход предотвращает рендеринг любых HTML-тегов, оставляя только безопасный Markdown.
Контроль атрибутов и ссылок Даже если HTML
разрешён, необходимо фильтровать опасные атрибуты, такие как
on* события, jav * ascript: в ссылках и
data: в изображениях. В DOMPurify это настраивается через
конфигурацию:
const clean = DOMPurify.sanitize(html, {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'p', 'ul', 'li', 'img'],
ALLOWED_ATTR: ['href', 'src', 'alt', 'title'],
FORBID_ATTR: ['onclick', 'onerror']
});Регулярное обновление библиотек XSS-уязвимости могут скрываться в старых версиях Marked или зависимостей. Поддержание актуальной версии библиотеки снижает риск внедрения новых атак.
onerror и
использовать jav * ascript: в src. Их следует
фильтровать и при необходимости заменять на безопасные
альтернативы.jav * ascript: протоколом
способны инициировать выполнение скриптов. Их необходимо проверять перед
вставкой в DOM.Эти меры позволяют безопасно использовать Marked в веб-приложениях, минимизируя риски XSS-атак.