flawopen.com/Что такое ReDoS/Explained
Что такое ReDoS (катастрофический возврат)?
Механизм регулярных выражений с возвратом может проверять разные способы разделить одну строку после неудачного совпадения. Для некоторых неоднозначных шаблонов число попыток растёт экспоненциально с длиной ввода. Задержка зависит от шаблона, механизма, размера ввода, параллелизма и ограничений ресурсов; повторные дорогие запросы могут исчерпать возможности сервиса.
# Nested quantifier ^(a+)+$ # Overlapping alternatives, quantified ^(a|aa)+$ # A long matching prefix plus a final mismatch can # force extensive retries in vulnerable engines. # Do not benchmark this with attacker-sized input.
# Bound input before matching, then use a simple # full-string identifier rule with no nested ambiguity. import re IDENTIFIER = re.compile(r"[a-z0-9]{1,64}\Z") def valid_identifier(value: str) -> bool: if not isinstance(value, str) or len(value) > 64: return False return IDENTIFIER.fullmatch(value) is not None # A bound reduces worst-case work; still set request # size, concurrency, and execution-time limits.
Почему возврат резко увеличивается
Шаблон вроде ^(a+)+$ неоднозначен для механизма с возвратом: aaaa можно разделить между вложенными квантификаторами несколькими способами. Завершающий несовпадающий символ может заставить механизм перебрать варианты, прежде чем он отклонит всю строку.
Для таких шаблонов число проверяемых путей может экспоненциально расти с длиной совпавшего префикса перед несовпадением. Это зависит от конкретной пары «шаблон — механизм», а не от любых регулярных выражений или сбоев. При параллельных запросах важны и короткие строки; ограничивайте размер ввода, параллелизм и время.
Где недоверенные данные попадают в регулярные выражения
Проверка ввода — очевидный случай, но риск также скрыт в обработке User-Agent и других заголовков, журналов, Markdown и подсветки синтаксиса, маршрутизации URL, фильтров контента и правил WAF, а также в библиотеках, применяющих regex к переданным полям. Популярные пакеты публиковали уведомления о ReDoS, поэтому зависимости важны не меньше собственных шаблонов.
Частые вопросы
Риск зависит от механизма и шаблона, а не только от языка. Некоторые механизмы с возвратом для отдельных шаблонов проверяют чрезмерное число вариантов. Документация Go для regexp гарантирует линейное время по длине ввода. Библиотека Rust regex указывает O(m·n) для одного поиска (m — размер шаблона, n — размер ввода), то есть линейно по n при фиксированном шаблоне; у итераторов повторного поиска другие худшие оценки. Эти механизмы не поддерживают, например, обратные ссылки, мешающие таким гарантиям.
Ограничение уменьшает возможный объём работы, но безопасное значение зависит от шаблона, механизма, частоты запросов и бюджета сервиса. Исправляйте неоднозначные шаблоны и вводите лимиты до разбора или сопоставления.
Используйте статический анализатор с проверкой ReDoS и сверяйте результаты с фактическим механизмом. Ищите повторяемые группы с вложенными повторениями или альтернативами с общими префиксами; затем тестируйте ограниченные данные со строгим таймаутом в изолированной среде.
Поддержка таймаутов зависит от среды выполнения и API. В .NET задавайте явный таймаут для сопоставления с недоверенным вводом. В остальных случаях проверяйте документацию конкретного механизма; выберите более безопасный механизм или переработайте шаблон, если применимого таймаута нет. Таймаут дополняет ограничения размера и параллелизма, но не делает неоднозначный шаблон эффективным.
Источники
- CWE-1333 — Inefficient Regular Expression Complexity
- OWASP — regular expression denial of service
- Go regexp package documentation
- Rust regex crate — performance and complexity
- .NET regular expression best practices
- Russ Cox — regular expression matching can be simple and fast
- Is JavaScript's RegExp vulnerable to ReDoS?