Модульні уроки (4/4)
Написання ReDoS-безпечних шаблонів
ReDoS (регулярний вираз відмова в обслуговуванні) – це клас атак, де ретельно створений вхідний сигнал робить час збігу регулярного виразу розбитим. Механізм JS використовує зворотне відстеження: якщо шаблон «неоднозначний», на an невдалий вхід він може виконати експоненціальну кількість спроб.
Класична катастрофічна модель
Pattern: ^(a+)+$
Input: "aaaaaaaaaaaaaaaaaaaaab"Щоб зіставити, механізм намагається кожне можливе розділення "a" між ними
два квантори +. На 20 "а" це 2^20 = ~1 мільйон спроб.
На 30 «а» мільярд.
Інші небезпечні приклади:
(a*)*b-- "вкладені зірочки".(a|a)*-- альтернативи, що збігаються.(\w+)+@-- жадібні групи із зовнішнім квантором.
Як помітити небезпеку
Шукайте такі структури:
- Квантор всередині квантифікатора:
(...+)+,(...*)*,(...{n,})+. - Альтернативи, що збігаються під квантором:
(a|ab)*,(\w|\d)+. - Огляд вперед/позаду зі складними альтернативами повторюється.
Захисне переписування
Dangerous: ^(\w+\s+)+$
Safe: ^(?:\w+\s+)*\w+$Безпечна версія відокремлює базовий випадок від повторюваного, видаляючи неоднозначність. Інші техніки:
- Присвійні квантифікатори (
a++) -- не підтримуються в JS, але доступні в інших механізмах. - Атомарні шаблони (
(?>...)) -- не в JS. - Обмежте довжину вхідних даних перед відповідністю.
- Тайм-аут під час відповідності (редактор цього курсу використовує воркер із тайм-аутом 500 мс).
Рекомендації щодо ReDoS-безпечних шаблонів
- Переконайтеся, що варіанти чергування є взаємовиключними (наприклад, не використовуйте
(a|a+)). - Уникайте застосування вкладених кванторів до виразів, що накладаються (наприклад,
(\\s*)*). - Завжди віддавайте перевагу конкретним запереченим класам символів (
[^\\n]*) над загальною крапкою підстановки (.*).
Спробуйте
Визначте шаблони повторюваних літер, але безпечним для ReDoS способом. Використовуйте один клас символів, а НЕ вкладені групи, такі як (a+)+.
Показати підказку
Замініть небезпечний (a+)+ простим a+. Результат той же, але безпечний.
Рішення доступне після 3 спроб
Повторна вправа
Розпізнавайте послідовність слів, розділених пробілами, безпечним для ReDoS способом. Використовуйте структуру `(?:слово+пробіл+)*слово` замість `(слово+пробіл+)+`.
Показати підказку
Замініть групу захоплення (\\w+\\s+)+ на непересічну версію (?:\\w+\\s+)*\\w+.
Рішення доступне після 3 спроб
Додатковий виклик
Make the vulnerable pattern `(\w+\s*)+:` which causes ReDoS safe, by removing the overlapping whitespace recursion.
Показати підказку
Перемістіть пробіл, щоб він не накладався на повторення групи: (?:\\w+\\s+)*\\w+:
Рішення доступне після 3 спроб