ADG Оставить заявку
Блог Информационная безопасность 4 мин чтения

50 000 попыток за ночь: переходим на SSH-ключи

В логах одного из серверов обнаружили пятьдесят тысяч попыток входа за ночь - словарная атака на SSH. Перевели всё на ключи, убрали пароли, сдвинули порт. Атаки не прекратились, но стали бесполезны.

Контекст момента

Брутфорс SSH-портов становится массовым - ключи вытесняют пароли на Linux-серверах

Началось банально. Один из сисадминов заметил, что сервер под утро ведёт себя как-то вяло - не критично, но заметно. Открыли /var/log/auth.log - и там пятьдесят с чем-то тысяч строк вида Failed password for invalid user admin from 218.x.x.x. За одну ночь. Один сервер. Один порт 22.

Формально - ничего страшного. Пароли у нас были нормальные, root-логин по SSH отключён. Но сам факт такого объёма атаки потребовал разобраться и закрыть вопрос правильно, а не просто посмотреть и забыть.

Откуда это берётся

Про ботнеты мы уже писали: заражённые машины по всему миру, никакой координации с человеком, просто перебирают адреса и словари. SSH на 22 порту - одна из любимых целей. Словарь несложный: admin, root, test, user, guest, ftp, плюс имена типа john, oracle, postgres. Потом идут пароли: 123456, password, admin, название сервиса.

Если в системе есть хоть один слабый аккаунт - рано или поздно попадут. А с пятьюдесятью тысячами попыток за ночь вопрос не «если», а «когда».

Что сделали

Решение на самом деле простое, просто требует аккуратности при накатке - не хочется выйти из сервера и не войти обратно.

Генерация ключей. На каждой рабочей машине администраторов генерируем пару через ssh-keygen. Алгоритм RSA, 2048 бит - вполне нормально. Приватный ключ с паролем, публичный - на сервер в ~/.ssh/authorized_keys. Это принципиальный момент: приватный ключ никуда не отправляется, сидит на машине администратора за паролем.

Проверяем, что вход по ключу работает - не закрывая существующую сессию. Открываем второй терминал, пробуем. Если зашло - продолжаем.

Правим sshd_config:

PasswordAuthentication no
ChallengeResponseAuthentication no
PermitRootLogin no

Перечитываем конфиг (service ssh reload), проверяем в третьем терминале - теперь без ключа не войти. Закрываем лишние сессии.

Меняем порт. 22 - порт, который сканируют в первую очередь. Перевели на нестандартный (что-то выше тысячи). Это не защита сама по себе - кто ищёт целенаправленно, найдёт. Но девяносто процентов автоматических сканеров работают по стандартным портам, и объём мусора в логах сразу падает.

AllowUsers - явный список пользователей, которым разрешён SSH. Всё, что не в списке, автоматически получает отказ ещё до авторизации.

Что поменялось

Атаки не прекратились. Они и не могут прекратиться - мы не контролируем ботнеты. Но теперь это выглядит иначе: в логах Connection refused или Connection closed без всяких Failed password. Боты стучатся - дверь закрыта, разговор не начинается.

Нагрузки от перебора практически нет: SSH-демон отвергает соединение быстро, без попыток подобрать пароль, потому что пароль больше не метод входа.

Один момент, который приходится держать в голове: если потеряешь приватный ключ или рабочую машину без резервной копии ключа - можешь потерять доступ к серверу. Поэтому ключи резервируем. У каждого администратора своя пара, все публичные ключи в authorized_keys. Если один из нас не может войти - другой заходит и разбирается.

Для серверов без физического доступа (арендованные, удалённые площадки) дополнительно держим аварийную консоль - IPMI/iLO решает именно такие ситуации. На случай если что-то пошло совсем не так.

Про fail2ban

Параллельно поставили fail2ban - он смотрит логи и банит IP после нескольких неудачных попыток. С ключами это скорее дополнительный слой, чем необходимость. Но штука полезная: сокращает шум в логах и слегка уменьшает нагрузку на сеть, не пуская особо настойчивых.

Где это не работает без дополнительных шагов

Ключи решают задачу для серверов, где администраторы заходят со своих машин. Сложнее с ситуациями, где надо дать временный доступ подрядчику или зайти с чужого компьютера. Тут либо выдаёшь временный ключ (и потом убираешь из authorized_keys), либо смиряешься с паролем для конкретного пользователя с ограниченными правами.

Для разработчиков в команде клиента отдельная история: не все умеют работать с ключами, приходится объяснять. Но это разовое усилие, потом привыкают.

В целом - решение рабочее, накатывается за час на любое количество серверов, и вопрос брутфорса SSH закрывается полностью. Пятьдесят тысяч попыток в логах всё равно остаются, но они теперь просто статистика, а не угроза.

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.