Чи є спосіб ввести шкідливий код у регулярний вираз?


138

Я хочу додати можливість регулярного пошуку виразів на своїй публічній веб-сторінці. Окрім HTML, що кодує вихід, чи потрібно мені щось робити, щоб захистити від зловмисного введення користувача?

Пошуки Google переповнюються людьми, що вирішують зворотну проблему - використовуючи регулярні вирази для виявлення шкідливого введення - що мене не цікавить. У моєму сценарії введення користувача є регулярним виразом.

Я буду використовувати бібліотеку Regex в .NET (C #).


4
Це може залежати від того, якою мовою та / або бібліотекою регулярних виразів ви користуєтесь.
aschepler

Ще кілька матеріалів для читання: ReDoS на OWASP , ReDoS у Вікіпедії
joeytwiddle

Відповіді:


216

Проблеми з відмовою в обслуговуванні

Найпоширеніша проблема, пов'язана з регулярними гексами, - це атака відмови в обслуговуванні через патологічні зразки, що переходять у експоненціальний - або навіть суперекспоненційний! - і так, здається, вічно вирішити. Вони можуть відображатися лише на певних вхідних даних, але загалом можна створити такі, де це не має значення.

Які з них є, залежатиме дещо від того, наскільки розумним буде компілятор регулярних виразів, який ви використовуєте, оскільки деякі з них можна виявити під час компіляції. Компілятори Regex, які реалізують рекурсію, зазвичай мають вбудований лічильник глибини рекурсії для перевірки непрогресування.

Відмінна праця Русса Кокса про збіг регулярних виразів 2007 року може бути простою і швидкою (але у Java, Perl, PHP, Python, Ruby, ...) розповідає про способи, якими більшість сучасних NFA, які, як видається, походять від коду Генрі Спенсера , зазнають серйозної деградації продуктивності, але там, де у НФА у стилі Томпсона таких проблем немає.

Якщо ви визнаєте лише шаблони, які можуть бути вирішені DFA, ви можете скласти їх як такі, і вони працюватимуть швидше, можливо, набагато швидше. Однак для цього потрібен час . У документі Кокса згадується такий підхід та супутні питання. Все зводиться до класичної торгівлі часом-простором.

З DFA ви витрачаєте більше часу на його створення (і виділення більше станів), тоді як з NFA ви витрачаєте більше часу на його виконання, оскільки він може бути одночасно декількома станами, а зворотний трек може з'їсти ваш обід - і ваш процесор.

Рішення про відмову в обслуговуванні

Напевно, найрозумніший спосіб вирішити ці зразки, які втрачають кінець гонки з тепловим смертю Всесвіту, - це обернути їх таймером, який фактично відводить максимальний час, дозволений для їх виконання. Зазвичай це буде набагато, набагато менше, ніж час очікування за замовчуванням, яке надає більшість серверів HTTP.

Існують різні способи їх застосування, починаючи від форми простої alarm(N)на рівні С, до якогось try {}блоку виловлює винятки типу тривоги, аж до нерестування нової нитки, створеної спеціально з обмеженням часу, вбудованим у неї.

Вимоги до коду

У мовах регулярних виразів, які допускають опис коду, слід надати певний механізм для дозволу або заборони їх із рядка, який ви збираєтеся скласти . Навіть якщо описи коду призначені лише для кодування на тій мові, яку ви використовуєте, ви повинні обмежити їх; вони не повинні мати можливість викликати зовнішній код, хоча якщо вони можуть, у вас є набагато більші проблеми.

Наприклад, у Perl не може бути додаткового опису коду в регексах, створених за допомогою рядкової інтерполяції (як це було б, як вони складаються під час виконання), якщо спеціальна лексично-обширна прагма не use re "eval";діє в поточному масштабі.

Таким чином, ніхто не може прокрастися в кодовому описі для запуску системних програм rm -rf *, наприклад. Оскільки описи коду є настільки чутливими до безпеки, Perl відключає їх за замовчуванням у всіх інтерпольованих рядках, і вам доведеться вийти зі свого шляху, щоб повторно увімкнути їх.

Визначено користувачем \ P {roperties}

Там залишається ще одна захисту чутливої проблеми , пов'язана з властивостями Unicode-стиль - як \pM, \p{Pd}, \p{Pattern_Syntax}або \p{Script=Greek}- що може існувати в деяких регулярних виразах компіляторів, підтримка, нотація.

Проблема полягає в тому, що в деяких із них набір можливих властивостей зручно для користувача. Це означає, що ви можете мати власні властивості, які є фактичним описом коду для іменованих функцій у певному просторі імен, наприклад, \p{GoodChars}або \p{Class::Good_Characters}. Як ваша мова поводиться з тими, можливо, варто подивитися.

Пісочниця

У Perl відсік з пісочним Safeмодулем через модуль дозволив би контролювати видимість простору імен. Інші мови пропонують подібні технології пісочниці. Якщо такі пристрої доступні, ви, можливо, захочете їх вивчити, оскільки вони спеціально розроблені для обмеженого виконання ненадійного коду.


4
Перетворення NFA-> DFA може призвести до вибуху експоненціального стану, перетворивши час DoS в простір DoS, а також витрати часу на генерування експоненціальної кількості станів.
Баррі Келлі

але, ймовірно, йому не знадобляться всі можливості регулярних виразів, що ви думаєте про обмеження сили регулярних виразів, як google зробив: google.com/intl/uk/help/faq_codesearch.html#regexp
systems default

1
@Barry Цілком правильно. Я думав про стратегію Русса Кокса, описану в одній із своїх робіт про поетапне складання частин NFA в еквівалентну DFA, але викинувши її, якщо вона надто велика. Але в DFA немає жодної срібної кулі, навіть якщо Томпсон виявив це еквівалентним NFA, тому що вам доведеться платити за піпера в той чи інший момент. Час, витрачений на прохання операційної системи отримати більше місця, і супутні витрати на налаштування таблиці сторінок, іноді можуть підштовхувати шкалу врівноваження далі іншим способом і роблять перетворення часу від простору менш привабливим, ніж було б.
tchrist

20

Додаючи відмінну відповідь tchrist: той самий Russ Cox, який написав сторінку "Regular Expression", також випустив код! re2 - бібліотека C ++, яка гарантує O (length_of_regex) час виконання та настроюваний ліміт використання пам'яті. Він використовується в Google, щоб ви могли ввести регулярний вираз у пошуковому коді Google - це означає, що він був протестований.


2
Дійсно так. Ви можете поміняти re2 в двигун регулярних виразів Perl за допомогою модуля, і він буде використовувати re2, якщо можливо, і Perl, якщо ні. Працює досить добре.
tchrist


6

Ви хочете прочитати цей документ:

Небезпечна комутація контексту: інокуляція регулярних виразів на життєздатність У статті розповідається про те, що може піти не так з двигунами регулярного вираження (наприклад, PCRE), але це може допомогти вам зрозуміти, що ви проти.


1
Ось рекомендації щодо безпеки щодо коду GNU libc regcomp (3): securityreason.com/achievement_securityalert/93 Як своєчасно! Принаймні, під Linux, вразливість легко продемонструвати: grep -E ". * {10,} {10,} {10,} {10,} {10,}"
Брюс Едігер

5

Ви повинні не тільки турбуватися про саму відповідність, але і про те, як ви робите відповідність. Наприклад, якщо ваш вхід проходить якусь фазу eval або заміну команд на шляху до двигуна регулярних виразів, може бути код, який виконується всередині шаблону. Або якщо ваш синтаксис регулярного вираження дозволяє вбудовувати команди, ви також повинні насторожено ставитися до цього. Оскільки ви не вказали мову у своєму питанні, важко точно сказати, які всі наслідки для безпеки.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.