Интеграция Fail2ban с CSF для противодействия DDoS на nginx

110a4b607a44460a997c3fe5ee971cbd.jpgНабор скриптов ConfigServer Security & Firewall (CSF) изначально обладает достаточно богатыми возможностями по организации защиты сервера хостинга Web с помощью фильтра пакетов iptables. В частности с его помощью можно противостоять затоплению атакуемого хоста пакетами TCP SYN, UDP и ICMP слабой и средней силы. Дополняет CSF встроенный Login Failure Daemon (lfd), который осуществляет мониторинг журналов на предмет наличия многочисленных неудачных попыток авторизации в различных сетевых сервисах с целью подбора пароля. Такие попытки блокируются путем внесения адреса IP злоумышленника в черный список CSF.Существует другой сторонний инструмент, реализующий аналогичный функционал: Fail2ban. Несмотря на схожесть решаемых задач, между lfd и Fail2ban присутствует кардинальное отличие. Первый имеет закрытую архитектуру и поддерживает ограниченный набор сервисов. В то время как второй позволяет самостоятельно разработать фильтры практически под любые задачи. Однако сожительствуют CSF и Fail2ban в пределах одного сервера плохо, поскольку обращаются с правилами iptables несколько бесцеремонно. Постараемся решить эту проблему на примере ОС Linux Debian v7.XX amd64 так, что бы извлечь максимум из возможностей обоих инструментов. А в качестве примера организуем защиту от атак DDoS на nginx.В моей конфигурации CSF был изначально установлен и настроен на сервере. Останавливаться на этом вопросе я не буду, материала по нему достаточно и ничего нового мне сказать нечего. Поэтому начнем сразу с установки Fail2ban, по окончании которой его необходимо остановить и отключить автозапуск:

service fail2ban stop update-rc.d -f fail2ban remove Запускать Fail2ban мы будем средствами CSF. Для этого необходимо создать скрипт »/etc/csf/csfpost.sh»:

#!/bin/sh /etc/init.d/fail2ban reload Он же обеспечит автоматическую загрузку правил Fail2ban в iptables, если CSF будет перезагружать свои, например, в случае обновления.Идея интеграции Fail2ban с CSF строится на том, что для блокировки адресов IP злоумышленников первый будет использовать черный список второго, а не напрямую правила iptables. Однако полностью от iptables в Fail2ban мы не отказываемся.Отключаем все фильтры в Fail2ban. Большую их часть перекрывает lfd. Fail2ban будем использовать только для того, что не поддерживает lfd.

sed -i «s|enabled = true|enabled = false|g» /etc/fail2ban/jail.conf Добавляем поддержку CSF в Fail2ban. Для этого создадим файл настроек »/etc/fail2ban/action.d/csf-ip-deny.conf» следующего содержания:

[Definition] actionstart = actionstop = actioncheck = actionban = csf -d Added by Fail2Ban for actionunban = csf -dr Заменим для всех фильтров Fail2ban действие блокировки на созданный «csf-ip-deny»:

sed -i -e «s|banaction = |banaction = csf-ip-deny\n#banaction = |» /etc/fail2ban/jail.conf Для особо назойливых злоумышленников предусмотрена длительная блокировка. Реализуется этот механизм путем контроля журнала самого Fail2ban. Создаем файл настроек »/etc/fail2ban/filter.d/fail2ban.conf»:

[Definition] # Count all bans in the logfile failregex = fail2ban.actions: WARNING \[(.*)\] Ban # Ignore our own bans, to keep our counts exact. # In your config, name your jail 'fail2ban', or change this line! ignoreregex = fail2ban.actions: WARNING \[fail2ban\] Ban Добавляем в »/etc/fail2ban/jail.conf» следующие строки:

