Markdown-it — это современная библиотека для парсинга Markdown в JavaScript, обладающая высокой настраиваемостью через плагины и правила рендеринга. Один из аспектов, который требует особого внимания при работе с Markdown-it, — инъекции через ссылки, поскольку Markdown позволяет создавать гиперссылки с произвольным содержимым и атрибутами, что потенциально может стать вектором XSS-атак при неправильной обработке.
Markdown-it парсит ссылки с использованием правил
link_open и link_close. Любая ссылка в
Markdown, например:
[текст ссылки](https://example.com)
разбивается на несколько токенов:
link_open — токен, содержащий атрибут
href.inline — внутренний токен с текстом
ссылки.link_close — закрывающий токен.При этом библиотека по умолчанию не фильтрует содержимое
атрибута href, оставляя это на усмотрение
разработчика, что открывает возможность для внедрения вредоносного
JavaScript кода через ссылки вида:
[нажми меня](jav * ascript:alert('XSS'))
Основные сценарии, где возможны инъекции через ссылки:
jav * ascript: или data:text/html.onclick, onmouseover и другие атрибуты, если
они добавлены через плагины или кастомные правила.html: true в конфиге).Markdown-it при стандартной конфигурации позволяет безопасно
рендерить Markdown, но при использовании html: true или
кастомных правил рендеринга разработчик берёт на себя ответственность за
безопасность.
Для предотвращения инъекций важно фильтровать и проверять
атрибут href. Например, можно использовать
встроенную функцию для проверки протоколов:
const md = require('markdown-it')();
md.renderer.rules.link_open = (tokens, idx, options, env, self) => {
const hrefIndex = tokens[idx].attrIndex('href');
if (hrefIndex >= 0) {
const href = tokens[idx].attrs[hrefIndex][1];
if (!/^https?:\/\//i.test(href)) {
tokens[idx].attrs[hrefIndex][1] = '#';
}
}
return self.renderToken(tokens, idx, options);
};
В этом примере все ссылки, не начинающиеся с
http:// или https://, заменяются на безопасную
заглушку #, предотвращая выполнение JavaScript
через ссылку.
Markdown-it имеет систему плагинов, которые позволяют безопасно обрабатывать ссылки:
rel="nofollow noopener noreferrer" к ссылкам.Пример использования markdown-it-link-attributes:
const md = require('markdown-it')();
const linkAttributes = require('markdown-it-link-attributes');
md.use(linkAttributes, {
pattern: /^https?:\/\//,
attrs: {
rel: 'nofollow noopener noreferrer',
target: '_blank'
}
});
Эта настройка гарантирует, что все внешние ссылки будут безопасно открываться в новом окне и не будут передавать управление JavaScript на страницу.
Markdown-it позволяет включать HTML напрямую через опцию
html: true. Если эта опция включена, необходимо
дополнительно санитизировать HTML:
const DOMPurify = require('dompurify');
const { JSDOM } = require('jsdom');
const window = new JSDOM('').window;
const purify = DOMPurify(window);
const rawHtml = '<a href="jav * ascript:alert(1)">Click me</a>';
const safeHtml = purify.sanitize(rawHtml);
Такой подход предотвращает XSS, даже если Markdown содержит опасные ссылки или HTML-теги.
href.html: true.href.Инъекции через ссылки в Markdown-it возникают в основном из-за
небезопасных протоколов или разрешённого HTML. Системная фильтрация,
плагины для безопасности и санитизация HTML позволяют безопасно работать
с Markdown и минимизировать риск XSS. Настройка рендерера ссылок через
правила link_open — основной инструмент для контроля
безопасности.