Доброго времени суток!
Сегодня мы расскажем вам о том, как защитить web-сервер от DDOS-атак с использованием пакета fail2ban.
Предыстория: недавно, на веб-сервере клиента, был замечен подозрительно высокий трафик запросов. В лог-файле access.log наблюдалось следующее: (tail -f /var/log/nginx/access.log)
46.39.53.193 - - [09/Feb/2017:11:43:23 +0900] "CONNECT www.google.com:443 HTTP/1.0" 400 181 "-" "-" 138.201.48.4 - - [09/Feb/2017:11:43:25 +0900] "CONNECT 1xbet.com:443 HTTP/1.1" 400 181 "-" "-" 223.150.225.7 - - [09/Feb/2017:11:43:27 +0900] "GET http://m.search.yahoo.com/ HTTP/1.1" 200 612 "http://m.search.yahoo.com/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" 116.115.206.41 - - [09/Feb/2017:11:43:29 +0900] "CONNECT search.yahoo.com:443 HTTP/1.1" 400 181 "-" "-" 52.166.249.182 - - [09/Feb/2017:11:43:34 +0900] "CONNECT tados-s.westeurope.cloudapp.azure.com:15002 HTTP/1.0" 400 181 "-" "-" 188.244.145.169 - - [09/Feb/2017:11:43:51 +0900] "POST /Exam/Test/Test HTTP/1.1" 302 141 "http://gw.lensk.gosnadzor.ru/Exam/Test/RenderView?attemptId=37089" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)" 188.244.145.169 - - [09/Feb/2017:11:43:51 +0900] "GET /Exam/Test/RenderView?attemptId=37089 HTTP/1.1" 200 2443 "http://gw.lensk.gosnadzor.ru/Exam/Test/RenderView?attemptId=37089" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)" 61.146.233.116 - - [09/Feb/2017:11:43:55 +0900] "GET http://m.search.yahoo.com/ HTTP/1.1" 200 612 "http://m.search.yahoo.com/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" 41.200.137.14 - - [09/Feb/2017:11:43:55 +0900] "CONNECT store.steampowered.com:443 HTTP/1.1" 400 181 "-" "-" 162.244.10.249 - - [09/Feb/2017:11:43:57 +0900] "GET http://chekfast.zennolab.com/proxy.php HTTP/1.1" 404 151 "RefererString" "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0" 125.66.152.161 - - [09/Feb/2017:11:44:01 +0900] "GET http://zc.qq.com/cgi-bin/iframe/othmailreg/init_11?r=0.414529966383488 HTTP/1.1" 404 151 "http://zc.qq.com/cgi-bin/iframe/othmailreg/init_11?r=0.414529966383488" "Mozilla/5.0 (Windows; U; Windows NT 5.1) Gecko/20070803 Firefox/1.5.0.12" 120.27.247.33 - - [09/Feb/2017:11:44:09 +0900] "CONNECT search.yahoo.com:443 HTTP/1.1" 400 181 "-" "-" 52.166.249.182 - - [09/Feb/2017:11:44:12 +0900] "\x05\x01\x00" 400 181 "-" "-" 43.241.216.172 - - [09/Feb/2017:11:44:15 +0900] "GET http://mobile.12306.cn/weixin/leftTicket/query?leftTicketDTO.train_date=2017-02-01&leftTicketDTO.from_station=CUW&leftTicketDTO.to_station=%E6%B8%A1%E5%B8%82&purpose_codes=ADULT HTTP/1.1" 404 208 "https://kyfw.12306.cn/otn/lcxxcx/init" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.73 Safari/537.36" 188.244.145.169 - - [09/Feb/2017:11:44:18 +0900] "POST /Exam/Test/Test HTTP/1.1" 302 141 "http://gw.lensk.gosnadzor.ru/Exam/Test/RenderView?attemptId=37089" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)" 188.244.145.169 - - [09/Feb/2017:11:44:18 +0900] "GET /Exam/Test/RenderView?attemptId=37089 HTTP/1.1" 200 2430 "http://gw.lensk.gosnadzor.ru/Exam/Test/RenderView?attemptId=37089" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)" 162.245.82.89 - - [09/Feb/2017:11:44:19 +0900] "CONNECT auth.api.sonyentertainmentnetwork.com:443 HTTP/1.0" 400 181 "-" "-" 58.83.130.81 - - [09/Feb/2017:11:44:29 +0900] "GET http://dynamic.12306.cn/mapping/kfxt/zwdcx/LCZWD/cx.jsp?cz=%E5%A4%AA%E5%8E%9F&cc=K1082&cxlx=0&rq=2017-02-09&czEn=-E5-A4-AA-E5-8E-9F&tp=1486608269332 HTTP/1.1" 404 579 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36" 155.94.65.85 - - [09/Feb/2017:11:44:30 +0900] "GET http://a.yesadsrv.com/display.php?nid=4&zone=119285&type=pop&sid=76697&pid=94049&subid=&opt1=&opt2= HTTP/1.0" 404 177 "http://www.monsports.com/2016/02/16/exceptional-maro-itoje-a-future-england-captain-in-the-making-says-veteran-nick-easter/" "Mozilla/5.0 (Windows NT 6.1; rv:38.0) Gecko/20100101 Firefox/38.0" 61.224.43.77 - - [09/Feb/2017:11:44:33 +0900] "GET http://m.search.yahoo.com/ HTTP/1.1" 200 612 "http://m.search.yahoo.com/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" 137.74.0.220 - - [09/Feb/2017:11:44:33 +0900] "CONNECT www.google.pl:443 HTTP/1.1" 400 181 "-" "-"
В логе было отчетливо видно, что производиться ddos-атака. (причины атаки неизвестны до сих пор). На web-сервере не размещены коммерческие ресурсы. Есть CRM исключительно для внутреннего использования. Открыты для доступа удаленных подразделений организации. За сутки, на данном linux сервере, почти закончилась оперативная память: из 4Gb оставалось ~450Мб. Было решено временно остановить демон web-сервера Nginx. После проведенного анализа рынка существующего ПО, по защите от DDoS-атак выбор пал на софт fail2ban (спасибо за подсказку, моему другу и отличному linux-администратору — Диме Водолазову). Данный софт анализирует любой из предоставленных ему log-файлов и по определенным правилам может блокировать «подозрительные» соединения.
В Интернете есть много статей по настройке данного ПО, но мы решили написать свою, так как многие статьи, на наш взгляд, имеют не правильное описание настройки fail2ban. (p.s. софт может защищать не только web-сервер но и другие сетевые службы и сервисы).
Первым делом, мы установили официальный пакет с репозитория Ubuntu, но в процессе эксплуатации софта выяснилось, что он «из коробки» не включает в себя модуль БД sqlite3 для хранения заблокированных ip-адресов и увы, после перезапуска демона fail2ban, все заблокированные адреса благополучно очищались, а при повторном запуске софт начинал их заново блокировать и так, до следующей перезагрузки. Разумеется, такой вариант нас не устраивал. Было решено установить ПО из исходников, таким образом, убить двух зайцев:
- установить последнюю (самую новую) версию (в репозитории была довольно-таки старая);
- включить использование модуля БД sqlite3 для хранения уже заблокированных адресов.
Теперь перейдем к установке и настройке fail2ban:
ОС: Ubuntu server 14.04
Web-сервер: nginx
Переходим по ссылке http://www.fail2ban.org/wiki/index.php/Downloads, копируем ссылку на файл stable (на момент написания статьи актуальная версия 0.9.4) и скачиваем ее на сервер через wget:
wget https://github.com/fail2ban/fail2ban/archive/0.9.4.tar.gz
Далее распаковываем скачанный архив:
sudo tar zxvf 0.9.4.tar.gz
И переходим в директорию с ПО:
cd fail2ban-0.9.4/
Запускаем установку:
./setup.py install
после установки переходим в каталог files
cd files/
и копируем init-файл для управления демоном fail2ban. В нашем случае, пойдет файл debain-initd, его нужно скопировать в директорию /etc/init.d/ под другим, более понятным названием, скажем: fail2ban:
sudo cp debian-initd /etc/init.d/fail2ban
Затем прописываем исполняемому файлу необходимые права и добавляем в автозагрузку:
chmod 755 /etc/init.d/fail2ban update-rc.d fail2ban defaults
На данном этапе установка закончена. Далее будем конфигурировать установленный софт:
Для начала, необходимо настроить хранение заблокированных ip-адресов в файле БД: сначала проверяем, подключен ли модуль БД, для этого, достаточно удостовериться в наличии строки dbfile = /var/lib/fail2ban/fail2ban.sqlite3 в файле /etc/fail2ban/fail2ban.conf
sudo nano /etc/fail2ban/fail2ban.conf
Затем,в самом низу находим параметр dbpurgeage = он отвечает за срок хранения записи в БД (в секундах), устанавливаем свое (на свое усмотрение) мы указали 1 год:
dbpurgeage = 31536000 #31536000секунд - 1 год либо #604800секунд - 7 дней (неделя)
За основную настройку отвечает файл jail.conf он хранит в себе информацию, о так называемых фильтрах, которые мы будем применять для защиты сервера. Открываем файл /etc/fail2ban/jail.conf для редактирования и добавляем в самом конце следующие строки:
[http-query-ddos] enabled = true port = http,https filter = http-query-ddos logpath = /var/log/nginx/access.log maxretry = 10 findtime = 60 bantime = 31536000 action = iptables[name=HTTP, port=http, protocol=tcp]
где,
[http-query-ddos] - секция кода с наименованием фильтра enabled = true - активен или не активен данный фильтр port = http,https - обозначение портов filter = http-query-ddos - наименование фильтра (создадим позже) в директории filter.d logpath = /var/log/nginx/access.log - лог-файл для анализа maxretry = 10 - максимальное количество зафиксированных попыток лог-файле findtime = 60 - период времени, в течение которого будет производиться проверка maxretry (значение выше) в сек. bantime = 31536000 - время в бана (в сек. 31536000 - 1 год) action = iptables[name=HTTP, port=http, protocol=tcp] - действие при выявлении
Далее находим параметр ignoreip по умолчанию, его значение 127.0.0.1/8. Он отвечает за список тех ip-адресов, которые будут пропускаться и не проверяться софтом. Так называемые «свои» ip, туда можно например включить ip из локальной сети 192.168.0.0/24 или какой-нибудь белый ip: 8.8.8.8, значения записываются через пробел, также можно использовать общепринятое указание маски, Например:
ignoreip = 127.0.0.1/8 192.168.0.0/24 8.8.8.8
Далее создадим сам фильтр для распознавания нетипичных запросов в логах web-сервера, как ранее упоминалось, все фильтры расположены в директории filter.d, переходим туда и создаем
cd filter.d/ sudo touch http-query-ddos.conf
Далее открываем созданный файл и вносим туда следующий код:
# Fail2Ban configuration file # # Author: http://www.go2linux.org # [Definition] # Option: failregex # Note: This regex will match any GET entry in your logs, so basically all valid and not valid entries are a match. # You should set up in the jail.conf file, the maxretry and findtime carefully in order to avoid false positives. failregex = ^<HOST> -.*"(GET|POST|CONNECT) # Option: ignoreregex # Notes.: regex to ignore. If this regex matches, the line is ignored. # Values: TEXT # ignoreregex =
Самой главной строкой в этом файле является переменная с регулярным выражение failregex = ^<HOST> -.*»(GET|POST|CONNECT), где сказано, что нужно из лог файла следить за всеми HOST (ip-адреса) с запросами GET|POST|CONNECT, то есть, соединив правило из файла jail.conf и данный файл, программа будет искать следующую логику:
Если в файле access.log появился запрос GET|POST|CONNECT и HOST инициировавший данный запрос, сделал это более чем 10 раз в 60 секунд — то заблокировать его. Вот такая вот логика, значения которой Вы можете менять самостоятельно, можете указать, хоть 1 попытку запроса с любого ip и разрешить полный доступ только на «белые», которые указаны в параметре ignoreip. Остальное всё будет заблокировано.
После успешного сохранения настроек, необходимо перезапустить демон fail2ban:
sudo /etc/init.d/fail2ban restart
После перезапуска можем посмотреть работу программы в лог-файле:
sudo tail -f /var/log/fail2ban.log 2017-02-09 13:48:03,863 fail2ban.filter [19867]: INFO [http-query-ddos] Found 41.210.125.169 2017-02-09 13:48:08,863 fail2ban.filter [19867]: INFO [http-query-ddos] Found 41.210.125.169 2017-02-09 13:48:12,863 fail2ban.filter [19867]: INFO [http-query-ddos] Found 41.210.125.169 2017-02-09 13:48:16,863 fail2ban.filter [19867]: INFO [http-query-ddos] Found 41.210.125.169 2017-02-09 13:48:22,863 fail2ban.filter [19867]: INFO [http-query-ddos] Found 41.210.125.169 2017-02-09 13:48:22,844 fail2ban.filter [19867]: INFO [http-query-ddos] Ignore 192.168.0.32 by ip 2017-02-09 13:48:23,844 fail2ban.filter [19867]: INFO [http-query-ddos] Ignore 192.168.0.32 by ip 2017-02-09 13:48:28,863 fail2ban.filter [19867]: INFO [http-query-ddos] Found 41.210.125.169 2017-02-09 13:48:30,863 fail2ban.filter [19867]: INFO [http-query-ddos] Found 41.210.125.169 2017-02-09 13:48:38,863 fail2ban.filter [19867]: INFO [http-query-ddos] Found 41.210.125.169 2017-02-09 13:48:45,863 fail2ban.filter [19867]: INFO [http-query-ddos] Found 41.210.125.169 2017-02-09 13:48:55,863 fail2ban.actions [19867]: NOTICE [http-query-ddos] Ban 41.210.125.169
в лог-файле видно, что сработал фильтр [http-query-ddos] нашел ip 41.210.125.169 — 9 раз и на 10 заблокировал его. Также в логе можно видеть текст Ignore 192.168.0.32 by ip где также понятно, что данный ip (из локальной сети) был пропущен из проверки, так как он у нас использован в параметре ignoreip.
Так как, при многочисленных запросах, сильно увеличивается размер log-файлов и они могут «вздуться» до неимоверных размеров, необходимо производить их ротацию, то есть при достижении логом определенного (максимального) размера, архивируем его и создаем новый. Для этого, мы будем использовать пакет logrotate. Устанавливаем:
sudo apt-get -y install logrotate
Далее открываем (создаем) конфигурационный файл для ротации файла fail2ban.log
sudo nano /etc/logrotate.d/fail2ban
и добавляем туда следующее содержимое:
"/var/log/fail2ban.log" { su root root daily rotate 7 size=16M compress missingok notifempty create 0640 root root sharedscripts postrotate # Перезапуск fail2ban sudo service fail2ban restart endscript # Между postrotate и endscript расположены команды # интерпретатора sh(1), исполняемые непосредственно после ротации. }
Сохраняем и закрываем.
Далее проверяем правильность настройки следующей командой:
logrotate -d /etc/logrotate.conf
Если всё нормально, то видим следующее (среди большого количества текста, возможно нужно будет покрутить скролл):
rotating pattern: "/var/log/fail2ban.log" 16777216 bytes (7 rotations) empty log files are not rotated, old logs are removed considering log /var/log/fail2ban.log log does not need rotating not running postrotate script, since no logs were rotated
После установки пакета logrotate он автоматически прописывает задание в /etc/cron.daily, там должен лежать файл logrotate, который будет ежедневно запускаться и выполнять ротацию для файлов, расположенных в директории /etc/logrotate.d/
На этом, установка fail2ban для защиты web-сервера завершена, спасибо за внимание!