## fail2ban with CSF to block repeat offenders [fail2ban] enabled = true filter = fail2ban action = iptables-allports # sendmail-whois[name=fail2ban] logpath = /var/log/fail2ban.log maxretry = 10 # Find-time: 1 day findtime = 86400 # Ban-time: 1 week bantime = 604800 Т.е. те из злоумышленников, кто в течение суток блокировался другими фильтрами 10 и более раз, будет заблокирован этим фильтром на неделю. Обратите внимание, что тут используется действие «iptables-allports», а не «csf-ip-deny». Это не ошибка. Так нужно, что бы длительная блокировка не оказалась случайно снятой другими фильтрами.

Теперь на примере организации защиты nginx от атак DDoS рассмотрим создание правил фильтрации Fail2ban. Начнем с настройки nginx, в нем необходимо задействовать возможности модулей ngx_http_limit_conn_module и ngx_http_limit_req_module. Для этого добавляем следующие строки в настройки:

limit_conn_zone $binary_remote_addr zone=perip:10m; limit_conn perip 100; limit_conn_zone $server_name zone=perserver:10m; limit_conn perserver 200; limit_req_zone $binary_remote_addr zone=reqip:10m rate=10r/s; limit_req zone=reqip burst=30; Таким образом, мы установили лимиты на не более чем 100 подключений с одного адреса IP единовременно со скоростью 10–30 новых подключений в секунду и не более 200 — к одному сайту всего с любого количества адресов IP. Превышения будет фиксироваться в журнале ошибок, для которого мы настроим фильтры Fail2ban.Создаем следующие файлы настроек.»/etc/fail2ban/filter.d/nginx-conn-limit.conf»

# Fail2Ban configuration file #

[Definition] # Option: failregex # Notes.: Regexp to catch a generic call from an IP address. # Values: TEXT # failregex = limiting connections by zone.*client:

# Option: ignoreregex # Notes.: regex to ignore. If this regex matches, the line is ignored. # Values: TEXT # ignoreregex = »/etc/fail2ban/filter.d/nginx-req-limit.conf»

# Fail2Ban configuration file # [Definition] # Option: failregex # Notes.: Regexp to catch a generic call from an IP address. # Values: TEXT # failregex = limiting requests.*client: # Option: ignoreregex # Notes.: regex to ignore. If this regex matches, the line is ignored. # Values: TEXT # ignoreregex = »/etc/fail2ban/filter.d/nginx-dos.conf»

# Fail2Ban configuration file #

[Definition] # Option: failregex # Notes.: Regexp to catch a generic call from an IP address. # Values: TEXT # failregex = ^ -.*»(GET|POST).*HTTP.*»$

# Option: ignoreregex # Notes.: regex to ignore. If this regex matches, the line is ignored. # Values: TEXT # ignoreregex = Добавляем в »/etc/fail2ban/jail.conf»:

[nginx-conn-limit] enabled = true filter = nginx-conn-limit action = csf-ip-deny[name=nginx-conn-limit] logpath = /var/log/nginx/error.log maxretry = 4 findtime = 21600 bantime = 3600 [nginx-req-limit] enabled = true filter = nginx-req-limit action = csf-ip-deny[name=nginx-req-limit] logpath = /var/log/nginx/error.log maxretry = 4 findtime = 21600 bantime = 3600

[nginx-dos] # Based on apache-badbots but a simple IP check (any IP requesting more than # 240 pages in 60 seconds, or 4p/s average, is suspicious) enabled = true filter = nginx-dos action = csf-ip-deny[name=nginx-dos] logpath = /var/log/nginx/access.log maxretry = 240 findtime = 60 bantime = 3600 Фильтры «nginx-conn-limit» и «nginx-req-limit» будут блокировать тех, кто превышает лимиты на подключения к nginx, а «nginx-dos» — тех, кто слишком часто обращается к сайтам: более 240 страниц в минуту.

Часто целью атак является широкой распространенная CMS WordPress: перебор паролей и большое количество запросов XML-RPC. Организуем защиту от них тоже.»/etc/fail2ban/filter.d/nginx-wp-login.conf»

