iptables的recent模块需严格按--rcheck→--update→--set顺序配置,否则无法闭环实现ssh暴力防护;验证需检查/proc/net/xt_recent/ssh_attack文件内容,封禁参数须结合业务场景调整。

能直接用,但规则顺序和参数组合错一点就失效——recent模块不报错,只默默不工作。
为什么SSH暴力扫描必须用--rcheck放最前
recent模块不会自动“记住”IP然后拉黑,它靠三条规则的协作完成闭环:先查是否已拉黑、再更新计时、最后登记新连接。如果把--set写在最前面,每个新连接都会被立刻记入,--rcheck永远查不到“已命中”,封禁逻辑就断了。
-
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --name ssh_attack --rcheck --seconds 300 --hitcount 1 -j DROP(第一优先级:已进黑名单的,直接丢) -
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --name ssh_attack --update --seconds 300 -j ACCEPT(命中即刷新倒计时,避免误踢) -
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --name ssh_attack --set -j ACCEPT(仅对未拉黑的新连接登记)
顺序颠倒或漏掉--update,会导致IP一旦触发就永久滞留在列表里(因为时间戳不再刷新),或者根本无法触发封禁。
怎么验证recent是否真在跟踪IP
别信日志,直接看内核内存里的实时记录。模块加载后,/proc/net/xt_recent/下会生成对应--name的文件:
cat /proc/net/xt_recent/ssh_attack
输出类似src=192.168.1.100 ttl: 297才表示该IP已被跟踪且剩余封禁时间还有297秒。如果返回空或报No such file or directory,说明xt_recent没加载:
- 运行
modprobe xt_recent手动加载 - 检查
/proc/net/xt_recent/是否存在目录 - 确认
iptables版本支持(≥1.4.21)
封禁时长和命中次数怎么设才不误伤
300秒+1次是底线,但实际要结合业务场景调:
- 运维人员频繁切换网络(如4G/WiFi),建议
--seconds 600 --hitcount 3,容忍短时重连 - SSH端口非22(比如改到2222),需同步改
--dport,否则规则完全不匹配 - 若服务器启用了
UseDNS no和MaxStartups 10:30:60,可适当收紧--hitcount到2,因真实用户极少连续输错3次密码 - 注意
--hitcount 1不是“试一次就封”,而是指在--seconds窗口内第1次命中即触发——所以--seconds 300 --hitcount 1等效于“5分钟内任一失败连接都拉黑”
为什么封禁后SSH还是能连上
常见三个漏点:
- 规则插在
INPUT链末尾,但前面已有-j ACCEPT放行所有22端口流量,导致封禁规则根本没机会执行 - 没加
-m state --state NEW,把已建立的连接(如keepalive)也纳入recent统计,造成合法会话被意外中断 - 用
-j DROP但没配LOG规则,无法确认是封禁生效还是网络层其他问题(比如云厂商安全组先拦截了)
补一条调试日志能快速定位:iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --name ssh_attack --rcheck --seconds 300 --hitcount 1 -j LOG --log-prefix "SSH-BLACKLIST: "。日志出现在/var/log/messages或journalctl -k里,看到前缀就说明规则已触达。
recent列表重启即清空,不持久化;真正要长期封禁得接fail2ban或ipset,但那已是另一层逻辑了。











