Отражение DDOS атаки с использованием nginx, ipset, fail2ban и bash
Имеем:
Ботнет, генерирующий ~20.000 соединений в секунду. Входящий траффик ~70 Мб/с.
В логе апача картина:
187.2.194.149 — — [15/Mar/2012:17:46:31 +0300] «GET /forum/topic/102808-ddos-uslugizakazat-ddosddos-attackddos-uslugi/ HTTP/1.0» 502 173 «-» «Mozilla/4.0 (compatible; MSIE 6.0; Symbian OS; Nokia 6600/5.27.0; 6936) Opera 8.50 [ru]»
41.134.194.89 — — [15/Mar/2012:17:46:31 +0300] «GET /forum/topic/102808-ddos-uslugizakazat-ddosddos-attackddos-uslugi/ HTTP/1.0» 502 173 «-» «Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.9) Gecko/20050711 Firefox/1.0.5»
79.173.200.41 — — [15/Mar/2012:17:46:31 +0300] «GET /forum/topic/102808-ddos-uslugizakazat-ddosddos-attackddos-uslugi/ HTTP/1.0» 502 575 «-» «Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)»
Итак, у нас однотипные запросы с постоянно меняющимся UA. К слову, через некоторое время атака поменялась и пошли запросы
GET /
и
POST /
1. Усиливаем TCP стек: #cat /etc/sysctl.conf
net.ipv4.tcp_syncookies=1 net.ipv4.tcp_tw_recycle=1 net.ipv4.tcp_tw_reuse=1 net.ipv4.tcp_keepalive_time=10 net.ipv4.tcp_fin_timeout=5
2. Пробуем отбиться силами nginx
Страницу, на которую производится атака, отправляем в кэш и выводим в отдельный лог, который потом будет банить.
#cat /etc/nginx/sites-avaible/www.site.ru
location /forum/topic/102808-ddos-uslugizakazat-ddosddos-attackddos-uslugi/{ limit_req zone=one burst=2; proxy_cache pagecache; proxy_cache_key "$request_uri"; proxy_cache_valid 20030130230410m; proxy_ignore_headers "Cache-Control""Expires"; proxy_hide_header "Set-Cookie"; proxy_pass http://127.0.0.1/; proxy_read_timeout 600; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; if($request_method = POST){ return403; } access_log /tmp/ban_location; }
3a. Пробуем отбиться через fail2ban
Внимание! При ботнете свыше 10.000 хостов fail2ban бесполезен. Не успевают обрабатываться логи, этот шаг был ошибочен
#cat /etc/fail2ban/jail.conf
[DEFAULT] ignoreip =127.0.0.1 bantime =600 maxretry =3 backend = polling destemail = root@localhost banaction = iptables-multiport mta = sendmail protocol = tcp action_ =%(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s] action_mw = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s] %(mta)s-whois[name=%(__name__)s, dest="%(destemail)s", protocol="%(protocol)s] action_mwl = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s] %(mta)s-whois-lines[name=%(__name__)s, dest="%(destemail)s", logpath=%(logpath)s] action =%(action_)s [apache-ddos] enabled =false port =80 filter = apache-ddos logpath =/tmp/ban_location maxretry =5 bantime =1200 action = ipset[port=80,name=ddos,proto=tcp]
3. Стандартный iptables не справится с такой нагрузкой, поэтому устанавливаем ipset
4. Запускаем скрипт, который будет ловить злодеев и банить их
#!/bin/bashwhiletrue;do cat /tmp/ban_location |awk {'print $1'}|sort|uniq -c | sort -n|awk '$1>5 {print $2}'>/tmp/add # Эта строчка была написана всвязи с изменившемся типом атаки вида GET / и POST / cat /var/log/nginx/localhost.access.log | grep ""ET site.ru " | awk {'print $1'}|sort|uniq >>/tmp/add for i in`cat /tmp/add`;do ipset -A ban $i;done cat /tmp/add >>/root/bad_ips >/tmp/ban_location >/var/log/nginx/localhost.access.log sleep 3