[Definition] failregex = .*POST /wp-login.php ignoreregex = »/etc/fail2ban/filter.d/nginx-wp-xmlrpc.conf» [Definition] failregex = .*POST /xmlrpc.php ignoreregex = »/etc/fail2ban/filter.d/nginx-wp-register.conf» [Definition] failregex = ^ .* «GET /wp-login.php\? action=register HTTP/.*» .*$ ignoreregex = Добавляем в »/etc/fail2ban/jail.conf»: [nginx-wp-login] enabled = true filter = nginx-wp-login action = csf-ip-deny[name=nginx-wp-login] logpath = /var/log/nginx/access.log maxretry = 4 findtime = 600 bantime = 3600 [nginx-wp-xmlrpc] enabled = true filter = nginx-wp-xmlrpc action = csf-ip-deny[name=nginx-wp-xmlrpc] logpath = /var/log/nginx/access.log maxretry = 4 findtime = 600 bantime = 3600

[nginx-wp-register] enabled = true filter = nginx-wp-register action = csf-ip-deny[name=nginx-wp-register] logpath = /var/log/nginx/access.log maxretry = 4 findtime = 600 bantime = 3600 Вот, что можно будет наблюдать в журнале Fail2ban во время атаки DDoS на nginx:

spoiler 2015–01–04 13:44:10,660 fail2ban.actions: WARNING [nginx-req-limit] Ban 188.191.47.46 2015–01–04 13:44:11,668 fail2ban.actions: WARNING [nginx-conn-limit] Ban 109.187.63.199 2015–01–04 13:44:21,061 fail2ban.actions: WARNING [nginx-req-limit] 188.191.47.46 already banned 2015–01–04 13:44:29,382 fail2ban.actions: WARNING [nginx-conn-limit] Ban 178.123.155.115 2015–01–04 13:44:36,584 fail2ban.actions: WARNING [nginx-conn-limit] Ban 109.62.153.190 2015–01–04 13:44:38,246 fail2ban.actions: WARNING [nginx-dos] Ban 5.143.158.88 2015–01–04 13:44:38,826 fail2ban.actions: WARNING [nginx-req-limit] Ban 178.158.206.140 2015–01–04 13:44:41,739 fail2ban.actions: WARNING [nginx-conn-limit] Ban 5.44.168.38 2015–01–04 13:44:49,877 fail2ban.actions: WARNING [nginx-dos] Ban 91.214.131.71 2015–01–04 13:44:52,333 fail2ban.actions: WARNING [nginx-conn-limit] Ban 176.125.48.22 2015–01–04 13:44:53,395 fail2ban.actions: WARNING [nginx-req-limit] Ban 91.207.211.222 2015–01–04 13:44:53,773 fail2ban.actions: WARNING [nginx-dos] Ban 178.158.206.140 2015–01–04 13:44:54,849 fail2ban.actions: WARNING [nginx-conn-limit] Ban 5.143.158.88 2015–01–04 13:44:57,395 fail2ban.actions: WARNING [nginx-req-limit] 91.207.211.222 already banned 2015–01–04 13:44:57,765 fail2ban.actions: WARNING [nginx-dos] Ban 37.232.87.169 2015–01–04 13:44:58,073 fail2ban.actions: WARNING [nginx-conn-limit] Ban 77.34.22.95 2015–01–04 13:44:58,506 fail2ban.actions: WARNING [nginx-req-limit] Ban 93.80.45.244 2015–01–04 13:45:02,733 fail2ban.actions: WARNING [nginx-dos] Ban 176.120.38.238 2015–01–04 13:45:05,615 fail2ban.actions: WARNING [nginx-conn-limit] Ban 178.173.4.162 А вот так будут блокироваться чрезмерно назойливые злоумышленники:

spoiler 2015–01–04 11:43:29,618 fail2ban.actions: WARNING [nginx-wp-login] Ban 95.163.121.129 2015–01–04 12:43:30,160 fail2ban.actions: WARNING [nginx-wp-login] Unban 95.163.121.129 2015–01–04 12:56:53,543 fail2ban.actions: WARNING [nginx-wp-login] Ban 95.163.121.129 2015–01–04 13:56:54,279 fail2ban.actions: WARNING [nginx-wp-login] Unban 95.163.121.129 2015–01–04 14:02:40,932 fail2ban.actions: WARNING [nginx-wp-login] Ban 95.163.121.129 2015–01–04 15:02:41,040 fail2ban.actions: WARNING [nginx-wp-login] Unban 95.163.121.129 2015–01–04 15:12:16,906 fail2ban.actions: WARNING [nginx-wp-login] Ban 95.163.121.129 2015–01–04 16:12:16,937 fail2ban.actions: WARNING [nginx-wp-login] Unban 95.163.121.129 2015–01–04 16:55:33,362 fail2ban.actions: WARNING [nginx-wp-login] Ban 95.163.121.129 2015–01–04 17:55:34,142 fail2ban.actions: WARNING [nginx-wp-login] Unban 95.163.121.129 2015–01–04 18:23:37,665 fail2ban.actions: WARNING [nginx-wp-login] Ban 95.163.121.129 2015–01–04 19:23:38,136 fail2ban.actions: WARNING [nginx-wp-login] Unban 95.163.121.129 2015–01–04 19:45:46,850 fail2ban.actions: WARNING [nginx-wp-login] Ban 95.163.121.129 2015–01–04 20:03:17,247 fail2ban.actions: WARNING [nginx-wp-login] Ban 92.255.28.42 2015–01–04 20:45:47,085 fail2ban.actions: WARNING [nginx-wp-login] Unban 95.163.121.129 2015–01–04 21:03:17,297 fail2ban.actions: WARNING [nginx-wp-login] Unban 92.255.28.42 2015–01–04 21:09:51,996 fail2ban.actions: WARNING [nginx-wp-login] Ban 92.255.28.42 2015–01–04 21:16:22,336 fail2ban.actions: WARNING [nginx-wp-login] Ban 95.163.121.129 2015–01–04 22:09:52,036 fail2ban.actions: WARNING [nginx-wp-login] Unban 92.255.28.42 2015–01–04 22:13:27,799 fail2ban.actions: WARNING [nginx-wp-login] Ban 92.255.28.42 2015–01–04 22:16:23,295 fail2ban.actions: WARNING [nginx-wp-login] Unban 95.163.121.129 2015–01–04 22:24:56,755 fail2ban.actions: WARNING [nginx-wp-login] Ban 95.163.121.129 2015–01–04 23:13:28,058 fail2ban.actions: WARNING [nginx-wp-login] Unban 92.255.28.42 2015–01–04 23:16:50,235 fail2ban.actions: WARNING [nginx-wp-login] Ban 92.255.28.42 2015–01–04 23:24:56,843 fail2ban.actions: WARNING [nginx-wp-login] Unban 95.163.121.129 2015–01–05 00:00:42,183 fail2ban.actions: WARNING [nginx-wp-login] Ban 95.163.121.129 2015–01–05 00:00:43,851 fail2ban.actions: WARNING [fail2ban] Ban 95.163.121.129 2015–01–05 00:16:50,263 fail2ban.actions: WARNING [nginx-wp-login] Unban 92.255.28.42 2015–01–05 00:23:22,863 fail2ban.actions: WARNING [nginx-wp-login] Ban 92.255.28.42 2015–01–05 01:00:42,637 fail2ban.actions: WARNING [nginx-wp-login] Unban 95.163.121.129 2015–01–05 01:23:23,750 fail2ban.actions: WARNING [nginx-wp-login] Unban 92.255.28.42 2015–01–05 01:26:16,543 fail2ban.actions: WARNING [nginx-wp-login] Ban 92.255.28.42 2015–01–05 02:26:16,681 fail2ban.actions: WARNING [nginx-wp-login] Unban 92.255.28.42 2015–01–05 02:32:28,850 fail2ban.actions: WARNING [nginx-wp-login] Ban 92.255.28.42 2015–01–05 03:32:29,350 fail2ban.actions: WARNING [nginx-wp-login] Unban 92.255.28.42 2015–01–05 03:39:18,048 fail2ban.actions: WARNING [nginx-wp-login] Ban 92.255.28.42 2015–01–05 04:39:18,609 fail2ban.actions: WARNING [nginx-wp-login] Unban 92.255.28.42 2015–01–05 04:43:38,428 fail2ban.actions: WARNING [nginx-wp-login] Ban 92.255.28.42 2015–01–05 05:43:39,091 fail2ban.actions: WARNING [nginx-wp-login] Unban 92.255.28.42 2015–01–05 05:47:47,722 fail2ban.actions: WARNING [nginx-wp-login] Ban 92.255.28.42 2015–01–05 05:47:50,212 fail2ban.actions: WARNING [fail2ban] Ban 92.255.28.42 2015–01–05 06:47:48,343 fail2ban.actions: WARNING [nginx-wp-login] Unban 92.255.28.42 В последнее время участились случаи, когда злоумышленники осуществляют распределенный перебор паролей с разных адресов IP одной подсети класса C. Алгоритм работы Fail2ban не способен распознать такое поведение:

