Защита VPS от нечисти с помощью fail2ban и iptables

fail2ban · iptables · jail · защита vps · debian · linux
Как только в цифровом океане интернета рождается новый маленький беззащитный VPS, злые боты сбегаются со всех уголков Сети сканировать его наивно открытые миру порты и доступные веб-адреса с целью найти брешь и доложить своему хозяину. Юному серверу приходится учиться, как нарастить толстый панцирь, который убережёт его большинства вредных тварей. В этой заметке я расскажу, как помочь ему в этом. Однако, хоть дальнейшее повествование и будет на все сто правдиво только для сервера с ОС Debian, единственной задачей которого является хостинг сайтов, я думаю, что кому-то оно будет полезно и в некоторых других случаях.
Основным инструментом в построении защиты Linux-хоста является утилита iptables, которая управляет работой межсетевого экрана. Утилита fail2ban тоже использует iptables для блокировки пакетов с забаненных IP-адресов и python для детектирования таких адресов. Для большей безопасности я рекомендую сменить стандартный порт SSH на какой-нибудь экзотический. С этого и начнём.

Перенос SSH-сервера на другой порт

Это легко, и делается в два коротких шага. Сначала отредактируем файл конфига демона SSH:
sudo nano /etc/ssh/sshd_config
Сменим порт 22 на что-то сложное и пятизначное. Во избежание возможных конфликтов с другими программами, необходимо выбирать из диапазона динамических портов, а это значения от 49152 до 65535:
# What ports, IPs and protocols we listen for
#Port 22
Port 49681
Сохраним изменения (Ctrl+O), выйдем из nano (Ctrl+X) и перезапустим SSH-демона:
sudo service ssh restart
Готово! При следующем подключении необходимо явно указать порт:
ssh user@host -p 49681

Блокировка всех портов кроме HTTP, HTTPS и SSH

Я бы не рекомендовал держать на сервере с сайтами ещё какие-либо открытые в Сеть сервисы, под них лучше выделить отдельный VPS, и настроить его соответственно. В случае, когда единственной функцией является веб-хостинг, можно закрыть все порты, кроме тех двух, куда обычно направлены браузеры живых посетителей ресурса - 80 (HTTP) и 443 (HTTPS), и ещё одного, куда подключается администратор сервера по SSH (мы сменили его выше на 49681). Для начала создадим файл с правилами iptables:
sudo touch /etc/iptables.firewall-rules
Помещаем внутрь следующее содержимое:
*filter

# Разрешаем весь внутренный трафик на интерфейсе lo и запрещаем внутренний трафик, который не использует lo
-A INPUT -i lo -j ACCEPT
-A INPUT ! -i lo -d 127.0.0.0/8 -j REJECT

# Разрешаем все уже установленные входящие соединения
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Разрешаем весь исходящий трафик
-A OUTPUT -j ACCEPT

# Разрешаем все входящие HTTP и HTTPS соединения
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT

# Разрешаем подключение на порт 49681 для SSH
-A INPUT -p tcp -m state --state NEW --dport 49681 -j ACCEPT

# Разрешаем пинг
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT

# Запишем в лог все соединения, что были сброшены файерволом
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7

# Запретим все соединения, что явно не разрешены
-A INPUT -j REJECT
-A FORWARD -j REJECT

COMMIT
Теперь необходимо написать скрипт, который будет применять эти правила автоматически при загрузке системы. Создадим пустой файл и сразу сделаем его исполняемым:
sudo touch /etc/network/if-pre-up.d/firewall
sudo chmod +x /etc/network/if-pre-up.d/firewall
Его содержимое должно быть примерно следующим:
#!/bin/sh

/sbin/iptables-restore < /etc/iptables.firewall-rules
Первый раз указанную в скрипте команду нужно выполнить вручную от суперпользователя, чтобы сразу после настройки включить защиту, а при дальнейших перезагрузках ОС правила будет добавлять скрипт. Проверить, какие правила добавлены в iptables можно следующим способом:
sudo iptables -L

Динамическая защита от ботов при помощи fail2ban

