Что имеем: есть сервер (8Гб памяти, Intel(R) Xeon(R) CPU E31220 @ 3.10GHz) FreeBSD 8.4 Release amd64, сайт на php5.2, nginx+apache+mysql.
Перейти полностью на php-fpm не получилось, поэтому пришлось защищаться как есть. Это поможет отразить небольшую syn flood атаку.
Ниже будет приведены выполненные действия для отражения атак.
1) Тюнинг sysctl.
/boot/loader.conf:
kern.ipc.nmbclusters=65535
net.inet.tcp.syncache.hashsize=1024
net.inet.tcp.syncache.bucketlimit=100
net.inet.tcp.tcbhashsize=4096
/etc/sysctl.conf:
vfs.usermount=0
security.bsd.see_other_uids=0
security.bsd.see_other_gids=0
security.bsd.hardlink_check_uid=1
security.bsd.hardlink_check_gid=1
security.bsd.conservative_signals=1
security.bsd.unprivileged_proc_debug=0
security.bsd.unprivileged_read_msgbuf=0
security.bsd.unprivileged_get_quota=0
kern.ipc.somaxconn=32768
kern.ipc.maxsockets=204800
kern.ipc.maxsockbuf=2097152
kern.maxfiles=204800
kern.maxfilesperproc=200000
kern.random.sys.harvest.ethernet=0
kern.random.sys.harvest.interrupt=0
kern.random.sys.harvest.point_to_point=0
net.link.ether.inet.max_age=1200
net.link.ether.inet.log_arp_movements=0
net.local.stream.sendspace=65536
net.local.stream.recvspace=65536
net.inet6.ip6.redirect=0
net.inet.ip.portrange.first=1024
net.inet.ip.portrange.last=65535
net.inet.ip.fw.dyn_max=8192
net.inet.ip.redirect=0
net.inet.ip.sourceroute=0
net.inet.ip.accept_sourceroute=0
net.inet.ip.ttl=128
net.inet.ip.random_id=1
net.inet.ip.intr_queue_maxlen=4096
net.inet.icmp.drop_redirect=1
net.inet.icmp.bmcastecho=0
net.inet.icmp.maskrepl=0
net.inet.icmp.icmplim=50
net.inet.icmp.log_redirect=0
net.inet.udp.recvspace=65536
net.inet.udp.maxdgram=57344
net.inet.tcp.blackhole=2
net.inet.udp.blackhole=1
net.inet.tcp.log_in_vain=0
net.inet.udp.log_in_vain=0
net.inet.tcp.sendspace=64395
net.inet.tcp.recvspace=64395
net.inet.tcp.drop_synfin=1
net.inet.tcp.syncookies=1
net.inet.tcp.rfc1323=1
net.inet.tcp.msl=15000
net.inet.tcp.icmp_may_rst=0
net.inet.tcp.sack.enable=0
net.inet.tcp.finwait2_timeout=20000
net.inet.tcp.fast_finwait2_recycle=1
net.inet.tcp.sendbuf_max=16777216
net.inet.tcp.recvbuf_max=16777216
net.inet.tcp.maxtcptw=40960
net.inet.tcp.sack.enable=0
net.inet.tcp.delayed_ack=0
net.inet.tcp.nolocaltimewait=1
2) Файервол.
Пришлось ограничить количество соединений с одного IP до 20 шт.
ipfw add check-state
...
ipfw add allow tcp from any to me 80, 443 limit src-addr 20 via ${LanOut}
ipfw add allow tcp from 10.0.0.0/8 to me 80, 443 via ${LanIn} # для локальных юзеров
ipfw deny tcp from any to me dst-port 80,443
...
3) Nginx
– GeoIP
Поскольку сайт был украиноязычным, то решено было внедрить GeoIP (nginx пришлось пересобрать с поддержкой этого модуля) и ограничить для UA, RU, US (для гуглоботов и прочих ботов bingo, yahoo,…).
Скачиваем свежие базы GeoIP и распаковываем:
#mkdir /usr/local/etc/nginx/geoip && cd /usr/local/etc/nginx/geoip
#fetch http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz && gunzip GeoIP.dat.gz
#fetch http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz && gunzip GeoLiteCity.dat.gz
Далее в /usr/local/etc/nginx/nginx.conf добавляем такой код в раздел http:
map $geoip_country_code $good_country {
default no;
UA yes;
RU yes;
US yes;
}
– nginx map
Что бы разрешить доступ юзерам из локалки нужно создать map для нужных IP’ок. Для этого добавляем такой код в /usr/local/etc/nginx/nginx.conf в раздел http:
geo $net_geo {
default 0;
10.0.0.0/8 yes;
127.0.0.0/8 yes;
}
– применение для сайта
Что бы применить настройки GeoIP + map для нашего сайта, добавляем такой код в раздел server:
set $GOOD 0;
map $good_country:$net_geo $GOOD {
"yes":"yes" '1';
default '0';
}
if ($GOOD = 0) {
return 444;
}
Или устаревший вариант:
set $GOOD 0;
if ($good_country = yes) {
set $GOOD 1;
}
if ($net_geo = yes) {
set $GOOD 1;
}
if ($GOOD = 0) {
return 444;
}
– прочие настройки для nginx
В секции server добавляем
worker_rlimit_nofile 200000;
events {
worker_connections 10240;
use kqueue;
}
В секции http добавляем
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
reset_timedout_connection on;
client_body_timeout 10;
client_header_timeout 10;
send_timeout 10;
4) Прочие.
Можно написать скрипт, который будет парсить netstat на предмет syn соединений с window size 0 и банить IP.
Так же полезно отключить access-логи в apache/nginx, если они не используются для какой-то статистики. Дополнительно можно установить кешер (APC, eAccelerator, …) и смонтировать папку с кешем как tmpfs. Для mysql tmp-папку тоже смонтировать в tmpfs.
Нашёл недавно ПО ( http://synflood-defender.net/docs ) типа для защиты от атак, но не сильно верю, что оно поможет ))
Можно попробовать поставить Varnish для кеширования страниц, особенно, если боты запрашивают одну и ту же.
5) Дополнительная блокировка через файервол
pf:
### block probes that can possibly determine our operating system by disallowing ### certain combinations that are commonly used by nmap, queso and xprobe2, who ### are attempting to fingerprint the server. ### * F : FIN - Finish; end of session ### * S : SYN - Synchronize; indicates request to start session ### * R : RST - Reset; drop a connection ### * P : PUSH - Push; packet is sent immediately ### * A : ACK - Acknowledgement ### * U : URG - Urgent ### * E : ECE - Explicit Congestion Notification Echo ### * W : CWR - Congestion Window Reduced block drop in quick on $ext_if proto tcp flags FUP/WEUAPRSF block drop in quick on $ext_if proto tcp flags WEUAPRSF/WEUAPRSF block drop in quick on $ext_if proto tcp flags SRAFU/WEUAPRSF block drop in quick on $ext_if proto tcp flags /WEUAPRSF block drop in quick on $ext_if proto tcp flags SR/SR block drop in quick on $ext_if proto tcp flags SF/SF
ipfw:
ipfw add deny tcp from any to any in via $ext_if tcpflags fin, syn, rst, psh, ack, urg ipfw add deny tcp from any to any in via $ext_if tcpflags !fin, !syn, !rst, !psh, !ack, !urg ipfw add deny tcp from any to any in via $ext_if not established tcpflags fin ipfw add deny tcp from any to any not verrevpath in via $ext_if
Дополнение: неплохой пример блокировки через файервол pf на основе country code https://it-notes.dragas.net/2024/06/16/freebsd-blocking-country-access/
2 коментарі “Защита от небольшого DDoS’a”
Не Ваниш надо ставить, а использовать fast_cgi cache.
Да, можно и его.