ReDoS (Regular Expression Denial of Service) — это тип уязвимости, связанный с чрезмерной сложностью регулярных выражений. В контексте библиотеки Markdown-it, которая активно использует регулярные выражения для парсинга текста, ReDoS может проявляться при обработке специально сформированных входных данных. Злоумышленник может создать текст, который вызывает экспоненциальное время выполнения одного или нескольких регулярных выражений, что приводит к зависанию или высокому потреблению ресурсов сервера.
Парсинг ссылок и изображений Markdown-it
использует регулярные выражения для распознавания синтаксиса
[текст](url) и . Сложные или
некорректно сформированные строки, особенно с большим количеством
вложенных скобок, могут вызвать длинное выполнение регулярных
выражений.
Обработка эмодзи и HTML-тегов Встроенные правила для эмодзи и HTML-тегов используют выражения, которые пытаются сопоставить открывающие и закрывающие теги. Злоумышленник может создать строку с множеством частично закрытых тегов, что замедлит процесс парсинга.
Множественные блоки и вложенные списки Markdown-it строит структуру документа через вложенные блоки, где каждое регулярное выражение запускается рекурсивно. Глубоко вложенные конструкции могут создать сценарий экспоненциального времени обработки.
1. Ограничение длины входных данных Перед передачей строки в Markdown-it рекомендуется проверять размер текста. Например:
const MAX_LENGTH = 10000;
if (input.length > MAX_LENGTH) {
throw new Error('Входной текст слишком большой');
}
2. Использование таймаутов для парсинга Для серверных приложений важно ограничивать время обработки Markdown:
const { Worker, isMainThread, parentPort } = require('worker_threads');
function parseMarkdownWithTimeout(input, timeout = 1000) {
return new Promise((resolve, reject) => {
const worker = new Worker('./markdownWorker.js', { workerData: input });
const timer = setTimeout(() => {
worker.terminate();
reject(new Error('Превышено время обработки Markdown'));
}, timeout);
worker.on('message', result => {
clearTimeout(timer);
resolve(result);
});
worker.on('error', err => {
clearTimeout(timer);
reject(err);
});
});
}
3. Минимизация использования уязвимых плагинов Markdown-it поддерживает плагины для расширенного синтаксиса. Некоторые плагины могут содержать сложные регулярные выражения. Рекомендуется:
4. Очистка HTML и фильтрация пользовательского ввода Markdown-it позволяет вставлять HTML-теги. Для защиты от ReDoS и XSS одновременно следует использовать строгие фильтры, например DOMPurify или собственные проверки:
const DOMPurify = require('dompurify')(new JSDOM('').window);
const cleanHtml = DOMPurify.sanitize(parsedHtml);
5. Ограничение глубины вложенности Markdown-it обрабатывает вложенные блоки рекурсивно. Ограничение глубины вложенности предотвращает сценарии экспоненциальной обработки:
const md = require('markdown-it')({
maxNesting: 20
});
const md = require('markdown-it')({
html: false
});
Изоляция парсинга в отдельном процессе Это позволяет серверу оставаться устойчивым, даже если входные данные вызывают зависание.
Лимит на размер отдельных блоков Можно проверять длину заголовков, ссылок и списков отдельно, предотвращая глубокую рекурсию для одной конструкции.
Использование этих инструментов позволяет заранее обнаруживать опасные шаблоны и заменять их безопасными альтернативами.
Правильная конфигурация библиотеки, ограничение входных данных и изоляция парсинга являются ключевыми элементами безопасной работы. Markdown-it, как мощный парсер Markdown, требует осознанного подхода к обработке потенциально опасного пользовательского контента, особенно в публичных веб-приложениях и сервисах.