Ubuntu服务器日志里频繁出现“Failed password for invalid user”或者“authentication failure”这类记录,基本可以判断有人在用自动化工具爆破SSH。这不是偶发事件,公网IP每天被扫描是常态。异常预警的核心不是等入侵发生后再看日志,而是让系统在异常累积到阈值时主动通知你,同时配合安全配置降低攻击成功率。
先解决一个误区:很多人以为装了fail2ban就万事大吉,但默认配置对Ubuntu 22.04/24.04的systemd日志兼容性并不理想。你会发现fail2ban读取/var/log/auth.log时经常漏报,因为新版本Ubuntu把认证日志交给了journald管理,auth.log虽然还在,但部分日志格式已经变化。更可靠的做法是直接基于journalctl的日志输出做监控脚本,或者用fail2ban的systemd后端。
第一步:确认当前系统日志中正在发生的异常类型登录服务器后执行:
journalctl -u ssh -n 50 --no-pager
如果输出中大量出现“Connection closed by authenticating user root 192.168.x.x port 55555 [preauth]”或者“Received disconnect from 203.0.113.5 port 45678:11: Bye Bye [preauth]”,说明SSH正在被持续探测。再看:
journalctl -u ssh --since "1 hour ago" | grep -c "Failed password"
这个数字如果在一小时内超过50,说明爆破强度不低。再进一步确认来源IP分布:
journalctl -u ssh --since "1 hour ago" | grep "Failed password" | awk '{print $(NF-3)}' | sort | uniq -c | sort -nr | head
注意不同Ubuntu版本的日志字段位置可能略有差异,如果awk取到的不是IP,先用grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}'来提取IP。这些命令能让你快速判断攻击来源是分散还是集中,集中来源适合直接封禁,分散来源则需要更系统的策略。
第二步:建立基于日志的实时异常预警机制不建议一上来就上复杂的监控平台。Ubuntu服务器上最轻量的做法是用systemd timer配合一个bash脚本,每5分钟检查一次认证失败次数,超过阈值就发送告警。脚本核心逻辑如下:
#!/bin/bash
THRESHOLD=30
COUNT=$(journalctl -u ssh --since "5 minutes ago" --no-pager | grep -c "Failed password")
if [ "$COUNT" -gt "$THRESHOLD" ]; then
echo "SSH暴力破解预警:过去5分钟失败登录次数达到 $COUNT 次" | mail -s "安全告警" admin@example.com
fi
把这个脚本保存为/usr/local/bin/ssh-alert.sh,然后创建timer单元:
# /etc/systemd/system/ssh-alert.timer [Unit] Description=SSH异常登录预警 [Timer] OnBootSec=5min OnUnitActiveSec=5min [Install] WantedBy=timers.target
# /etc/systemd/system/ssh-alert.service [Unit] Description=SSH异常登录预警执行 [Service] Type=oneshot ExecStart=/usr/local/bin/ssh-alert.sh
执行systemctl enable ssh-alert.timer && systemctl start ssh-alert.timer即可。邮件发送需要服务器上配置好mailx或postfix,如果不想依赖邮件,可以改成调用Webhook推送,比如把告警内容POST到企业微信或钉钉机器人,这样手机端能实时收到。
第三步:针对日志异常来源的自动封禁策略预警只是告诉你出事了,自动封禁才能减少后续压力。Ubuntu上最直接的工具是fail2ban,但必须正确配置后端。安装后创建本地配置:
# /etc/fail2ban/jail.local [DEFAULT] backend = systemd bantime = 3600 findtime = 600 maxretry = 5 ignoreip = 127.0.0.1/8 ::1 你的办公IP [sshd] enabled = true port = ssh logpath = /var/log/auth.log
关键点是backend = systemd,这样fail2ban会通过journald读取日志,不会漏掉新格式的认证失败记录。maxretry设成5意味着10分钟内同一IP失败5次就封禁1小时。如果你的服务器只允许密钥登录,可以把maxretry降到3。重启fail2ban后,用fail2ban-client status sshd查看封禁数量。
但fail2ban有一个盲区:它只处理SSH服务的认证失败,对于其他服务的异常日志无能为力。如果你的服务器还运行了Nginx、MySQL或自定义应用,建议再加一层基于iptables的实时封禁脚本。思路是持续跟踪journald中所有标记为“Failed”或“Invalid”的日志,提取来源IP,超过频率阈值就加入iptables拒绝列表。这种脚本网上有很多现成实现,核心是journalctl -f配合管道处理,但要注意控制资源占用,不建议在低配VPS上跑复杂的实时管道。
第四步:从源头降低日志异常的安全配置预警和封禁都是事后手段,真正有效的安全配置能大幅减少异常日志的产生。第一项是关闭密码登录,只允许密钥认证。编辑/etc/ssh/sshd_config:
PasswordAuthentication no ChallengeResponseAuthentication no PubkeyAuthentication yes PermitRootLogin prohibit-password
修改后执行systemctl reload ssh。这样配置后,那些“Failed password”日志会直接消失,因为SSH根本不再接受密码验证请求。攻击者面对密钥认证的服务器,爆破成功率趋近于零,日志里只会剩下连接后主动断开的记录。
第二项是修改默认SSH端口。虽然安全圈对改端口有争议,认为这只是隐藏而非防护,但从日志噪音的角度看,改到非22端口后,自动化扫描的日志量能下降90%以上。你的异常预警脚本会变得更有意义,因为剩下的连接尝试大概率是针对你服务器的定向行为,而不是全网无差别扫描。在sshd_config中修改Port 2222,同时记得在防火墙放行新端口。
第三项是限制SSH登录用户。在sshd_config中添加:
AllowUsers deploy@192.168.1.0/24 ubuntu@10.0.0.5
这样即使有人拿到了密码或密钥,只要来源IP和用户名不匹配,也无法登录。对于跳板机或管理机场景尤其有效。
第五步:日志轮转与审计保留异常预警依赖历史日志,但Ubuntu默认的logrotate配置对auth.log只保留4周,对于需要追溯安全事件的场景远远不够。建议调整/etc/logrotate.d/rsyslog中的配置,将auth.log的rotate从4改为12,并启用compress。同时把journald的存储策略改为持久化:
# /etc/systemd/journald.conf Storage=persistent SystemMaxUse=500M MaxRetentionSec=3month
这样即使系统重启,认证日志也不会丢失。对于需要合规审计的场景,还可以配置rsyslog把auth日志实时转发到独立的日志服务器,避免服务器被入侵后日志被篡改。
另外,定期人工检查也是预警体系的一部分。每周花五分钟执行一次:
journalctl -u ssh --since "7 days ago" | grep -E "Accepted|Failed" | awk '{print $1, $2, $3, $(NF-3), $(NF-5)}' | sort | uniq -c | sort -nr | head -20
这条命令能列出过去一周所有成功和失败的登录记录,按出现次数排序。如果看到某个IP在奇怪的时间段成功登录,或者某个用户名反复失败后突然成功,那就是需要深入排查的信号。
第六步:结合系统资源监控识别日志异常背后的攻击类型有些攻击不会在认证日志中留下明显痕迹,比如慢速CC攻击或者针对Web应用的漏洞扫描。这时候需要把日志预警和系统指标结合起来。当CPU使用率突然飙升但登录日志正常时,检查Nginx访问日志中是否有大量相同路径的请求:
tail -n 10000 /var/log/nginx/access.log | awk '{print $7}' | sort | uniq -c | sort -nr | head
如果某个路径被请求了数千次,且来源IP分散,大概率是扫描器在探测漏洞。针对这种情况,可以在Nginx配置层面对敏感路径直接返回444,或者用limit_req模块限制单IP请求频率。Ubuntu的ufw防火墙也可以配合limit规则限制连接速率:
ufw limit ssh ufw limit 80/tcp
这样每个IP在30秒内只能新建6个连接,超过就被临时拒绝,对慢速爆破和CC都有抑制作用。
最后强调一点:日志预警系统的价值在于持续运行和及时响应。很多服务器部署了fail2ban和监控脚本后,因为告警邮件太多被管理员忽略,最终形同虚设。建议对告警进行分级,只有达到较高阈值才推送手机通知,日常低频异常只记录不打扰。安全配置的目标不是消除所有日志异常,而是让真正的威胁在噪音中凸显出来。