Fail2ban обычно не входит в базовый набор утилит системы, и её нужно установить:
sudo apt-get install fail2ban
Перед началом работы рекомендуется сделать копию конфигурационного файла и вносить изменения только в него, так как оригинальный конфиг может быть перезаписан при обновлении:
cd /etc/fail2ban/ && cp jail.conf jail.local
Утилита fail2ban из коробки имеет несколько готовых фильтров для Apache, но я бы рекомендовал создать свои: один для лога access, а второй - для error. Виртуальные хосты следует настроить таким образом, чтобы эти логи для всех сайтов были общими, что позволяет защищать все сайты на сервере сразу при помощи всего лишь двух фильтров. Создадим пустые файлы для фильтров:
cd /etc/fail2ban/filter.d/
touch apache-access.conf
touch apache-error.conf
Примерное содержимое для фильтра apache-access.conf:
# Apache Access Filter

[Definition]

failregex =

^.* ‹HOST› .*///.*
^.* ‹HOST› .*\\\.*
^.* ‹HOST› .*w00tw00t.*
^.* ‹HOST› .*WinHttpRequest.*

ignoreregex =
Его можно и нужно дополнять новыми строками в секции failregex на основании того, какую подозрительную активность вы нашли в логе access.log. Выше блокируются запросы, содержащие слова "w00tw00t", "WinHttpRequest" или по три слеша в ту или другую сторону. Фильтр для error.log имеет точно такую же структуру:
# Apache Error Filter

[Definition]

failregex =

^.*\[client ‹HOST›\].*w00tw00t.at.ISC.SANS.DFind.*
^.*\[client ‹HOST›\].*Lost connection to MySQL server during query.*
^.*\[client ‹HOST›\].*client denied by server configuration.*
^.*\[client ‹HOST›\].*Invalid URI in request.*
^.*\[client ‹HOST›\].*/admin.php' not found or unable to stat
^.*\[client ‹HOST›\].*/wp-login.php' not found or unable to stat
^.*\[client ‹HOST›\].*/vam_rss2_info.php' not found or unable to stat
^.*\[client ‹HOST›\] File does no exist: .*typo3
^.*\[client ‹HOST›\] File does no exist: .*hostcmsfiles
^.*\[client ‹HOST›\] File does no exist: .*administrator
^.*\[client ‹HOST›\] File does no exist: .*bitrix
^.*\[client ‹HOST›\] File does no exist: .*bbadmin
^.*\[client ‹HOST›\] File does no exist: .*WebAdmin
^.*\[client ‹HOST›\] File does no exist: .*webmanage
^.*\[client ‹HOST›\] File does no exist: .*fck
^.*\[client ‹HOST›\] File does no exist: .*fckeditor
^.*\[client ‹HOST›\] File does no exist: .*web

ignoreregex =
В файл конфига jail.local в разделе HTTP servers необходимо подключить недавно созданные фильтры. Правильно укажите пути до файлов с логами, иначе работать не будет:
[apache-access]

enabled = true
port = http,https
filter = apache-access
logpath = /path/to/access.log
maxretry = 1
findtime = 600
bantime = 86400

[apache-error]

enabled = true
port = http,https
filter = apache-error
logpath = /path/to/error.log
maxretry = 1
findtime = 600
bantime = 86400
Полезно заодно включить (поменять с false на true поле enabled) предустановленные фильтры [ssh] и [ssh-ddos]. Для того, чтобы активировать защиту, перезапустим fail2ban:
sudo service fail2ban restart
После этого фильтры fail2ban и список заблокированных за плохое поведение IP-адресов можно будет увидеть в выводе команды:
sudo iptables -L

Результат

Пришло время подвести итог. Наш юный сервер стал уже не таким доверчивым, он не реагирует на пакеты, приходящие на порты, отличные от HTTP, HTTPS и SSH. Он может оценить, хорошо ли ведёт себя тот или иной клиент, и забанить в противном случае. Он будет защищаться при попытке взлома SSH.

Обсуждение

Никто не оставлял здесь комментариев.
Войдите на сайт, чтобы присоединиться к обсуждению.