Алертами завален мониторинг, CPU упёрся в 100 %, API отвечает таймаутами, а сеть почти не шевелится. В логах — один странный запрос, после которого бэкенд завис. В такой картине легко заподозрить сетевую атаку, но нередко виновата одна кривая регулярка.
Какую проблему решаем
ReDoS — это отказ в обслуживании из-за регулярного выражения. Опасность не в трафике, а в том, что движок проверки строки начинает перебирать слишком много вариантов и съедает процессорное время.
Такое часто всплывает в валидации email, логинов, поисковых фильтров и форм обратной связи. Проблема особенно неприятна тем, что один короткий запрос способен повесить поток обработки, а иногда и весь сервис. Подобные инциденты по эффекту очень похожи на то, о чём мы уже писали в разборе атак на серверы и скрытый доступ к сетям, только источник беды тут внутри кода.
Что подготовить
Чтобы не гадать на глаз, держите под рукой сам шаблон регулярного выражения, пример входных данных и способ прогнать тест на худшем случае. Полезно иметь локальный стенд, где можно безопасно повторить проблему и посмотреть нагрузку на процессор.
Ещё один важный шаг — проверить, где именно в коде проходит пользовательский ввод. Часто узкое место прячется не в очевидной форме, а в вспомогательной проверке, которую никто давно не трогал.
Пошаговые действия
один. Найдите подозрительные выражения
Смотрите в первую очередь на вложенные квантификаторы вроде (a+)+, (.*)*, ([a-zA-Z]+)* и на пересекающиеся альтернативы. Именно они чаще всего запускают катастрофический бэктрекинг.
Если шаблон выглядит слишком «гибким» и принимает почти всё подряд, это уже повод насторожиться. Особенно когда он работает на длинных строках из внешнего ввода.
два. Проверьте, как он ведёт себя на плохом примере
Возьмите строку, которая почти подходит, но ломает совпадение в самом конце. В таком случае движок начинает откатываться назад и перебирать варианты разбиения строки на группы.
Для теста не нужны сложные инструменты — достаточно локального запуска и сравнения времени обработки на короткой и длинной строке. Если рост идёт не линейно, а резко, шаблон опасен.
три. Упростите регулярку
Чаще всего проблему решает удаление лишней вложенности, отказ от ненужных «жадных» участков и более точное описание допустимого формата. Если можно описать правило без сложных вложенных групп, так и делайте.
Иногда лучше разбить одну тяжёлую проверку на несколько простых. Это проще читать, легче тестировать и намного безопаснее для сервера.
четыре. Ограничьте длину ввода
Даже хороший шаблон не стоит пускать на бесконечную строку. Ограничение длины имени, email, комментария или поискового запроса сильно снижает риск зависания.
Для публичных форм это базовая гигиена. Если пользователь присылает 5 КБ туда, где ожидается 50 символов, такое поле надо резать ещё до проверки шаблоном.
пять. Разделяйте критичные проверки и тяжёлую логику
Не вешайте сложные шаблоны на горячий путь — например, на каждый запрос к API. Лучше вынести проверку в отдельный слой, где можно отлавливать задержки и быстро отключать проблемный сценарий.
Если вам нужно понять, как подобные ошибки выглядят в реальных продуктах, полезно посмотреть и на прикладные инциденты. В материале о закрытии уязвимости в серверном ПО хорошо видно, как одна слабая точка быстро превращается в операционную проблему.
шесть. Держите защиту на стороне инфраструктуры
Логи, лимиты по времени на обработку, таймауты и мониторинг CPU помогают заметить проблему раньше, чем её увидят пользователи. Это не лечит сам шаблон, но снижает ущерб.
Если сотрудники работают из поездов, кафе или аэропортов, не забывайте и о шифровании трафика на личных устройствах. В таком сценарии пригодится инструмент для защиты трафика в открытом Wi‑Fi, чтобы лишний раз не светить данные в чужой сети.
Как проверить себя
Задайте три простых вопроса. Может ли входная строка заставить движок долго откатываться назад? Есть ли в шаблоне вложенные повторения? Понятно ли, почему он не зависнет на длинном мусорном вводе?
Если на любой из этих вопросов нет уверенного ответа, регулярку надо пересмотреть. Хорошая проверка должна быть предсказуемой по времени, а не только «работать на тестовых примерах».
Что делать, если не получилось
Если шаблон уже уронил сервис, первым делом отключите или упростите проблемную проверку. Потом снимите нагрузку с узла, посмотрите, какие запросы её вызывают, и добавьте жёсткий лимит на размер входа.
Дальше — перепишите регулярку или замените её обычным разбором строки. Для критичных мест это часто надёжнее и дешевле, чем надеяться на сложный паттерн.
Практический чек-лист
- Проверить все регулярные выражения с вложенными квантификаторами
- Протестировать шаблоны на длинных почти совпадающих строках
- Ограничить длину пользовательского ввода до проверки
- Убрать лишнюю сложность из горячих путей API
- Поставить таймауты и следить за 100 % загрузкой CPU
- Переписать опасные шаблоны на более простые правила
- Проверить, нет ли похожих ошибок в формах, поиске и фильтрах
- Добавить локальный сценарий теста на ReDoS в CI
Комментарии (0)
Будьте уважительны. Спам и ссылки на сторонние сервисы скрываются модерацией.
Пока комментариев нет. Вы можете быть первым.