Большинство взломов обнаруживают поздно, потому что никто не смотрит, кто входит на сервер. Злоумышленник с украденным паролем входит точно так же, как вы, и строка в логе выглядит обычной, если не знать, какие IP и ключи ваши. В этом руководстве показано, как провести аудит входов по SSH на сервере Linux, сопоставить каждый вход с ключом, проверить входы в панель aaPanel (BaoTa) и отправлять сообщение в Telegram при каждом входе, чтобы посторонний был заметен в течение нескольких секунд.
who # interactive sessions
ss -tnp | grep sshd # every SSH connection, including tunnels without a terminal
ssh -N), не открывает терминал, поэтому не отображается в who и w. Всегда дополнительно проверяйте ss -tnp или ps -ef | grep "sshd:". Соединение с незнакомого IP, открытое уже несколько дней, — серьёзный тревожный признак.last -a | head -30 # successful logins (from /var/log/wtmp)
lastb -a | head -30 # failed logins (from /var/log/btmp)
# Successful SSH logins with the method used (password or key)
grep "Accepted" /var/log/auth.log | tail -50 # Debian / Ubuntu
grep "Accepted" /var/log/secure | tail -50 # Rocky / AlmaLinux / CentOS
journalctl -u ssh -u sshd --since "7 days ago" | grep Accepted
В каждой строке указаны способ входа, пользователь, IP-адрес источника, а для ключей — отпечаток ключа:
Accepted password for root from 198.51.100.7 port 51234 ssh2
Accepted publickey for root from 203.0.113.20 port 60122 ssh2: ED25519 SHA256:Xq3vR8...
Сведите их вместе, чтобы сразу увидеть все IP-адреса источников и способы входа:
grep -h "Accepted" /var/log/auth.log* 2>/dev/null | awk '{for(i=1;i<=NF;i++){if($i=="Accepted")m=$(i+1); if($i=="from")ip=$(i+1)}; print m, ip}' | sort | uniq -c | sort -rn
Если вы входите только по ключам, любая строка Accepted password подозрительна.
Выведите отпечатки всех ключей, которым разрешён вход, и сравните их с отпечатками в логе:
ssh-keygen -lf /root/.ssh/authorized_keys
for h in /home/*; do [ -f "$h/.ssh/authorized_keys" ] && ssh-keygen -lf "$h/.ssh/authorized_keys"; done
У каждого ключа должен быть знакомый вам комментарий (например, alice@laptop). Удалите ключи, происхождение которых не можете объяснить, и проверьте, не добавил ли кто-то дополнительные файлы ключей через AuthorizedKeysFile в /etc/ssh/sshd_config.
В aaPanel на главной странице показаны последние входы в панель, а в разделе Logs → Panel logs (журналы → журналы панели) перечислены все входы с IP-адресами. Их также можно прочитать из командной строки:
sqlite3 /www/server/panel/data/default.db \
"select addtime, log from logs where type in ('Login','用户登录') order by id desc limit 30"
После входа проверьте в тех же журналах, что делалось в этой сессии (загрузка и скачивание файлов, задания cron, новые сайты). Затем включите Google Authenticator (two-step verification) (двухэтапная проверка) в Settings (настройки), задайте защищённый вход (security entrance) и по возможности ограничьте доступ к панели по IP, как описано в статье руководство по усилению безопасности aaPanel.
Создайте бота Telegram через @BotFather, отправьте ему сообщение и узнайте свой chat ID, как показано в статье ежедневный AI-отчёт о сервере. Затем создайте скрипт оповещения:
cat > /usr/local/bin/ssh-login-alert.sh <<'EOF'
#!/bin/bash
# Called by PAM when an SSH session opens: send user, source IP and host to Telegram
[ "$PAM_TYPE" = "open_session" ] || exit 0
TG_TOKEN="123456789:replace-with-your-bot-token"
TG_CHAT="123456789"
TEXT="SSH login on $(hostname): user=${PAM_USER} from=${PAM_RHOST} at $(date '+%F %T %Z')"
curl -s -m 5 "https://api.telegram.org/bot${TG_TOKEN}/sendMessage" \
--data-urlencode "chat_id=${TG_CHAT}" --data-urlencode "text=${TEXT}" >/dev/null 2>&1 &
exit 0
EOF
chmod 700 /usr/local/bin/ssh-login-alert.sh
Подключите его к PAM, чтобы он запускался для каждой SSH-сессии, включая входы по ключу и туннели:
echo "session optional pam_exec.so /usr/local/bin/ssh-login-alert.sh" >> /etc/pam.d/sshd
grep -i "^UsePAM" /etc/ssh/sshd_config # must be "UsePAM yes" (the default on most systems)
Не закрывайте текущее окно SSH, войдите из второго окна и проверьте, что сообщение в Telegram пришло. Ключевое слово optional и 5-секундный тайм-аут гарантируют, что сбой Telegram никогда не заблокирует ваш вход.
Accepted для этого пользователя из journalctl -u ssh -n 20. Делайте скрипт коротким: он выполняется при каждом входе.Неинтерактивные сессии (scp, sftp, туннели) часто не записываются в wtmp. Их фиксируют лог SSH и описанное выше оповещение через PAM.
Проверьте /var/log/auth.log.1 и сжатые файлы .gz (zgrep Accepted /var/log/auth.log*). Для более длинной истории отправляйте логи на другой сервер или сохраняйте оповещения в Telegram.
Не удалось решить проблему по этим шагам? Создайте тикет в поддержку, и круглосуточная техническая команда IMIDC поможет. Укажите IP сервера и подозрительные строки из логов, чтобы мы быстрее нашли причину.