spoiler 2015–01–05 14:01:14,432 fail2ban.actions: WARNING [nginx-wp-login] Ban 193.176.147.176 2015–01–05 14:01:14,656 fail2ban.actions: WARNING [nginx-wp-login] Unban 193.176.147.249 2015–01–05 14:01:35,906 fail2ban.actions: WARNING [nginx-wp-login] Ban 193.176.147.198 2015–01–05 14:02:39,536 fail2ban.actions: WARNING [nginx-wp-login] Unban 193.176.147.154 2015–01–05 14:02:53,766 fail2ban.actions: WARNING [nginx-wp-login] Ban 193.176.147.132 2015–01–05 14:02:53,980 fail2ban.actions: WARNING [nginx-wp-login] Unban 193.176.147.202 2015–01–05 14:04:00,782 fail2ban.actions: WARNING [nginx-wp-login] Ban 193.176.147.136 2015–01–05 14:04:05,007 fail2ban.actions: WARNING [nginx-wp-login] Unban 193.176.147.104 2015–01–05 14:04:07,234 fail2ban.actions: WARNING [nginx-wp-login] Ban 193.176.147.167 2015–01–05 14:04:25,473 fail2ban.actions: WARNING [nginx-wp-login] Ban 193.176.147.143 2015–01–05 14:05:26,993 fail2ban.actions: WARNING [nginx-wp-login] Unban 193.176.147.253 2015–01–05 14:06:25,719 fail2ban.actions: WARNING [nginx-wp-login] Unban 193.176.147.230 2015–01–05 14:06:27,945 fail2ban.actions: WARNING [nginx-wp-login] Ban 193.176.147.162 2015–01–05 14:07:23,484 fail2ban.actions: WARNING [nginx-wp-login] Ban 193.176.147.153 2015–01–05 14:07:56,962 fail2ban.actions: WARNING [nginx-wp-login] Ban 193.176.147.140 2015–01–05 14:08:11,207 fail2ban.actions: WARNING [nginx-wp-login] Unban 193.176.147.142 2015–01–05 14:09:37,759 fail2ban.actions: WARNING [nginx-wp-login] Unban 193.176.147.137 2015–01–05 14:10:59,757 fail2ban.actions: WARNING [nginx-wp-login] Unban 193.176.147.175 2015–01–05 14:11:04,030 fail2ban.actions: WARNING [nginx-wp-login] Unban 193.176.147.117 2015–01–05 14:11:23,273 fail2ban.actions: WARNING [nginx-wp-login] Ban 193.176.147.218 2015–01–05 14:11:41,517 fail2ban.actions: WARNING [nginx-wp-login] Unban 193.176.147.139 2015–01–05 14:13:22,590 fail2ban.actions: WARNING [nginx-wp-login] Ban 193.176.147.204 2015–01–05 14:13:24,808 fail2ban.actions: WARNING [nginx-wp-login] Ban 193.176.147.220 2015–01–05 14:14:36,124 fail2ban.actions: WARNING [nginx-wp-login] Ban 193.176.147.190 2015–01–05 14:14:38,356 fail2ban.actions: WARNING [nginx-wp-login] Ban 193.176.147.179 2015–01–05 14:14:38,577 fail2ban.actions: WARNING [nginx-wp-login] Ban 193.176.147.137 2015–01–05 14:14:49,805 fail2ban.actions: WARNING [nginx-wp-login] Unban 193.176.147.188 2015–01–05 14:15:48,398 fail2ban.actions: WARNING [nginx-wp-login] Unban 193.176.147.131 Устраним этот недостаток с помощью следующего скрипта, который будет выполняться каждый час планировщиком cron.»/etc/cron.hourly/fail2ban-subnets»

