Методы борьбы с DDoS-атаками (HTTP)
Проявление атаки
Проявляется в огромном количестве процессов apache, сервер недоступен из-за превышения максимального числа процессов, или, что наиболее вероятно, недоступен из-за нехватки оперативной памяти.
Диагностика
Если есть возможность зайдите на сервер по ssh. Командами ps и top отметьте большое количество процессов httpd. Если на сервер по ssh войти не удается, то воспользуйтесь VDSmanager (ссылка на него есть в клиентской зоне)
Посмотрите меню Запущенные процессы и Текущая нагрузка. Перезагрузите сервер через VDSmanager, попробуйте зайти по ssh, если падает, из-за apache, то остановите его, как вариант, можете убить все процессы httpd через него же.)
netstat -na | grep ':80 '
netstat -na
Эти команды покажут вывод, направление и состояние всех установленных на 80 порту или на всех портах соединений.
ps aux | grep httpd | wc -l
netstat -na | grep ":80 " | wc -l
Эти команды считают количество процессов httpd и количество подключений на 80 порт. Если количество соединение превышает среднестатистическое, вероятно, это DoS/DDoS-атака. Также http-флуд можно выявить по косвенным признакам:
watch 'ls -laS /home/httpd-logs/' (для FreeBSD)
watch 'ls -laS /var/www/httpd-logs/' (для Linux)
Эти команды каждые 2 секунды будут выводить список логов apache, если размер верхнего access файла быстро растет, почти наверняка атака идет на этот сайт. Примечание: во FreeBSD пакет watch выполняет другие функции. Следует использовать пакет cmdwatch.
tcpdump -n port 80 -c 200 -w ddos.log
данная команда также поможет в выявлении DoS/DDoS. Tcpdump запишет в файл ddos.log первые 200 пакетов, которые соединений на 80 порту.
tcpdump -nr ddos.log | awk '{print $3}' |grep -oE '[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}' |sort |uniq -c |sort -rn
а так лог-файл можно прочитать и отсортировать по ip и количеству подключений.
Действия администратора
Для FreeBSD включите firewall - отредактируйте /etc/rc.conf прописав в нем строки (редактировать файлы можно через VDSmanager)
firewall_enable="YES"
firewall_type="/etc/firewall.conf"
Создайте файл /etc/firewall.conf и пропишите в нем
add allow ip from ip-адрес с_которого_администрируете_сервер
add deny tcp from any to me 80
Тем самым после перезагрузки сервера у вас будет недоступен apache извне и не будет приводить к зависанию сервера.
Подключение mod_status в Apache 2.2
Теперь надо определить на какой именно сайт идет атака. У apache есть замечательный модуль mod_status http://httpd.apache.org/docs/2.2/mod/mod_status.html
mod_status позволяет в реальном времени осуществлять мониторинг загрузки сервера.
В apache2.2 отредактируйте /usr/local/etc/apache22/httpd.conf
Раскомментируйте строки
#LoadModule status_module libexec/apache22/mod_status.so
#Include etc/apache22/extra/httpd-info.conf
Отредактируйте файл конфигурации /usr/local/etc/apache22/extra/httpd-info.conf
<Location /server-status>
SetHandler server-status
Order deny,allow
Deny from all
Allow from .example.com
</Location>
Поменяйте на
<Location /server-status>
SetHandler server-status
</Location>
Раскомментируйте строку
#ExtendedStatus On
Перезапустите apache
Подключение mod_status в apache 1.3
В apache 1.3 подключение server_status осуществляется аналогично apache 2.2, за исключением того, что все настраивается только в /usr/local/etc/apache/httpd.conf
Использование server-status
Теперь по адресу
http://ip-aдрес.сервера/server-status доступна статистика запросов к нему.
Аккуратно удалите правило запрещащие запросы к серверу по 80 порту
# ipfw delete 200
И посмотрите http://ip-aдрес.сервера/server-status
Нас интересует следующее
0-0 86795 0/31/31 W 0.54 0 0 0.0 0.09 0.09 89.18.166.89 example.com GET / HTTP/1.0
1-0 86796 0/19/19 W 0.30 0 0 0.0 0.06 0.06 79.140.78.68 example.com GET / HTTP/1.0
2-0 86801 0/9/9 W 0.15 0 0 0.0 0.03 0.03 89.18.166.89 example.com GET / HTTP/1.0
3-0 86802 0/9/9 W 0.14 0 0 0.0 0.03 0.03 82.12.33.48 myhost.com GET /server-status/ HTTP/1.1
4-0 86805 0/4/4 W 0.07 1 0 0.0 0.01 0.01 79.140.78.68 example.com GET / HTTP/1.0
5-0 86806 0/3/3 W 0.06 2 0 0.0 0.01 0.01 89.18.166.89 example.com GET / HTTP/1.0
6-0 86807 0/4/4 W 0.07 0 0 0.0 0.01 0.01 89.18.166.89 example.com GET / HTTP/1.0
7-0 86808 1/4/4 C 0.08 0 2015 3.0 0.01 0.01 89.18.166.89 example.com GET / HTTP/1.0
8-0 86811 0/1/1 W 0.02 0 0 0.0 0.00 0.00 89.18.166.89 example.com GET / HTTP/1.0
9-0 86812 0/1/1 W 0.02 0 0 0.0 0.00 0.00 89.18.166.89 example.com GET / HTTP/1.0
10-0 86813 0/1/1 W 0.02 0 0 0.0 0.00 0.00 89.18.166.89 example.com GET / HTTP/1.0
В данном случае, атака идет пустыми запросами GET / к серверу example.com
Вам следует его отключить. Выполнить это лучше всего создав файл .htaccess в корневой директории домена с содержимым
Deny from All
Теперь при обращении к сайту будет выдаваться ошибка 403 Forbidden и нагрузка на остальные сайты значительно снизится.
Как правило, флуд-боты обращаются по имени сервера, соответственно, пропишите DNS для этого домена на IP-адрес 127.0.0.1 и когда обновится кэш DNS, то поток пустых запросов полностью прекратится.
Фильтрация
iptables -A INPUT -p tcp --src xxx.xxx.xxx.xxx --dport 80 -j DROP
так можно зафильтровать 80 порт для ip xxx.xxx.xxx.xxx
ipfw add deny tcp from xxx.xxx.xxx.xxx to me dst-port 80
то же для FreeBSD.
Команды ниже, создает таблицу для ipfw, которой запрещен доступ к серверу по 80 порту и раз в 30 секунд анализирует лог доступа к сайту на наличие ip, появившихся в логе более 50 раз.
ipfw 10 add deny ip from "table(1)" to me dst-port 80
while true; do tail -10000 /home/httpd-logs/site.ru.access.log | sort | cut -f 1 -d " " | uniq -c | awk '($1>50){print $2}' | xargs -n 1 ipfw table 1 add; sleep 30; done
или занесите в cron такое задание:
netstat -an | grep -E '\.80 ' | awk '{print $5}' | grep -Eo '[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}' | sort | uniq -c | sort -n | tail | awk '($1>50){print $2}' | xargs -I _ ipfw table 1 add _
Команды выше будут записывать в таблицу 1 ip с количеством подключений больше 50
ipfw flush — очистить правила
ipfw table 1 flush — очистить правила в таблице 1
Для Linux. Создается цепочка dos, куда перенаправляются все подключения на 80 порт сервера. В эту цепочку добавляются «плохие» ip.
iptables -N dos
iptables -A INPUT -p tcp --dport 80 -j dos
while true; do tail -10000 /var/www/httpd-logs/site.ru.access.log | sort | cut -f 1 -d " " | uniq -c | awk '($1>50){print $2}' | xargs -tn 1 iptables -A dos -p tcp -j DROP --dport 80 -s; sleep 30; done
iptables -F INPUT — очищаем таблицу INPUT.
iptables -F dos — очищаем таблицу dos
iptables -X dos — удаляем таблицу dos
Способ для iptables, имеет одну нехорошую особенность, в цепочке возникают дублирующиеся правила. Поэтому лучше использовать ipset (нужен соответствующий модуль).
ipset -N ddos iphash
iptables -A INPUT -p tcp -m tcp --dport 80 -m set --set ddos src -j DROP
while true; do tail -10000 /var/www/httpd-logs/site.ru.access.log | sort | cut -f 1 -d " " | uniq -c | awk '($1>50){print $2}' | xargs -tl -I _ ipset -A ddos _;sleep 30; done
Закрываем icmp (поможет при icmp-flood)
iptables -A INPUT -p icmp -j DROP --icmp-type 8
для FreeBSD.
ipfw add deny log icmp from any to any
Ограничение максимального числа «полуоткрытых» соединений с одного IP к конкретному порту (необходим соответствующий модуль):
iptables -I INPUT -p tcp --syn --dport 80 -m iplimit --iplimit-above 10 -j DROP
Так во FreeBSD вы ограничите максимальное число одновременных подключений (не стоит его делать меньше) с одного IP-адреса.
ipfw add allow tcp from any to me dst-port 80 limit src-addr 4
Дополнительная оптимизация сервера
В качестве дополнительных параметров, которые следует использовать, при настройке сервера
/usr/local/etc/apache22/extra/httpd-mpm.conf
<IfModule mpm_prefork_module>
StartServers 1
MinSpareServers 1
MaxSpareServers 1
MaxClients 150
MaxRequestsPerChild 100
</IfModule>
Измените MaxClients (максимальное число процессов) в меньшую сторону до количества процессов, которые не роняют ваш сервер по нехватке оперативной памяти. Каждый процесс apache занимает в среднем 4-8 мегабайт памяти. А лучше узнать точно сколько в среднем на вашем сервере занимает памяти один процесс apache/httpd так:
top -d 1 | grep -E 'http|apache' | awk '{a+=$7}END{print a/(1024*NR) " Mb"}'
Необходимо чтобы суммарное количество помещалось в оперативной памяти.
Отредактируйте /usr/local/etc/apache22/extra/httpd-default.conf Следует уменьшить параметры
Timeout 300
MaxKeepAliveRequests 100
До 60 и 50 соответственно, чтобы как можно более скорее старые процессы apache прекращали свое существование
Использование nginx
При использовании nginx в качестве Front-End к Apache (стандартная конфигурация при установки nginx совместно с ISPmanager) WWW домен следует отключать в конфигурации nginx в описании соответствующего виртуалхоста Например
server {
listen 80;
server_name example.com www.example.com;
Пропишите ниже server_name строку
deny all;
И тем самым уже nginx будет выдавать ответ 403 Forbidden и не перенаправлять запросы к web-серверу apache.
Переменные sysctl
Системные переменные, которые могут быть полезны, при DDoS.
ICMP-FLOOD
Команда ниже поможет при отражении атаки типа icmp-flood.
sysctl net.ipv4.icmp_echo_ignore_all=1
Ограничиваем число ответов на ICMP-сообщения 50-ю в секунду (защита от ICMP-флуда) для FreeBSD:
sysctl net.inet.icmp.icmplim=50
SYN-FLOOD
Увеличиваем максимальное количество подключений к серверу для FreeBSD:
sysctl kern.ipc.somaxconn=32768
Уменьшение времени удержания «полуоткрытых» соединений:
sysctl -w net.ipv4.tcp_synack_retries=1
Включение TCP syncookies:
sysctl -w net.ipv4.tcp_syncookies=1 sysctl net.inet.tcp.syncookies=1 (для FreeBSD)
Увеличиваем размер очереди полуоткрытых соединений. По-умолчанию - 512.
sysctl -w net.ipv4.tcp_max_syn_backlog=4096
Проверять TCP-соединение каждую минуту. Если на другой стороне - легальная машина, она сразу ответит. По-умолчанию - 2 часа.
sysctl -w net.ipv4.tcp_keepalive_time=60
Повторить проверку через 20 секунд
sysctl -w net.ipv4.tcp_keepalive_intvl=20
Количество проверок перед закрытием соединения
sysctl -w net.ipv4.tcp_keepalive_probes=3
Изменяем время ожидания приема FIN
sysctl -w net.ipv4.tcp_fin_timeout=10