
核心要点(TL;DR)
- 先查 auth.log 与 lastb 确认是否已有成功登录,再谈封禁。
- 禁用密码登录改公钥认证,是阻断 SSH 爆破最有效的一步。
- fail2ban 配合 nftables/iptables 可自动封禁高频失败 IP。
- 改默认端口只能减少噪音,不能替代密钥认证与限流。
凌晨收到一堆 SSH 登录失败告警,auth.log 每分钟刷出上百条 Failed password for root——这是 22 端口暴露在公网后最常见的场景。本文按「先取证、再止血、后加固」的顺序给出可直接复制的命令与检查清单,帮你在一小时内把爆破压下去,并确认服务器没有被攻破。
一、先确认:是噪音还是已经出事
不要急着封 IP,先判断有没有成功登录的痕迹。爆破本身不可怕,可怕的是其中一次猜中了。
# 今日失败次数(systemd 系统)
sudo journalctl -u ssh --since today | grep -c 'Failed password'
# Debian/Ubuntu 传统日志
sudo grep -c 'Failed password' /var/log/auth.log
# 统计攻击源 TOP10
sudo grep 'Failed password' /var/log/auth.log \
| awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head
# 关键:查是否有成功登录
last -a | head -20
sudo grep 'Accepted' /var/log/auth.log | tail -20同时检查 lastb(失败记录)、/root/.ssh/authorized_keys 是否被追加陌生公钥、crontab -l 与 /etc/cron.d/ 是否有可疑任务。只要出现来源不明的 Accepted publickey,就按入侵事件处理,先隔离再排查。
二、止血:自动封禁高频失败 IP
手工 iptables 封 IP 追不上扫描速度,用 fail2ban 做自动封禁。安装后写 /etc/fail2ban/jail.local:
[sshd]
enabled = true
port = ssh
filter = sshd
backend = systemd
maxretry = 5
findtime = 10m
bantime = 1h
ignoreip = 127.0.0.1/8 你的办公IP然后 sudo systemctl enable --now fail2ban,用 sudo fail2ban-client status sshd 查看当前封禁列表。若服务器用 nftables,把 banaction 设为 nftables-multiport,否则规则会写进不生效的 iptables 链。封禁只是止血,下面才是根治。
三、根治:关掉密码认证,只留公钥
绝大多数爆破成功案例都源于弱口令。正确顺序是:先配密钥并验证,再关密码。
- 本地生成密钥:
ssh-keygen -t ed25519 -C "ops@host"。 - 上传公钥:
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server。 - 新开终端验证
ssh -i ~/.ssh/id_ed25519 user@server能免密登录。 - 编辑
/etc/ssh/sshd_config:PasswordAuthentication no、PubkeyAuthentication yes、PermitRootLogin no、MaxAuthTries 3、LoginGraceTime 20。 sudo sshd -t校验语法,再sudo systemctl reload ssh。保留一个已登录会话,防止配置失误锁死。
权限同样关键:chmod 700 ~/.ssh、chmod 600 ~/.ssh/authorized_keys,属主必须是目标用户,否则 sshd 会拒绝密钥。
四、收敛攻击面:端口、来源与限流
改端口只能减少扫描噪音,不能替代认证加固,但配合来源限制收益明显。在 sshd_config 中设 Port 2222,并在防火墙只放行可信网段:
sudo nft add rule inet filter input tcp dport 2222 \
ip saddr != 203.0.113.0/24 drop也可用 AllowUsers deploy ops 做账号白名单。若必须保留 22 端口给外部,至少在云安全组层面限制来源 IP。改端口后记得同步 fail2ban 的 port 字段与监控告警。
五、验证与检查清单
| 检查项 | 命令/位置 | 期望结果 |
|---|---|---|
| 失败频率下降 | journalctl -u ssh --since -10m | grep -c Failed | 接近 0 |
| 密码登录已关闭 | sshd -T | grep passwordauth | no |
| root 禁止登录 | sshd -T | grep permitrootlogin | no |
| fail2ban 生效 | fail2ban-client status sshd | 有 Banned IP 列表 |
| 无异常公钥 | cat ~/.ssh/authorized_keys | 仅自己维护的密钥 |
防护建议:在完成上述配置后,可把登录失败告警、异常 IP 封禁与基线核查接入 AegisX 的持续监测能力,让爆破趋势与配置漂移在一个面板里可见,避免下次靠翻日志才发现问题。
六、行动建议
今天先做三件事:统计失败次数确认是否被爆破、检查 last 有无异常成功登录、部署 fail2ban 并设 bantime 至少 1 小时。本周内完成密钥登录切换与 PasswordAuthentication no,并把 22 端口的来源限制写进安全组。爆破不会停,但你可以让它永远猜不中。
常见问题(FAQ)
怎么快速判断 SSH 是不是正在被暴力破解?
看失败登录频率即可确认。执行 sudo journalctl -u ssh --since today | grep -c 'Failed password',数字上千基本就是被爆破;也可用 lastb | head 查看失败记录,或 grep 'Failed password' /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head 统计攻击源 IP。
只把 SSH 端口从 22 改成别的就安全了吗?
不够。改端口只是减少自动化扫描噪音,针对性扫描仍能发现新端口。真正有效的是禁用密码登录、仅允许公钥认证,并配合 fail2ban 或防火墙限流。建议顺序为:先配好密钥并验证可登录,再改 Port、设 PasswordAuthentication no,最后重启 sshd 并保留一个已登录会话做回滚。
fail2ban 封禁后为什么攻击日志还在涨?
多半是 jail 未真正匹配到日志或后端防火墙未生效。用 fail2ban-client status sshd 查看当前封禁数与日志路径,确认 /etc/fail2ban/jail.local 中 logpath 与实际日志一致(systemd 系统用 backend=systemd),再 fail2ban-client reload。若用 nftables,需确认 banaction 指向 nftables 而非默认 iptables。
禁用密码登录后自己登不上了怎么办?
先别断开现有会话。SSH 配置错误时,已建立的连接仍可用,可在其中修复 authorized_keys 权限(700 目录、600 文件)与属主,然后 sshd -t 校验配置再 systemctl reload ssh。云主机可借助控制台 VNC 登录救援。上线前务必用新终端实测密钥登录成功,再关闭密码认证。
还有哪些低成本加固手段值得一起做?
限制来源与权限最划算:防火墙只放行可信 IP 段访问 22 端口,sshd_config 设 PermitRootLogin no、MaxAuthTries 3、LoginGraceTime 20,并启用 AllowUsers 白名单。再叠加 fail2ban 的 recidive 规则封禁惯犯 IP,配合系统更新与登录告警邮件,形成持续防护。