#!/bin/bash

log=»/var/log/fail2ban.log» limit=30 grep=`which grep`

${grep} «fail2ban.actions.*Ban» ${log} | ${grep} -E -o »(25[0–5]|2[0–4][0–9]|[01]?[0–9][0–9]?)\.(25[0–5]|2[0–4][0–9]|[01]?[0–9][0–9]?)\.(25[0–5]|2[0–4][0–9]|[01]?[0–9][0–9]?)\.(25[0–5]|2[0–4][0–9]|[01]?[0–9][0–9]?)» | awk -F'.' '{print $1».»$2».»$3}' | sort -u | while read line do count=$(${grep} -c «fail2ban.actions.*Ban.*${line}» ${log}) if [ ${count} -ge ${limit} ] then /usr/sbin/csf -td ${line}.0/24 7d «Subnet ${line}.0/24 is blocked for a week by Fail2ban after ${count} attempts» fi done

exit 0 Т.е. сети IP класса C будут заблокированы на неделю целиком, если ранее другие фильтры Fail2ban срабатывали на адреса из них 30 или более раз.Вот так выглядит результат:

# csf -t

A/D IP address Port Dir Time To Live Comment DENY 193.176.147.0/24 * in 6d 21h 34m 18s Subnet 193.176.147.0/24 is blocked for a week by Fail2ban after 641 attempts DENY 46.148.30.0/24 * in 6d 21h 34m 19s Subnet 46.148.30.0/24 is blocked for a week by Fail2ban after 332 attempts DENY 46.148.31.0/24 * in 6d 21h 34m 19s Subnet 46.148.31.0/24 is blocked for a week by Fail2ban after 334 attempts При написании данной статьи были использованы наработки со следующих ресурсов: https://extremeshok.com/5030/ubuntu-lts-fail2ban-with-csf-and-blocking-of-repeat-offenders-scan-log-files-to-ban-malicious-ips-and-prevent-brute-forcing-of-logins-with-configs/http://tecadmin.net/add-custom-iptables-rules-with-csf/https://rtcamp.com/tutorials/nginx/block-wp-login-php-bruteforce-attack/https://rtcamp.com/tutorials/nginx/fail2ban/https://www.xaker.name/forvb/showthread.php? t=28659https://beeznest.wordpress.com/2012/06/08/anti-nginx-dos-filter-for-fail2ban-4/https://debian.pro/1223http://www.michelem.org/2014/03/02/stopblock-apachenginx-hack-attempts-with-fail2ban/http://www.krazyworks.com/permanently-ban-ip-with-fail2ban/http://www.shellhacks.com/ru/RegEx-Nayti-IP-Adresa-v-Fayle-s-Pomoshchyu-Grep

© Habrahabr.ru