|
|||||||
Защита от DDoS с iptables и ipset
Время создания: 12.03.2011 21:34
Раздел: Компьютер - Linux - Сеть в Linux
Запись: xintrea/mytetra_syncro/master/base/0000003444/text.html на raw.github.com
|
|||||||
|
|||||||
Всех приветсвую. Давно хотел написать что-то подобное, но все не хотел =). Решил полазить интернет, нашол только 1 пример рабочих конфигов, но они были направлены на защиту какого-то самописного сервера. Я раскажу, как защитить сайт, с помощью iptables. Рекомендую ознакомится со следущим небольщим справочником: Iptables FAQ Далее, немного расскажу, про основные виды защиты не только сайтов.
Я знаю, а точнее использую два способа защиты сервера от атак.
Также для начала необходимо немного настроить сам сервер, чтобы он не загибался при 5к запросов. # Enables source route verification net.ipv4.conf.all.rp_filter = 1
# Enables the magic-sysrq key kernel.sysrq = 1
# TCP Explict Congestion Notification #net.ipv4.tcp_ecn = 0
# we do not want all our interfaces to send redirects net.ipv4.conf.default.send_redirects = 1 net.ipv4.conf.all.send_redirects = 0
net.ipv4.ip_forward = 1 net.ipv4.ip_dynaddr = 1
# Controls the maximum size of a message, in bytes kernel.msgmnb = 65536
# Controls the default maxmimum size of a mesage queue kernel.msgmax = 65536
# Controls the maximum shared segment size, in bytes kernel.shmmax = 4294967295
# Controls the maximum number of shared memory segments, in pages kernel.shmall = 268435456
net.ipv4.tcp_keepalive_time = 15 net.ipv4.tcp_keepalive_intvl = 10 net.ipv4.tcp_keepalive_probes = 5
net.ipv4.tcp_fin_timeout = 30 net.ipv4.tcp_window_scaling = 0 net.ipv4.tcp_sack = 0 net.ipv4.tcp_timestamps = 0
net.ipv4.netfilter.ip_conntrack_max = 224000 net.ipv4.netfilter.ip_conntrack_tcp_timeout_close = 30 net.ipv4.netfilter.ip_conntrack_tcp_timeout_time_wait = 30 net.ipv4.netfilter.ip_conntrack_tcp_timeout_last_ack = 120 net.ipv4.netfilter.ip_conntrack_tcp_timeout_close_wait = 30 net.ipv4.netfilter.ip_conntrack_tcp_timeout_fin_wait = 60 net.ipv4.netfilter.ip_conntrack_tcp_timeout_established = 190 net.ipv4.netfilter.ip_conntrack_tcp_timeout_syn_recv = 30 net.ipv4.netfilter.ip_conntrack_tcp_timeout_syn_sent = 30 Эти значения подобраны потом и кровью и используются на сервере с 14 гигами памяти. Вам я рекомендую поуменьшать некоторые из них. iptables -I INPUT 1 -p tcp -m tcp --dport 80 --tcp-flags FIN,SYN,RST,ACK SYN -m connlimit --connlimit-above 15 --connlimit-mask 32 -j DROP Устанавливаем число одновременных запросов на IP с префиксом/32 – максимум 15, остальное в DROP. ipset -N blacklist iphash iptables -A INPUT -p tcp -m tcp --dport 80 -m set --set blacklist src -j DROP Создаем специальный сет для хранения IP. При больших потоках запросов, а также over 100 правил вида: iptables -A INPUT -s x.x.x.x -j DROP Вы будете иметь колосальную нагрузку на свой сервер, но это единственный вариант для OpenVZ виртуализации, все экзотические правила, требуют специальных модулей, просите свой саппорт чтобы они на вашу ВМ их подключили. Преимущества ipset:
Все мои коммандлайнеры предназначены для глобального access.log’а nginx’а. Если у вас другой вид записей, то тут уже правьте сами (: Давайте рассмотрим ситуацию, когда ддосят на / сайта. В принципе особой разницы нет что и как ддосят ,просто правим немного grep запрос и все (: 256.256.256.256 - - [07/Mar/2011:06:23:16 +0300] "GET / HTTP/1.1" 200 2437 "-" "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.224 Safari/534.10" "example.com" "2437" "0.019" В момент атаки на сервер сыпятся кучи таких запросов. Что нам нужно определить?
Начинаем по маленьку парситть логи. Так как tail -f нам дает большую задержку с использованием grep, awk, cut пока не заполнятся их буферы на чтение, будем использовать tail -n N (кол-во строк которые смотрим) Не забудьте в конечном варианте испроваить K на сколько вам нужно. На средних атаках, до 1к ботов я использую 15 на 10к строк логов. while true; do tail -n 1000 /var/log/nginx/access.log | grep "example\.org" | grep " GET / HTTP" ; sleep 60; done Все. Можете запустить на своем сервере, ессно сменив example.org на ваш домен, и хотя вообще можете полностью выкинуть этот греп, на этапе создания коммандлайнера он не нужен. Далее выдергиваем IP адрес клиента. while true; do tail -n 1000 /var/log/nginx/access.log | grep "example\.org" | grep " GET / HTTP" | cut -d " " -f1 ; sleep 60; done На выходе получаем: 256.256.256.256 Это всего лиш гипотетический пример, поэтому смотрите в оба (: Далее, нам нужно проверить, что все ипы у нас встречаются не более К раз, если такое случилось сразу его в магадан =) while true; do tail -n 1000 /var/log/nginx/access.log | grep "example\.org" | grep " GET / HTTP" | cut -d " " -f1 | sort | uniq -c; sleep 60; done Выход такой: 1 256.256.256.256 Первое число, кол-во повторений, второе сам IP. Далее awk выдергиваем то что нам нужно (: while true; do tail -n 1000 /var/log/nginx/access.log | grep "example\.org" | grep " GET / HTTP" | cut -d " " -f1 | sort | uniq -c | awk '{if($1>K){print $2}}'; sleep 60; done Вот и все. Мы получили IP тех, кто встретился нам более К раз. Осталось только его забанить. while true; do tail -n 1000 /var/log/nginx/access.log | grep "example\.org" | grep " GET / HTTP" | cut -d " " -f1 | sort | uniq -c | awk '{if($1>K){print $2}}' | xargs -tl -I _ ipset -A blacklist _; sleep 60; done На выходе увидете всякое разное (: . Перед началом написания коммандлайнера, нужно проверить какие запросы шлются на сервер: tail -f /var/log/nginx/access.log Если по какойто причине у вас атакующих ссылок несколько, а может быть что в конце ссылки стоит рандомное число, то вот тут нужно по другому делать grep -e "GET / HTTP" -e "GET /index.php HTTP" -e "GET /captcha.php HTTP" Есть еще один вариант, когда /index.php?123456789 куча цыферок. Вот в данном случае есть только 1 способ это все выдернуть, никакие iptables не помогут. Там нет регепсов. pcregrep --color "GET \/index\.php\?([0-9]+) HTTP" Ну а если я не разобрал ваш пример, пишите в комментарии, давайте урлы, или полностью строчки с логов, я и для них напишу паттерн. Чтобы ддосеры не спали, и занимались тренировкой мозгов. Вроде бы первый способ я озвучил. Давайте займемся вплотную Iptables: recent match doc : http://netfilter.org/documentation/HOWTO/netfilter-extensions-HOWTO-3.html Читаем брошурку и понимаем. Также можете посмотреть на nth match. Очень интерстный, но я пока не придумал как его в нашей ситуации можно использовать, если вы знаете, пишити в комментариях. Вот тут уже не получится фильтровать сразу за раз несолько урлов, и каждое правило применяется абсолютно ко всем доменам, так как действует на уровне всего сервера. iptables -A INPUT -p tcp -m tcp --dport 80 -m string --string "GET / HTTP" --algo kmp --to 1024 -m recent --set --name httpddos --rsource iptables -A INPUT -p tcp -m tcp --dport 80 -m string --string "GET / HTTP" --algo kmp --to 1024 -m recent --update --seconds 10 --hitcount 2 --name httpddos --rsource -j DROP Данные 2 правила делют следущее: Приходит пакет, если в нем есть «GET / HTTP», то обрабатывается слудущим модулем – recent. Если этого нет, то идет на следущее правило. Записали в память. Если в течении 10 секунд с этого IP еще раз придет запрос который удовлетворит GET / HTTP, то тогда этот запрос идет в DROP. Вот и весь смысл. Все просто, просто нужно чуточку почитать документацию, и погуглить, уже есть куча решений, но не всегда то что вам нужно. Есть одна проблема с модулем recent. Это количество запоминающихся IP адресов по дефолту. parm: ip_list_tot:number of IPs to remember per list (uint) parm: ip_pkt_list_tot:number of packets per IP to remember (max. 255) (uint) parm: ip_list_hash_size:size of hash table used to look up IPs (uint) parm: ip_list_perms:permissions on /proc/net/ipt_recent/* files (uint) parm: ip_list_uid:owner of /proc/net/ipt_recent/* files (uint) parm: ip_list_gid:owning group of /proc/net/ipt_recent/* files (uint) ip_list_tot = 100. для этого нам нужно сделать modprobe ipt_recent ip_list_tot=4000 При большом количестве pps при большом количестве этого параметра, ksoftirq процесс может начать жрать кучу CPU. ip_list_tot = 100
Просмотреть количество записей в данный момент можно с помощью команды: wc -l /proc/net/ipt_recent/* Одно главное замечание, все это применимо к Debian Lenny. Как все это использовать в франкенштейне CentOS пинайте, пожалуйста не меня, а гугл. |
|||||||
Так же в этом разделе:
|
|||||||
|
|||||||
|