Оперативная реакция на DDoS-атаки

DDoS-network-mapОдин из ресурсов, за которым я присматриваю, вдруг стал неожиданно популярным как у хороших пользователей, так и у плохих. Мощное, в общем-то, железо перестало справляться с нагрузкой. Софт на сервере самый обычный — Linux, Nginx, PHP-FPM (+APC), MySQL, версии — самые последние. На сайтах крутится Drupal и phpBB. Оптимизация на уровне софта (memcached, индексы в базе, где их не хватало) чуть помогла, но кардинально проблему не решила. А проблема — большое количество запросов, к статике, динамике и особенно базе. Поставил следующие лимиты в Nginx:

на соединения

и скорость запросов на динамику (fastcgi_pass на php-fpm)

Сильно полегчало, по логам видно, что в первую зону никто не попадает, зато вторая отрабатывает по полной.

Но плохиши продолжали долбить, и захотелось их отбрасывать раньше — на уровне фаервола, и надолго.

Сначала сам парсил логи, и особо настырных добавлял через iptables в баню. Потом парсил уже по крону каждые 5 минут. Пробовал fail2ban. Когда понял, что плохишей стало очень много, перенёс их в ipset ip hash.

Почти всё хорошо стало, но есть неприятные моменты:
— парсинг/сортировка логов тоже приличное (процессорное) время отнимает
— сервер тупит, если началась новая волна между соседними разборками (логов)

Нужно было придумать как быстро добавлять нарушителей в черный список. Сначала была идея написать/дописать модуль к Nginx + демон, который будет ipset-ы обновлять. Можно и без демона, но тогда придётся запускать Nginx от рута, что не есть красиво. Написать это реально, но понял, что нет столько времени. Ничего похожего не нашёл (может плохо искал?), и придумал вот такой алгоритм.

При привышении лимита, Nginx выбрасывает 503-юю ошибку Service Temporarily Unavailable. Вот я решил на неё и прицепиться!

Для каждого location создаём свою страничку с ошибкой

И соответствующий именованный location

Дальше интересней.

Нам нужна поддержка CGI-скриптов. Ставим, настраиваем, запускаем spawn-fcgi и fcgiwrap. У меня уже было готовое для collectd.

Сам CGI-скрипт fc

Собственно всё очевидно, кроме, разве что, SQLite. Я его добавил пока просто для статистики, но в принципе можно использовать и для удаления устаревших плохишей из черного списка. Время 5 минут пока тоже не используется.

Черный список создавался вот так

Правило в iptables у каждого может быть своё, в зависимости от конфигурации и фантазии.

З.Ы.: Улыбнуло сообщение одного «хакера» на форуме, как быстро он положил сервер. Он и не догадывался, что это сервер положил на него.

Источник: http://habrahabr.ru/post/176119/

Защита Apache от DDOS-атак

Пару недель назад позвонил один знакомый и пожаловался, что плохо работает сайт и канал поменяли на FTTX с xDSL и тариф выбрали со скоростью повыше, но помогло мало — пользователи жалуются на HTTP/1.1 403 Forbidden. Сервер настраивал им не я, благо что установлена Ubuntu 10.04 LTS — люблю продукты семейства long time support — очень уж они хорошо. Получив доступ начал ковырять систему — первое что бросилось в глаза — практически пустой фаейр — десятка 2 правил на вход-выход ЛВС и сайта в мир. Набрав в консоли команду

— несколько секунд наблюдал строчки вида:

Сразу стало понятно — что сайт завален большим количеством syn-пакетов, потому так плохо и работает.


Удаленно ковырять файер не гут, потому ограничился минимумом — загнал в конфиг несколько дополнительных команд, заодно ограничил количество syn-пакетов до 500 в секунду, при превышении порога в 1500 — новые пакеты блокируются:

— выполняем с консоли и добавляем в /etc/rc.local на случай перезагрузки:

— добавляем в наш firewall-скрипт:

Портянка netstat стала существенно короче, но в логи все равно периодически выскакивала HTTP/1.1 403 Forbidden. Пришлось поковырять настройки apache2 — оказалось что подгружен mod_evasive — модуль для защиты от DOS/DDOS-атак, в принципе модуль неплохой, но для больших сайтов не годиться, потому решил что лучше его выключить и положиться на файер и настройки ядра, которые я сделал выше. Несколько дней понаблюдал за логами — HTTP/1.1 403 Forbidden выскочила раза 2-3, на том мы и остановились.

Вкратце о том что же за команды такие добавлены в настройки системы:

— tcp_syncookies — SYN cookies не использует очередь SYN, вместо этого ядро отвечает на каждый SYN пакет, как обычно SYN|ACK, но при этом в пакет будет включено специально сгенерированное число на основе IP адресов и портов источника и получателя, а также времени посылки пакета. Соответственно атакующий никогда не получит эти пакеты, а поэтому и не ответит на них. При реальном запросе, будет отправлен третий пакет, который содержащий число, а сервер проверит был ли это ответ на SYN cookie и, если да, то разрешит соединение даже в том случае, если в очереди SYN нет соответствующей записи. (З.Ы.: доступен только когда ядро собрано с CONFIG_SYNCOOKIES — тогда по умолчанию должен быть равен — 1)

— tcp_max_syn_backlog — размер очереди half-open connection (полуоткрытых соединений), по-умолчанию колеблется в диапазоне 1024-2048, лучше задавать от 15000 и выше.

— tcp_synack_retries — определяет сколько разрешено попыток повторной передачи пакетов SYNACK для пассивных соединений TCP. Не должно превышать 255. По-умолчанию значение 5 соответствует приблизительно 180 секундам на выполнение попыток организации соединения. Урезаем примерно до 9 секунд — присваиваем — 1.

— tcp_fin_timeout — определяет время сохранения сокета в состоянии FIN-WAIT-2 после его закрытия локальной стороной. Запрашивающая сторона может не закрыть это соединение никогда, поэтому следует закрыть его по своей инициативе по истечении тайм-аута. По умолчанию тайм-аут составляет 60 секунд, в некоторых старых ядрах linux — было 180 секунд. Если у WEB-сервера очень высокая нагрузкая смело поджимайте до 20-30.

— tcp_keepalive_probes — определяет keepalive-запросов, после которого соединение считается разорванным, По-умолчанию передается 9 запросов. Так как каналы у всех достаточно быстрые — жмем до 5, в принципе проблем не замечено и при 4, но когда из Нижних дыр юзеры лезут по диал-ап — могут быть проблемы.

— tcp_keepalive_intvl — определяет интервал передачи проб. Вычисляется как [tcp_keepalive_probes]*[tcp_keepalive_intvl] — результат дает нам время, по истечении которого соединение будет разорвано при отсутствии откликов. По умолчанию установлен интервал 75 секунд, таким образом разрыв соединения произойдет примерно через 675 секунд (больше 10 минут!!!!).

— netdev_max_backlog — определяет максимальное количество пакетов в очередь на обработку если интерфейс получает пакеты быстрее, чем ядро может их обработать. Для современного железа можно задавать высокие показатели, по-умолчанию 1000.

— somaxconn — определяет максимальное число открытых сокетов, ждущих соединения.

Источник: http://sysadminblog.ru/linux/2012/03/20/zaschita-ot-apache-ot-ddos-atak.html#comment921

Ограничение пропускной способности для ICMP-пакетов, с целью предотвращения DDoS-атак

Основная задача — настроить фильтры таким образом, чтобы пакеты, с исходящими адресами, не принадлежащими вашей сети, не смогли бы покинуть ее. Это предотвратит возможность отправки всякой «гадости» в Интернет.

Прежде, чем приступить к делу, нарисуем схему подключения локальной сети к Интернет:

[Интернет] —— [Linux router] — [Офис]
eth1 eth0

Зададим начальные условия:
# tc qdisc add dev eth0 root handle 10: cbq bandwidth 10Mbit avpkt 1000
# tc class add dev eth0 parent 10:0 classid 10:1 cbq bandwidth 10Mbit rate \
10Mbit allot 1514 prio 5 maxburst 20 avpkt 1000

Если у вас более высокоскоростное подключение — измените эти цифры соответствующим образом. Теперь необходимо определиться с «шириной» канала для ICMP-трафика. Чтобы найти типовое значение для вашей сети, можно воспользоваться утилитой tcpdump, запустив ее с перенаправлением вывода в файл. Затем, с помощью этого файла, вы сможете подсчитать количество ICMP-пакетов, отправляемых вашей сетью в единицу времени.
Если вариант подсчета экспериментальным путем вам не подходит, попробуйте ограничиться 10% общей пропускной способности. Построим наш класс:

# tc class add dev eth0 parent 10:1 classid 10:100 cbq bandwidth 10Mbit rate \
100Kbit allot 1514 weight 800Kbit prio 5 maxburst 20 avpkt 250 \
bounded

Он ограничивает пропускную способность канала величиной 100 Кбит/сек. А теперь подключим к нему фильтр для ICMP-пакетов:
# tc filter add dev eth0 parent 10:0 protocol ip prio 100 u32 match ip
protocol 1 0xFF flowid 10:100

http://docstore.mik.ua/manuals/ru/LARTC/x2502.html