flawopen.com/ReDoS/JavaScript RegExp
Уязвим ли JavaScript RegExp к ReDoS?
Представьте, что сотрудник пробует все способы разделить стопку бланков, когда на последнем нет отметки: неоднозначный шаблон заставляет regex-движок снова проверять одни и те же символы. Обычный путь RegExp в V8 может возвращаться назад; ограничение ввода и предсказуемый шаблон ограничивают работу. В Node синхронное сопоставление выполняется в потоке event loop и задерживает другие callbacks процесса. V8 описывает экспериментальный движок без backtracking, включаемый флагами и ограниченный по шаблонам; не считайте, что он включён в production.
// Неоднозначное вложенное повторение в данных запроса
const re = /^(\w+\s?)*$/;
app.post('/search', (req, res) => {
const q = req.body.q;
if (!re.test(q)) return res.sendStatus(400);
res.sendStatus(200);
});
// Ограничьте ввод и принимайте только грамматику поля
app.post('/search', (req, res) => {
const q = req.body.q;
if (typeof q !== 'string' || q.length > 128)
return res.sendStatus(400);
// Пример: только ASCII-буквы слова и пробелы
if (!/^[\w ]{1,128}$/.test(q))
return res.sendStatus(400);
res.sendStatus(200);
});
Почему Node.js усиливает последствия ReDoS
Синхронное сопоставление regex выполняется в потоке JavaScript, обслуживающем callbacks процесса Node.js. Если шаблон долго обрабатывает почти подходящую или не подходящую строку, event loop не может запускать другие callbacks и продвигать запросы, пока сопоставление не завершится. Workers, несколько процессов или реплик могут сохранить часть мощности, но затронутый процесс всё равно зависает.
Риск зависит от достижимости, сложности шаблона, ограничений ввода и топологии. Атакующий должен передать достижимому сопоставлению ввод, запускающий дорогой путь. Рассматривайте это как риск доступности затронутого процесса; отказ всего сервиса зависит от workers, реплик, маршрутизации и проверок здоровья.
Реальный случай npm: CVE-2026-83606 в xmldom
Проверенное уведомление для @xmldom/xmldom описывает CWE-1333 при разборе processing instruction: уязвимая грамматика позволяет жадной группе пробелов и ленивой группе данных поглощать одни пробелы. Если нет закрывающего ?>, парсер перебирает множество разбиений и работает квадратичное время. Затронуты версии 0.9.0-beta.9–0.9.10; в 0.9.11 разделитель перестал возвращать пробелы группе данных. Уведомление ограничивает проблему scoped-путём версии 0.9.x; ветка 0.8.x и пакет без scope не указаны как уязвимые.
Сканирование зависимостей полезно, но не доказывает безопасность regex
npm audit сообщает об известных уведомлениях для зависимостей в дереве проекта; он не анализирует каждое regex в коде и не обнаруживает неопубликованные ReDoS. Обновляйте прямые и транзитивные зависимости, проверяйте достижимость уязвимого кода и отдельно анализируйте шаблоны, обрабатывающие пользовательский текст.
npm audit --omit=dev
Аудит охватывает известные уведомления, а не все риски regex. Оцените отчёт с учётом развёртывания и отдельно проверьте, может ли недоверенный ввод вызвать дорогой матч и ограничена ли его длина.
Частые вопросы
У RegExp API нет тайм-аута на одно сопоставление. Используйте простой шаблон и ограничьте ввод до запуска. Если нужна сложная обработка, изолируйте её в worker или дочернем процессе с принудительным сроком завершения; это ограничит последствия, но не ускорит шаблон.
Да. Проблемное синхронное сопоставление может заморозить главный поток вкладки до завершения и заблокировать интерфейс. Ограничивайте ввод, упрощайте шаблон и не запускайте дорогой матч при каждом нажатии клавиши.
Считайте пользовательские шаблоны исполняемым вводом для потенциально дорогого сопоставления. Не принимайте произвольные шаблоны на сервере без строгих ограничений и изоляции. Если нужен буквальный поиск, экранируйте текст как regex-литерал или используйте API поиска по строке; экранирование не заменяет лимит длины.