Защита ssh от брутфорса. Блокирование IP при подборе паролей
Если у вас есть сервер, на котором должна быть возможность подключения по ssh из интернета, значит всегда будут желающие подобрать пароль (brute force) для входа. Как бороться с такими «переборщиками»?
Лучше всего сделать авторизацию по ключу. Можно поменять порт (поможет, но не от всех желающих). А что делать, если нужно использовать стандартный порт и авторизацию по паролю?
В первую очередь запретить руту логиниться по паролю:
PermitRootLogin no
Далее, вы должны ограничить число пользователей у которых есть доступ к ssh.
AllowUsers user1 user2 user3
Эти настройки вы должны изменить или добавить в конфигурационном файле ssh /etc/ssh/sshd_config и перезапустить демон sshd.
Теперь в вашем /var/log/messages будет полно записей типа:
Oct 15 18:13:59 myserver sshd[7790]: Failed password for invalid user root from 212.83
.130.87 port 56520 ssh2
Можно избавиться и от этих назойливых попыток взлома. Достаточно установить и настроить одну из программ Fail2ban или DenyHosts. Они будут анализировать содержимое журнала /var/log/messages и особо ретивых брутфорсеров блокировать при помощи firewall.
Но мы лёгких путей не ищем! У меня на сервере нет python, необходимого для работы этих программ, да и блокировки при помощи файервола мне не нравятся.
Сделаем на perl простенький блокировщик с использованием /etc/hosts.deny. Он будет постоянно следить за сообщениями syslog, поступающими от sshd, анализировать их. Если с какого-то ip-адреса будет более 5 попыток входа «нелегальным» пользователем, этот ip будет добавлен в /etc/hosts.deny, а это значит демон tcpd заблокирует доступ с этого ip к sshd.
Для начала определимся где будет находиться наш блокировщик. Например в /root/bin/deny-hosts/.
mkdir /root/bin/deny-hosts
Создаём файл для списка заблокированных ip.
touch /etc/hosts.sshd.deny
В /etc/hosts.deny добавим такую строчку:
sshd : /etc/hosts.sshd.deny
Взаимодействие syslog и нашей программы организуем через именованные каналы (named pipe). Создаем канал:
mknod /root/bin/deny-hosts/auth.info p
chmod 600 /root/bin/deny-hosts/auth.info
И настроим syslog так чтобы сообщения от sshd попадали в этот канал. Добавим в /etc/syslog.conf такую строчку:
auth.info;mail.none |/root/bin/deny-hosts/auth.info
Теперь в /root/bin/deny-hosts/ создадим deny-hosts.pl такого содержания:
#!/usr/bin/perl
use Sys::Syslog;
$from = "admin\@myserver.com"; $to = "admin\@myserver.com"; %ban; %banned;
openlog("deny-hosts", "ndelay,pid", "local0"); open (FIFO, "/root/bin/deny-hosts/auth.info");
syslog(LOG_INFO, "started");
while (1) { while (<FIFO>) { $str = $_; if ($str=~/Failed password for invalid user .+ (.+) port/) { if(!$ban{$1}) { $ban{$1}=1; } else { $ban{$1}++; } foreach $key (keys %ban) { if($ban{$key}>5 && $key) { if (!$banned{$key}) { open (BL, '>>/etc/hosts.sshd.deny'); print BL $key,"\n"; close(BL); smtp_send($key); syslog(LOG_INFO, "IP banned: $key"); } delete($ban{$key}); $banned{$key} = 1; } } } } smtp_send("syslog restarted"); sleep 5; }
syslog(LOG_INFO, "exited");
close (FIFO); closelog();
sub smtp_send { my $body = $_[0];
my $time = time(); my ($sec,my $min,my $hour,my $mday,my $mon,my $year,my $wday,my $yday,my $isdst) = localtime($time); my $now = sprintf("%04d-%02d-%02d %02d:%02d:%02d ", ($year+1900), ($mon+1), $mday, $hour, $min, $sec);
if (open (SENDMAIL, "|/usr/sbin/sendmail -t")) { print SENDMAIL "From: $from\n"; print SENDMAIL "To: $to\n"; print SENDMAIL "Subject: IP banned $now\n\n"; print SENDMAIL "$body"; close (SENDMAIL); } }
Следует заменить в коде email-адреса с которого будут отправляться и на который будут приходить сообщения о заблокированных ip-адресах (в 5 и 6 строках кода).
Дайте права на запуск:
chmod 755 /root/bin/deny-hosts/deny-hosts.pl
Можно запускать скрипт вручную, а можно написать такой вот скрипт запуска/перезапуска:
#!/bin/sh
killall deny-hosts.pl /root/bin/deny-hosts/deny-hosts.pl &
И запускать его автоматически при старте системы.