阿里云服务器SSH暴力破解防护实战:从发现攻击到fail2ban+firewalld联动加固
起因:频繁异地登录没当回事,结果服务器在对外扫描SSH
起初只是注意到 /var/log/secure 里有大量异地IP的登录失败记录,以为是常见的公网扫描噪音,没太在意。直到某天检查网络连接时发现服务器正在主动对外发起大量SSH连接请求——服务器本身已经被入侵,变成了攻击跳板。
进一步排查发现一个恶意脚本在后台运行,逻辑大致是:
- CPU 核心数少 → 对外扫描 SSH(弱口令爆破)
- CPU 核心数多 → 挖矿
扫描目标使用的都是经典弱口令:123456、admin、postgres、root/root 等。
处置过程
第一步:改强密码
最基础也最紧急的一步。不管后续加什么防护,弱密码是一切问题的根源。
# 生成一个随机强密码并修改
openssl rand -base64 24
passwd root
同时检查了所有可登录用户,确保没有遗留弱口令账户。
第二步:配置 fail2ban + firewalld + sshd 三层防护
sshd 加固
# /etc/ssh/sshd_config 关键配置
PermitRootLogin no # 禁止root直接登录(或改为prohibit-password)
PasswordAuthentication yes # 保留密码认证(配合fail2ban),有条件可换密钥认证
MaxAuthTries 3 # 单次连接最大尝试次数
ClientAliveInterval 300 # 空闲超时断开
firewalld 放行必要端口
# 启动并设置开机自启
sudo systemctl enable --now firewalld
# 放行SSH和Web服务
sudo firewall-cmd --add-service=ssh --permanent
sudo firewall-cmd --add-service=http --add-service=https --permanent
sudo firewall-cmd --reload
⚠️ 踩坑点:之前 firewalld 处于 inactive 状态,fail2ban 虽然在计数和记录 Ban,但封禁动作完全没有在网络层生效。firewalld 启动后重启 fail2ban,8条 rich rules 才真正加载到防火墙中。fail2ban 依赖 firewalld 来执行实际的网络层拦截,两者缺一不可。
fail2ban 配置
# /etc/fail2ban/jail.local
[sshd]
enabled = true
maxretry = 3 # 3次失败即封禁
findtime = 3600 # 1小时滑动窗口
bantime = 86400 # 封禁24小时
banaction = firewallcmd-rich-rules # 通过firewalld rich rules执行封禁
sudo systemctl enable --now fail2ban
fail2ban 的工作原理:它是怎么串联 sshd 和 firewalld 的
这三个组件各自独立,通过日志和命令行接口形成联动链路:
sshd 写认证日志 → systemd journal
↓
fail2ban 实时读取 journal(backend=systemd, journalmatch=_SYSTEMD_UNIT=sshd.service)
↓
正则匹配 "Failed password" 等模式,提取攻击者IP
↓
滑动窗口计数:1小时内同一IP失败≥3次 → 触发封禁
↓
调用 banaction:firewall-cmd --add-rich-rule="rule family='ipv4' source address='<IP>' port port='ssh' protocol='tcp' reject type='icmp-port-unreachable'"
↓
firewalld 在内核 netfilter 层插入拒绝规则
↓
后续该IP的SSH包在内核层被reject,不再到达sshd进程
↓
24小时后 fail2ban 调用 actionunban 移除规则
关键点:fail2ban 不是通过SSH协议交互获取信息的,它是一个纯粹的日志分析器。它读日志、做计数、调命令,整个过程对 sshd 完全透明。
为什么有了 firewalld 还要用 fail2ban?
因为 SSH 端口必须对外开放,这是业务需要。
- firewalld 能做的:开放/关闭端口、限制来源IP段。但它无法区分"正常登录"和"暴力破解"——只要端口开着,所有IP都能连上来尝试。
- fail2ban 能做的:在不关闭端口的前提下,动态识别并封禁恶意IP。正常用户不受影响,只有触发阈值的攻击者被拦截。
简单说:firewalld 管"谁能进门",fail2ban 管"谁在门口搞破坏就踢出去"。两者配合才能既保证SSH可用又有效防御暴力破解。
验证防护效果
修复后的对比数据(近2小时):
| 指标 | 数值 |
|---|---|
| SSH总失败登录 | 72次 |
| 新封禁IP | 3个 |
| 重启后恢复封禁 | 16个 |
| 被封IP封禁后SSH记录 | 0条(证明firewalld已在网络层拦截) |
验证方法:被封IP在Ban时间点之后,/var/log/secure 中再无任何该IP的记录——说明数据包在内核层就被拒绝了,根本没到达sshd进程。
经验总结
- 不要忽视频繁的异地登录失败,这可能是入侵的前兆或已经入侵的信号
- 弱密码是万恶之源,改强密码是所有安全措施的前提
- fail2ban 单独使用无效,必须确保 firewalld(或其他 banaction 对应的防火墙)处于 active 状态
- 三个服务都要设为开机自启:
systemctl enable sshd firewalld fail2ban - 定期验证防护是否真正生效:不能只看 fail2ban 的 Ban 计数,要确认防火墙规则确实存在且封禁后SSH日志中该IP记录消失