
核心要点(TL;DR)
- SSH 被爆破的第一优先级是关闭密码登录,改用密钥认证,从根上消除爆破面。
- fail2ban 读取 auth.log 自动封禁高频失败 IP,是低成本高收益的补充防线。
- 改 sshd_config 前先备份并保留一个已登录会话,避免把自己锁在门外。
- 加固后用 lastb、fail2ban-client status 验证封禁与登录效果,形成闭环。
半夜收到 CPU 告警,登录服务器一看 /var/log/auth.log 里全是 Failed password for root,每分钟几十条——这是几乎所有公网 Linux 服务器都会遇到的 SSH 暴力破解。放任不管,轻则日志膨胀、带宽被占,重则弱口令被撞开直接沦陷。本文按「先止血、再加固、后验证」的顺序,给出可直接复制执行的 fail2ban 与密钥登录加固步骤,照着做就能把爆破面关掉。
一、先判断:你的 SSH 到底被爆破到什么程度
动手前先量化现状,避免盲目改配置。常用排查命令:
# 统计失败登录次数最多的来源 IP
sudo grep "Failed password" /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head -20
# 查看最近失败记录
sudo lastb | head -20
# 实时观察爆破流量
sudo tail -f /var/log/auth.log | grep -i failed如果失败次数集中在少数 IP,fail2ban 封禁效果明显;如果来源极其分散(僵尸网络),单靠封 IP 收益有限,必须优先关闭密码登录。同时确认当前 sshd 配置:
sudo sshd -T | grep -Ei 'passwordauth|permitrootlogin|pubkeyauth|port'二、根治手段:配置 SSH 密钥登录并禁用密码
密钥认证的私钥不出本机,暴力破解在数学上不可行,这是消除爆破面的根本措施。步骤:
- 本地生成密钥(已有可跳过):
ssh-keygen -t ed25519 -C "ops@example",建议设置私钥口令。 - 上传公钥:
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server,或手动追加到~/.ssh/authorized_keys。 - 验证密钥可登录:新开一个终端执行
ssh user@server,确认免密进入。这一步不做,后面改配置极易把自己锁在门外。 - 修改 sshd_config:
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
sudo sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sed -i 's/^#\?PubkeyAuthentication.*/PubkeyAuthentication yes/' /etc/ssh/sshd_config
sudo sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
sudo sshd -t && sudo systemctl reload sshd关键提醒:修改时保留一个已登录的 SSH 会话不要退出,若新连接失败可立即回滚备份。禁用 root 直登后,用普通用户登录再 sudo 提权。权限也要检查:chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys。
三、自动封禁:fail2ban 安装与 sshd 规则配置
密钥登录解决了「破得开」的问题,fail2ban 解决「烦不烦」的问题——它监控日志,对高频失败来源自动下发防火墙封禁。以 Debian/Ubuntu 为例:
sudo apt update && sudo apt install -y fail2ban
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local编辑 /etc/fail2ban/jail.local,在 [sshd] 段配置:
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 5
findtime = 10m
bantime = 1h
ignoreip = 127.0.0.1/8 你的办公出口IPCentOS/RHEL 需把 logpath 改为 /var/log/secure,并确认已安装 fail2ban-server。启动并设为开机自启:
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd参数含义对比:
| 参数 | 作用 | 建议值 |
|---|---|---|
| maxretry | 统计窗口内允许失败次数 | 3~5 |
| findtime | 失败计数时间窗口 | 10m |
| bantime | 封禁时长 | 1h 起,可递增 |
| ignoreip | 白名单,永不封禁 | 本机与办公出口 IP |
验证封禁是否生效:sudo fail2ban-client status sshd 查看 Currently banned,用 sudo fail2ban-client unban IP 手动解封误伤地址。
四、补强:防火墙与 sshd 加固清单
fail2ban 依赖防火墙后端,确认 banaction 与实际防火墙匹配(iptables、nftables 或 firewalld)。再叠加以下措施:
- 安全组/防火墙只放行可信来源的 22 端口,或改用跳板机统一入口。
- 可选调整端口(
Port 2222)降低扫描噪音,但要同步更新安全组与 fail2ban 的port。 - 设置
LoginGraceTime 30、MaxAuthTries 3,缩短攻击窗口。 - 开启登录审计与告警,把
Accepted publickey与封禁事件推送到监控。
在防护建议层面,如果不想逐台手工维护规则,可以借助 AegisX 这类主机安全能力统一管理 SSH 基线、异常登录告警与封禁策略,把单机脚本升级为可审计的集中防护。
五、行动建议:按顺序落地并验证
推荐执行顺序:先配密钥并验证 → 关闭密码登录 → 部署 fail2ban → 补防火墙与白名单 → 观察一周日志。验证清单:sshd -T | grep passwordauth 应为 no;fail2ban-client status sshd 能看到封禁数;lastb 失败记录明显下降;新终端仍可用密钥正常登录。全部通过后,再清理旧备份与测试账号,形成可复用的加固脚本,新机器上线即套用。
常见问题(FAQ)
SSH 被暴力破解,先改端口还是先关密码登录?
先关密码登录。改端口只是降低被扫描概率,属于隐蔽性手段;禁用密码认证并启用密钥登录才是消除爆破面。正确顺序是:先配好密钥并验证可登录,再设置 PasswordAuthentication no,最后按需调整端口与防火墙规则,避免顺序颠倒导致无法远程登录。
fail2ban 封禁了 IP,为什么日志里还有失败记录?
因为封禁只作用于新连接,已建立的连接和封禁生效前的尝试仍会写入日志;同时若攻击来自大量分散 IP,单个 IP 被封后其他 IP 仍会继续尝试。建议结合密钥登录彻底关闭密码入口,并适当调大 maxretry 统计窗口,必要时用防火墙做网段级限制。
配置密钥登录后仍然提示输入密码怎么办?
通常是 sshd_config 未生效或权限问题。检查是否设置了 PasswordAuthentication no 与 PubkeyAuthentication yes,用 sshd -t 校验语法后 systemctl reload sshd;同时确认 ~/.ssh 权限为 700、authorized_keys 为 600,属主正确,SELinux 环境下还需恢复安全上下文。
fail2ban 会不会误封自己或运维同事的 IP?
有可能,尤其是多人共用出口 IP 或密码输错多次时。建议把公司出口 IP、跳板机加入 ignoreip 白名单,并先用 bantime 较短的值观察一段时间;生产环境可配合邮件或 webhook 告警,发现误封及时 fail2ban-client unban 解封。
云服务器还需要额外做什么 SSH 防护?
在密钥登录与 fail2ban 之外,建议启用云安全组只放行可信来源,关闭 root 直接登录并改用普通用户加 sudo,开启登录告警与审计日志。若业务允许,可再叠加双因素认证或堡垒机统一入口,形成多层防护而非依赖单一手段。