Что такое атака ReDoS и как убедиться в безопасности своего кода?

Что такое DoS?

Я рассказывал об этом в нескольких более ранних постах, но DoS означает отказ в обслуживании. Отказ в обслуживании - это тип кибератаки, при которой злоумышленник пытается нарушить доступность службы, приложения или компании. DoS-атаки обычно относятся к одной из двух широких категорий: отказ в обслуживании (DoS) и распределенный отказ в обслуживании (DDoS). Оба имеют одно и то же общее намерение, но принимают очень разные формы. В рамках DoS есть атаки на основе сети и атаки на основе приложений.

Атаки на уровне приложений, также иногда называемые атаками уровня 7, включают в себя нагрузку на программное обеспечение, обслуживающее запросы, таким образом, чтобы оно не могло обрабатывать дополнительные запросы - это то, на что мы будем обращать внимание при атаке ReDoS.

Что такое регулярное выражение?

Прежде чем мы сможем взглянуть на ReDoS, нам нужно понять, что такое Regex и почему он используется. Regex означает регулярное выражение. Регулярные выражения впервые обсуждались как концепция в начале 50-х годов математиками и теми, кто интересуется теоретической информатикой. Regex не получил широкого распространения до конца 60-х годов, когда его использовали для решения двух основных задач; сопоставление с образцом в текстовых редакторах и лексический анализ в компиляторах. Я не буду слишком углубляться в то, как работает регулярное выражение, поскольку существует множество других ресурсов по этой теме.

На очень (очень) высоком уровне реализация регулярных выражений в большинстве языков программирования строит так называемый недетерминированный конечный автомат (NFA). В эти конечные автоматы передаются входные данные, и они проверяют каждый возможный путь до тех пор, пока не будет найдено совпадение или все пути не будут исчерпаны. Вся промежуточная работа отбрасывается после каждой проверки. Хотя существуют альтернативные реализации, NFA - это тип реализации, восприимчивый к ReDoS, поскольку решения для тестирования могут быть экспоненциальными.

Сегодня регулярное выражение невероятно широко используется для сопоставления с образцом во всем: от браузеров, прокси, межсетевых экранов, инструментов сканирования безопасности, веб-серверов и отдельных приложений. Достаточно сказать, что риск отказа в обслуживании на любом или всех этих этапах является серьезным риском.

ReDoS

ReDos, также известное как Evil Regex, - это регулярное выражение, которое при очень специфическом вводе может привести к экспоненциальному времени обработки. Это экспоненциальное время обработки вызовет чрезмерную загрузку ЦП и может блокировать обработку других запросов.

ReDoS стал печально известным в 2016 году, когда неправильно настроенное регулярное выражение случайно отключило Stackoverflow.



Так как же выглядит Evil Regex? На самом деле это намного проще, чем можно было ожидать.

В качестве примера того, насколько все замедляется, вот быстрый пример сценария с использованием модуля стандартной библиотеки python, re, который я запускал на своем ноутбуке.

Примеры из реального мира

Поскольку теоретические примеры никогда не приносят наибольшего удовлетворения, я попытался найти какой-нибудь публичный код, уязвимый для ReDoS. Поиск на Github в этом отношении немного ограничивает, поэтому я немного поиграл в Google. Мне повезло с этим типом поиска"*)*" site:github.com filetype:py. Я не буду сообщать фактические источники ниже, но я уведомил владельцев репозитория.

Защита

Есть несколько способов защитить себя от атак ReDoS.

  • Взгляните на более безопасные альтернативные библиотеки, такие как pyre2 от Facebook, которая представляет собой оболочку Python для библиотеки регулярных выражений C ++ от Google, re2.
  • Всегда дважды проверяйте все регулярные выражения, которые вы добавляете в свое приложение, и никогда не доверяйте шаблонам регулярных выражений, которые вы найдете в Интернете.
  • Используйте инструменты SAST и фаззинга для тестирования собственного кода и проверьте Ochrona, чтобы убедиться, что ваши зависимости не уязвимы для атак ReDoS.
  • Если возможно, ограничьте длину ввода, чтобы не было строк длиннее, чем необходимо.