Tmnt-coverspread

В статье будут рассмотрены практические примеры защиты сайтов от DDoS-атак с использованием opensource-решений на базе Linux: iptables + nginx. О том, как защитить сайт от хакерских атак с использованием opensource, можно почитать в статье обеспечение безопасности сайта.

Развернем два сервера: Frontend (будет выполнять роль фильтрующего сервера: nginx, iptables, naxsi\modsecurity, fail2ban etc) и Backend (защищаемое веб-приложение). В данной статье будет описаны практически примеры фильтрации вредоносного трафика средствами Frontend-сервера.

1. Оптимизируем ОС

Первым делом оптимизируем ОС на сервере Frontend под большие нагрузки. Отредактируем файл /etc/sysctl.conf:

## Перезагрузка системы в случае "Kernel panic" через 10 секунд
kernel.panic = 10

## Оптимизация ОЗУ
kernel.shmmax = ХХХ
kernel.shmall = ХХХ

## Оптимизация подсистемы вывода сообщений
kernel.msgmnb = 65536
kernel.msgmax = 65536

## Оптимизация работы со SWAP
vm.swappiness = 10
vm.dirty_ratio = 40
vm.dirty_background_ratio = 5

## Оптимизация подсистемы работы с файлами ("Too many open files fix")
fs.file-max = 2097152

## Оптимизация сетевой подсистемы
net.ipv4.ip_forward = 1
net.core.somaxconn = 65535
net.netfilter.nf_conntrack_max = 10000000
net.netfilter.nf_conntrack_tcp_loose = 0
net.netfilter.nf_conntrack_tcp_timeout_established = 1800
net.netfilter.nf_conntrack_tcp_timeout_close = 10
net.netfilter.nf_conntrack_tcp_timeout_close_wait = 10
net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 20
net.netfilter.nf_conntrack_tcp_timeout_last_ack = 20
net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 20
net.netfilter.nf_conntrack_tcp_timeout_syn_sent = 20
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 10
net.ipv4.tcp_congestion_control = hybla
net.ipv4.tcp_slow_start_after_idle = 0
net.ipv4.ip_local_port_range = 1024 65000
net.ipv4.ip_no_pmtu_disc = 1
net.ipv4.route.flush = 1
net.ipv4.route.max_size = 8048576
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.tcp_mem = 65536 131072 262144
net.ipv4.udp_mem = 65536 131072 262144
net.ipv4.tcp_rmem = 4096 87380 33554432
net.ipv4.udp_rmem_min = 16384
net.ipv4.tcp_wmem = 4096 87380 33554432
net.ipv4.udp_wmem_min = 16384
net.ipv4.tcp_max_tw_buckets = 1440000
net.ipv4.tcp_tw_recycle = 0
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_max_orphans = 400000
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_rfc1337 = 1
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_synack_retries = 1
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_max_syn_backlog = 16384
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_sack = 1
net.ipv4.tcp_fack = 1
net.ipv4.tcp_ecn = 2
net.ipv4.tcp_fin_timeout = 10
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 60
net.ipv4.tcp_keepalive_probes = 10
net.ipv4.tcp_no_metrics_save = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.all.rp_filter = 1

Значения параметров kernel.shmmax и kernel.shmall рассчитываются исходя из объема ОЗУ. Для подсчета можно воспользоваться скриптом:

#!/bin/bash
# simple shmsetup script
page_size=`getconf PAGE_SIZE`
phys_pages=`getconf _PHYS_PAGES`
shmall=`expr $phys_pages / 2`
shmmax=`expr $shmall \* $page_size`
echo kernel.shmmax = $shmmax
echo kernel.shmall = $shmall

Указанные параметры позволят оптимизировать работу системы под высокие нагрузки. Применение изменений производится командой «sysctl -p» или перезагрузкой системы.

2. Iptables

Фильтруем атаки на сетевом\транспортном уровне с использованием iptables:

## Блокирование INVALID-пакетов
iptables -A INPUT -i eth0 -m conntrack --ctstate INVALID -j DROP
## Блокирование новых пакетов, которые не имеют флага SYN
iptables -A INPUT -i eth0 -p tcp ! --syn -m conntrack --ctstate NEW -j DROP
## Блокирование нестандартных значений MSS
iptables -A INPUT -i eth0 -p tcp -m conntrack --ctstate NEW -m tcpmss ! --mss 536:65535 -j DROP
## Блокирование фрагментированных пакетов
iptables -A INPUT -i eth0 -f -j DROP
## Блокирование пакетов с неверными TCP флагами
iptables -A INPUT -i eth0 -p tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP
iptables -A INPUT -i eth0 -p tcp --tcp-flags FIN,SYN FIN,SYN -j DROP
iptables -A INPUT -i eth0 -p tcp --tcp-flags SYN,RST SYN,RST -j DROP
iptables -A INPUT -i eth0 -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
iptables -A INPUT -i eth0 -p tcp --tcp-flags FIN,RST FIN,RST -j DROP
iptables -A INPUT -i eth0 -p tcp --tcp-flags FIN,ACK FIN -j DROP
iptables -A INPUT -i eth0 -p tcp --tcp-flags ACK,URG URG -j DROP
iptables -A INPUT -i eth0 -p tcp --tcp-flags ACK,FIN FIN -j DROP
iptables -A INPUT -i eth0 -p tcp --tcp-flags ACK,PSH PSH -j DROP
iptables -A INPUT -i eth0 -p tcp --tcp-flags ALL ALL -j DROP
iptables -A INPUT -i eth0 -p tcp --tcp-flags ALL NONE -j DROP
iptables -A INPUT -i eth0 -p tcp --tcp-flags ALL FIN,PSH,URG -j DROP
iptables -A INPUT -i eth0 -p tcp --tcp-flags ALL SYN,FIN,PSH,URG -j DROP
iptables -A INPUT -i eth0 -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP
## Защита от сканирования портов
iptables -N port-scanning
iptables -A port-scanning -p tcp --tcp-flags SYN,ACK,FIN,RST RST -m limit --limit 1/s --limit-burst 2 -j RETURN
iptables -A port-scanning -j DROP

Ограничим количество соединений с веб-сервером:

iptables -A INPUT -i eth0 -o eth1 -p tcp --syn -m multiport --dports 80,443 -m connlimit --connlimit-above 30 --connlimit-mask 32 -j DROP
iptables -A INPUT -i eth0 -o eth1 -p tcp -m multiport --dports 80,443 -j ACCEPT

Правила ограничат количество устанавливаемых сессий до 30 в секунду для каждого внешнего адреса. Значение подбирается индивидуально, в зависимости от типа веб-приложения. Как правило, значения 30 для connlimit-above будет достаточно.

3. Nginx

3.1 Блокируем избыточные обращения

Настроим Nginx на Frontend-сервере таким образом, чтобы ограничить избыточные обращения к серверу. Отредактируем vhost-файл:

# nano /etc/nginx/sited-enabled/frontend

limit_req_zone$binary_remote_addrzone=defcon.ru:10m rate=10r/s;
server {
listen 80;
server_name defcon.ru;
...
}
location / {
proxy_pass ...
...
limit_req zone=defcon.ru burst=20;
limit_req_log_level error;
limit_req_status 503;
...
}

Таким образом Nginx будет проксировать обращения клиентов на Backend-сервер не чаще, чем 10 запросов в секунду (параметр rate). Избыточные обращения будут накапливаться в очереди и проксироваться по мере освобождения «пула» обращений. В случае, если количество обращений превысит значение 20 (параметр burst), nginx на Frontend начнет отдавать 503 ошибку до тех пор, пока «пул» не начнет высвобождаться.

3.2 Блокируем подозрительные юзерагенты

Заблокируем юзерагенты, которые, как правило, не используют легитимные пользователи:

# nano /etc/nginx/nginx.conf

map $http_user_agent $bad_useragent {
include /etc/nginx/bad_useragents;
}

# nano /etc/nginx/bad_useragents

~*nmap 1;
~*nikto1 1;
~*wikto 1;
~*sf 1;
~*sqlmap 1;
~*bsqlbf 1;
~*acunetix 1;
~*havij 1;
~*appscan 1;
~*wpscan 1;
~*mj12bot 1;
~*ApacheBench 1;
~*WordPress 1;
~*DirBuster 1;
~*perl 1;
~*PhpStorm 1;
~*python 1;
~*w3af 1;
~*WhatWeb 1;
~*Arachni 1;
~*XSpider 1;
~*Hydra 1;
~*Evasions 1;
~*OpenVas 1;
~*visionutils 1;
~*Synapse 1;
~*HTTP_Request2 1;
~*GuzzleHttp 1;
~*Paros 1;
~*Synapse 1;
~*Python-urllib 1;

Отдельно стоит обратить внимание на user-agent «WordPress». Если защищаемое веб-приложение не использует CMS WordPress, или же функционал «track-back» и «ping-back» не планируется использовать (скорее всего), то блокирование запросов с данным user-agent позволит перекрыть атаки, использующие особенности реализации такого функционала в WordPress. изучить особенности таких атак можно здесь.

Реализация таких простых правил позволит обеспечить качественную защиту от DDoS-атак веб-сайта с минимальными затратами.

P.S.: Убедитесь, что другие сервисы на Frontend-сервере хорошо защищены и не позволят злоумышленнику получить удаленный доступ (например, по SSH или FTP).

UPD: В качестве альтернативы можно попробовать Nemesida WAF Community — полностью бесплатный, представлен в виде динамического модуля Nginx, устанавливается и обновляется из репозитория, не требует компиляции, подключается за несколько минут к уже установленному Nginx.