48 часов боевого дежурства: как мы тушили DDoS-волну 24-25 февраля
24-25 февраля несколько клиентов одновременно под атакой. Переключаем трафик через scrubbing, раздаём инструкции по iptables. Хроника 48 часов в режиме дежурства.
24-25 февраля 2022: масштабные DDoS-атаки на российские банки, госпорталы и корпоративную инфраструктуру
Прошлую волну мы разбирали десять дней назад - тогда ещё можно было говорить об «аномальном фоне» и методично пересматривать конфиги в рабочем порядке. 24 февраля фон закончился. Пошла стена.
Это хроника двух суток, в которые несколько клиентов оказались под атаками одновременно, а команда работала в режиме боевого дежурства без нормального сна.
Как это начиналось
Первые сигналы пошли примерно в промежутке раннего утра 24-го. Grafana по двум клиентским площадкам показала аномальный рост входящего трафика - в разы выше ночной нормы. Не постепенный, а резкий. Через час подключился третий клиент с похожей картиной, потом четвёртый.
Атаки были разнородные: на одной площадке - объёмный UDP-флуд на L3/L4, явно ботнетный, с характерным распределением источников. На другой - HTTP-флуд по публичным эндпоинтам, значительно меньший по объёму, но целенаправленный: запросы шли на тяжёлые страницы с полнотекстовым поиском. Третья площадка получила что-то среднее между двумя.
К обеду стало понятно, что это не случайное совпадение всплесков. Масштаб атак на российскую инфраструктуру в этот день был виден невооружённым глазом - новости от операторов связи, телеграм-каналы по ИБ, жалобы коллег в рабочих чатах. Мы оказались внутри общей ситуации, а не просто разбирали очередной инцидент клиента.
Что делали в первые часы
Приоритизация и распределение. Четыре площадки одновременно - это много для синхронной работы. Сначала быстро оценили, у кого критичнее: у кого публичный сервис с реальными пользователями и у кого внутренняя инфраструктура с запасом прочности. Начали с критичных.
Переключение трафика через upstream-scrubbing. Там, где у клиентов был договор с провайдером на scrubbing-центр - запросили переключение. Это не мгновенная операция: нужно подать заявку, провайдер перенаправляет трафик через фильтрующую инфраструктуру, потом трафик возвращается к нам уже очищенным. На это ушло от 20 минут до полутора часов в зависимости от провайдера и дня нагрузки на их NOC. Одна площадка через scrubbing более-менее стабилизировалась, у второй эффект был частичным - атака шла через несколько AS, и scrubbing помог только по части источников.
Ручные iptables-блокировки там, где scrubbing не было. Для площадок без договора на managed-фильтрацию единственный быстрый инструмент - прямые блокировки на хосте. Составляли списки подсетей по данным из логов nginx и tcpdump, передавали клиентам скрипты вида:
# блокировка подсети-источника флуда
iptables -I INPUT -s 185.220.0.0/16 -j DROP
# блокировка по диапазону портов для UDP-флуда
iptables -I INPUT -p udp --dport 1:1024 -m limit --limit 1000/s --limit-burst 2000 -j ACCEPT
iptables -I INPUT -p udp --dport 1:1024 -j DROP
Это паллиатив, а не решение. Ботнет с десятками тысяч IP-адресов не заблокируешь руками. Но для снижения нагрузки на период до включения более серьёзных инструментов - работает. Несколько сотен строк в ipset и нагрузка на nginx падает вдвое.
Связь с клиентами. Это отдельная работа, которую часто недооценивают. Когда у клиента не открывается сайт, он хочет понимать что происходит и что делают. Мы держали их в курсе каждые 30-60 минут - не "всё под контролем", а конкретно: что видим, что пробуем, почему ещё не работает.
Ночь и следующие сутки
Ночью атаки не прекратились. Это важный момент: ботнеты не спят по московскому времени. Дежурили посменно - кто-то мониторит и реагирует, остальные отдыхают по возможности.
К утру 25-го картина немного прояснилась. Две площадки стабилизировались через scrubbing. Одна работала с деградацией - атака трансформировалась, и фильтры провайдера стали пропускать больше. Пришлось докручивать rate limiting на nginx вручную, добавлять geo-блокировку по базе GeoIP для нероссийских подсетей (для этого клиента аудитория строго локальная).
Четвёртая площадка - та, где HTTP-флуд на тяжёлые эндпоинты - потребовала другого подхода. Объём трафика там был не критический, но запросы шли на /search с параметрами, которые генерировали неоптимальные планы запросов в PostgreSQL. Каждый такой запрос висел несколько секунд, пул соединений лёг. Решение нашлось не через сетевую фильтрацию, а через кеширование результатов поиска на уровне приложения и добавление таймаута запроса. Банально, но помогло.
Что обнаружили в процессе
Несколько наблюдений, которые хочется зафиксировать пока горячо.
Договор на scrubbing без предварительного тестирования - бумага. У одного клиента договор с провайдером на защиту от DDoS был. Но никто никогда не проверял, как именно происходит переключение и сколько это занимает. В момент атаки выяснилось, что процедура требует звонка дежурному инженеру провайдера (не заявки в личный кабинет), и этот телефон в документах не был указан. Потратили лишние 40 минут.
ipset быстрее iptables с большими списками. Когда список блокируемых подсетей перевалил за несколько сотен - обычные iptables-правила начали ощутимо нагружать ядро при каждом пакете. Переход на ipset с hash:net дал заметное снижение нагрузки на CPU. Это надо было сделать сразу, но в горячке не подумали.
Атакующие адаптируются. Примерно через 6-8 часов после первых блокировок характер атаки на одной площадке изменился - сменились диапазоны IP, поменялся паттерн запросов. Не сильно, но достаточно, чтобы часть правил перестала работать. Это не магия - просто у оператора ботнета есть обратная связь, и он видит снижение эффекта.
Мониторинг нагрузки на iptables - отдельная задача. Мы увлеклись тушением и не сразу заметили, что на одном хосте CPU ушёл под 90% из-за разросшихся правил. Хорошо что Grafana показала - иначе могли бы потушить DDoS и одновременно уронить сервер другим способом.
Где мы сейчас
Вечером 25-го ситуация более-менее стабилизировалась по всем площадкам - кто через scrubbing, кто через iptables+ipset, кто через комбинацию. Никто не лежит, но работаем в режиме повышенного мониторинга.
Атаки продолжаются в целом по рунету, и нет оснований считать, что это последняя волна. Что делаем параллельно с тушением: оформляем договоры на scrubbing для тех клиентов, у кого их не было; документируем процедуры переключения с контактами дежурных; готовим ansible-плейбуки для быстрого разворачивания ipset-правил. Всё то, что надо было сделать заранее - делаем сейчас.
Это работа в рамках managed-сопровождения, и именно в такие моменты понимаешь, что "managed" - не просто слово в договоре. Это значит, что в 3 ночи есть кому смотреть в мониторинг и реагировать, пока клиент спит.