Мы используем куки, чтобы пользоваться сайтом было удобно.
Хорошо
to the top

DoS-атака

22 Мар 2022

DoS-атака (аббревиатура от Denial of Service) — это атака с целью остановить или замедлить обработку запросов клиентов. DoS-атаки не имеют цели украсть или повредить данные клиентов. Сутью атаки является создание проблем с доступностью вычислительных ресурсов, из-за которых процессы не выполняются за приемлемое время. Вычислительными ресурсами обычно являются:

  • процессорное время;
  • объём оперативной памяти;
  • объём дисковой памяти;
  • пропускная способность сетевого канала;
  • пропускная способность канала ввода-вывода памяти.

Атаки могут быть разделены на две группы: DDoS (distributed denial-of-service) и DoS-атаки уровня приложения.

DDoS (distributed denial-of-service)

DDoS-атака достигается созданием огромного количества обычных клиентских запросов (входных данных) к API системы. Атака производится множеством устройств, поэтому и называется распределённой. Обычно для системы эти устройства и их запросы не имеют явных проблем для процессов её внутренней логики. Запросы не содержат вредоносных или использующих уязвимостей данных. Проблемы возникают, когда сетевой канал сервера не имеет достаточной пропускной способности для обработки всех запросов. Или вычислительные ресурсы машины, на которой установлен сервер, исчерпываются.

Для совершения атаки используются заранее заражённые устройства, которые делают запросы к цели по команде. Атакующим не требуется широкий сетевой канал, поэтому сетевая активность заражённого устройства может быть незаметна для владельца. Зачастую невозможно отличить реальных пользователей от заражённых атакующих. Такая ситуация может быть решена развёртыванием дополнительных ресурсов для системы на время атаки. Это может быть технически сложно и дорого, но едва ли существующим в системе данным клиентов будет нанесён урон.

DoS-атаки уровня приложения

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

Зачастую проблемы находятся в спецификациях и стандартах грамматик и форматов, откуда они в неявном виде переходят в парсеры и сериализаторы. Но ошибки в реализациях также не исключены.

Примером проблемы в стандартах и спецификациях является XEE-атака, для совершения которой требуется наличие API, принимающего XML-файлы. Если XML-парсер API сконфигурирован без защиты от разворачивания вложенных XML-сущностей, то может произойти исчерпание ресурсов машины парсером.

Некоторые другие уязвимости в коде также могут быть использованы для DoS-атак. Например, инъекция кода с большой вычислительной сложностью через XSS-уязвимость или SQL-инъекцию. Хотя эти уязвимости могут быть использованы для совершения более опасных атак для кражи и повреждения данных.

При неправильной архитектуре системы случайная DoS-атака может произойти даже без злого умысла. Ошибки в архитектуре системы могут быть причиной большого расхода ресурсов даже при работе с обычными данными. Например:

  • использование неэффективных алгоритмов с вычислительной сложностью больше O(n^2);
  • ошибки в условных конструкциях, приводящие к бесконечному циклу;
  • утечки памяти;
  • создание неэффективных SQL-скриптов, которые обрабатывают больше строк, чем требуется на самом деле;
  • создание неэффективных регулярных выражений и отсутствие ограничений по времени поиска текста.

Пример дефекта безопасности

Подробнее рассмотрим случай, когда обработка регулярных выражений может исчерпать ресурсы системы. Такая ситуация называется ReDoS (Regular Expression Denial of Service). Рассмотрим следующий код на языке C#:

string userInput = GetInput();
Regex regex = new Regex(@"(a+)+b");
bool isMatch = regex.IsMatch(userInput);
....

Выражение 'a+' декларирует найти одно вхождение или более символа 'a'. Выражение взято в скобки и в таком виде к нему применяется квантификатор '+'. Выражение '(a+)+' декларирует найти одно или более вхождений группы '(a+)'. Наконец, полное выражение декларирует найти символ 'b' после нахождения предыдущих подстрок. Минимально подходящая строка: 'ab'.

Это синтетический пример. Но он содержит пример ошибки катастрофического отката.

Для исследования возьмём строку 'aaaa'. В ней нет текста, который ищется регулярным выражением. Минимальной найденной подстрокой для '(a+)' будет один символ. Поэтому движок регулярных выражений будет перебирать всю строку в поиске 'b'. При неуспешном поиске движок отсекает последний символ в надежде, что среди новых комбинаций найдётся удовлетворяющая шаблону регулярного выражения.

  • Подстрока 'aaaa' соответствует выражению '(a+)+'. Но символ 'b' не найден. Поэтому движок делает отсечение на один символ.
  • Теперь 'aaa' соответствует '(a+)'. Последний символ создаёт соответствие '(a+)+'. 'b' не найден. Движок отсекает символ из 'aaa'.
  • Теперь 'aa' и 'aa' соответствуют '(a+)+'. Но все ещё нет соответствия полному шаблону. Движок отсекает символ второй группы 'aa'.
  • Теперь группы выглядят так 'aa' и 'a' и 'a'. Последний символ создаёт соответствие '(a+)+'. Провальная комбинация. Предпоследний символ создаёт соответствие '(a+)+'. Также провальная комбинация. Движок будет дробить группы по одному символу, как указано в группировке '(a+)'. И потом перебирать новые комбинации.

Этот механизм называется откатом, и движок переберёт всю строку. Время поиска растёт экспоненциально. Поэтому проблема называется катастрофическим откатом.

Итак, уязвимым регулярное выражение будет когда:

  • в нём есть группировка с повторением;
  • внутри повторяемой группировки также есть повторение.

Защититься от этой проблемы можно установкой ограничения по времени выполнения поиска:

string userInput = GetInput();
Regex regex = new Regex(@"(a+)+b", 
                        RegexOptions.None,
                        matchTimeout: TimeSpan.FromSeconds(1));
bool isMatch = regex.IsMatch(userInput);

Время поиска специфицируется аргументом 'matchTimeout'. Если это время будет превышено, произойдёт выброс исключения 'RegexMatchTimeoutException'.

Также побороть проблему поможет создание более точных регулярных выражений.

Дополнительные ссылки

Популярные статьи по теме


Комментарии (0)

Следующие комментарии next comments
close comment form
close form

Заполните форму в два простых шага ниже:

Ваши контактные данные:

Шаг 1
Поздравляем! У вас есть промокод!

Тип желаемой лицензии:

Шаг 2
Team license
Enterprise license
** Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности
close form
Запросите информацию о ценах
Новая лицензия
Продление лицензии
--Выберите валюту--
USD
EUR
RUB
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Бесплатная лицензия PVS‑Studio для специалистов Microsoft MVP
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Для получения лицензии для вашего открытого
проекта заполните, пожалуйста, эту форму
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Мне интересно попробовать плагин на:
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
check circle
Ваше сообщение отправлено.

Мы ответим вам на


Если вы так и не получили ответ, пожалуйста, проверьте, отфильтровано ли письмо в одну из следующих стандартных папок:

  • Промоакции
  • Оповещения
  • Спам