Перейти к основному содержимому
Модуль 8 · Урок 4 из 432/32 в курсе~14 min
Уроки модуля (4/4)

Написание шаблонов, безопасных для ReDoS.

ReDoS (отказ в обслуживании по регулярному выражению) — это класс атак, при которых тщательно обработанные входные данные приводят к взрыву времени сопоставления регулярного выражения. Движок JS использует обратное отслеживание: если шаблон «неоднозначен», на неудачный ввод, он может выполнить экспоненциальное количество попыток.

Классический катастрофический образец

Code
Pattern: ^(a+)+$
Input:   "aaaaaaaaaaaaaaaaaaaaab"

Для сопоставления движок пытается все возможные разделы «а» между два квантора +. Для 20 "a" это 2^20 = ~1 миллион попыток. На 30 «а» — миллиард.

Другие опасные примеры:

  • (a*)*b -- "вложенные звезды".
  • (a|a)* -- перекрывающиеся альтернативы.
  • (\w+)+@ -- жадные группы с внешним квантором.

Как заметить опасность

Найдите эти структуры:

  1. Квантор внутри квантора: (...+)+, (...*)*, (...{n,})+.
  2. Перекрывающиеся альтернативы по квантору: (a|ab)*, (\w|\d)+.
  3. Повторяющийся просмотр вперед/назад со сложными альтернативами.

Защитный переписывание

Code
Dangerous:  ^(\w+\s+)+$
Safe:       ^(?:\w+\s+)*\w+$

Безопасная версия отделяет базовый случай от повторяющегося, удаляя двусмысленность. Другие методы:

  • Притяжательные квантификаторы (a++) – не поддерживаются в JS, но доступны в других движках. – Атомарные шаблоны ((?>...)) – нет в JS.
  • Ограничить длину ввода перед сопоставлением.
  • Тайм-аут при сопоставлении (редактор этого курса использует работника с тайм-аутом 500 мс).

Рекомендации по шаблонам, безопасным для ReDoS

  1. Убедитесь, что чередующиеся варианты являются взаимоисключающими (например, не используйте (a|a+)).
  2. Избегайте применения вложенных кванторов к перекрывающимся выражениям (например, (\\s*)*).
  3. Всегда отдавайте предпочтение определенным классам отрицательных символов ([^\\n]*), а не общей подстановочной точке (.*).

Попробуйте это

Упражнение#regex.m8.l4.e1
Попыток: 0Загрузка…

Выявляйте шаблоны повторяющихся букв, но безопасным для ReDoS способом. Используйте один класс символов, а НЕ вложенные группы, такие как (a+)+.

Загрузка редактора…
Показать подсказку

Замените опасный (а+)+ простым а+. Результат тот же, но безопасный.

Решение доступно после 3 попыток

Обзор упражнения

Упражнение#regex.m8.l4.e2
Попыток: 0Загрузка…

Распознавайте последовательность слов, разделенных пробелами, безопасным для ReDoS способом. Используйте структуру `(?:слово+пробелы+)*слово` вместо `(слово+пробел+)+`.

Загрузка редактора…
Показать подсказку

Замените группу захвата (\\w+\\s+)+ на непересекающуюся версию (?:\\w+\\s+)*\\w+.

Решение доступно после 3 попыток

Дополнительная задача

Упражнение#regex.m8.l4.e3
Попыток: 0Загрузка…

Make the vulnerable pattern `(\w+\s*)+:` which causes ReDoS safe, by removing the overlapping whitespace recursion.

Загрузка редактора…
Показать подсказку

Переместите пробел так, чтобы он не перекрывал групповое повторение: (?:\\w+\\s+)*\\w+:

Решение доступно после 3 попыток