为什么 fail2ban 封了 IP,SSH 日志还在刷失败登录?

过公网服务器的,大概率都见过这种日志——/var/log/auth.log(Debian/Ubuntu)或者 /var/log/secure(CentOS/RHEL)里,一天到晚刷着这样的行:

Failed password for root from 203.0.113.7 port 43210 ssh2

一天几百上千条,IP 换着来,root、admin、test 挨个试。很多人第一反应是装 fail2ban 自动封 IP。装完问题来了:fail2ban-client status 明明显示 ban 了几个 IP,可 SSH 日志里失败登录还是一行接一行往外冒。今天就把这件事从头捋清楚。

它凭什么能自动封 IP

fail2ban 的活儿不复杂,就三件套:

  • 盯日志:一个叫 backend 的东西负责读日志源。老版本读日志文件,0.10 之后默认 backend = auto,在 systemd 系统上会优先去读 journald 日志,而不是直接啃 /var/log/auth.log 这个文件。
  • 对正则:每个"监狱"(jail)配一套 filter 规则,其实就是正则表达式,负责从日志里认出"这是一次失败登录"。
  • 动真格:认出来之后触发 action。默认的 action 是往 iptables 里加一条 DROP 规则,把这个 IP 封掉。

一句话:读日志、认攻击、封 IP,循环往复。听起来简单,但三个环节任何一个没对上,就会出现"看着在封、其实没封住"的怪象。

十分钟接上 fail2ban

先说安装。Debian/Ubuntu 一条 apt install fail2ban;CentOS/RHEL 需要先启用 EPEL 源,再 yum install fail2ban。

装完别急着改 /etc/fail2ban/jail.conf——这是默认配置,软件一升级就会被覆盖。正确姿势是复制一份成 jail.local,你的改动都写在这里,它会覆盖同名的默认值:

cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

然后在 jail.local 里写这么几行:

[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24
bantime  = 1h
findtime = 10m
maxretry = 3

[sshd]
enabled = true

逐行解释:

  • ignoreip:白名单,这些 IP/网段永远不会被封。千万别漏了你自己办公用的固定网段,否则哪天手滑输错几次密码,就把自己关门外了。
  • bantime:封多久,1h 是一小时。
  • findtime:统计窗口,10m 是十分钟。
  • maxretry:窗口内失败几次就封,3 就是十分钟里错三次就拉黑。
  • [sshd] 下面的 enabled = true:这条最关键,sshd 这个 jail 默认是关着的,不显式打开,装了半天啥也不会发生。

这几个参数的默认值在 jail.conf 的 [DEFAULT] 段里都有,不同发行版打包略有出入,动手前翻一眼自己机器上的实际数值最稳妥。

改完重启:

systemctl restart fail2ban

老 CentOS 6 用的是 service fail2ban restart。

确认它真的在封人

重启之后别凭感觉,用命令确认三件事。

第一件,看有没有跑起来、管着哪些 jail:

fail2ban-client status

会列出 sshd 等所有 jail。再看 sshd 这个 jail 的具体情况:

fail2ban-client status sshd

输出里有两行值得盯:Currently failed(当前失败次数)和 Currently banned(当前封禁的 IP 列表)。后者有内容,才说明它真的在动手。

第二件,看 iptables 里有没有对应的封禁链:

iptables -L -n | grep f2b

能看到 f2b-sshd 这样的链,说明 action 真正落到了内核防火墙,而不只是记在 fail2ban 自己的账本里。

第三件,手动解封验证一下链路是通的:

fail2ban-client set sshd unbanip 203.0.113.7

如果这条能正常解封,说明整个"封/解"闭环是通的。

封了还在刷,是哪儿没对

回到开头那个怪象:明明 ban 了 IP,日志还在刷。大概率是下面几个坑之一。

坑一:ignoreip 把攻击源放进了白名单

如果爆破来自你自己的网段,又恰好被写进了 ignoreip,fail2ban 会老老实实不封它——但日志照刷不误。看看那些失败登录的源 IP,是不是都在白名单里。

坑二:action 没真正落到 iptables

有些最小化安装或者自己精简过的配置,[DEFAULT] 里的 action 是空的。fail2ban 内部确实记录了"该封这个 IP",但没有任何 action 去执行,等于记了账没动手。判别方法就是上面第二条:iptables -L -n | grep f2b 看不到链,八成就是 action 没配。

坑三:backend 读的不是你以为的那个日志

0.10 之后默认 backend = auto,在 systemd 系统上走的是 journald。你要是还盯着 /var/log/auth.log 看有没有"被封"的记录,或者反过来改了 auth.log 却不见 fail2ban 反应,多半是 backend 的日志源和你想的不一致。用 journalctl -u ssh 看看服务侧的真实日志。

坑四:封禁本来就有延迟和窗口

maxretry = 3、findtime = 10m 的意思是十分钟内错够三次才封。第一次、第二次失败登录,日志照刷,因为它还没到触发线。刚解封的 IP 再扫,也是从零开始计数。别指望一次失败就瞬间拉黑。

坑五:僵尸网络换着 IP 来

对最顽固的爆破,封 IP 治标不治本——对方用的是分布式肉鸡池,封了这个下个又冒出来。fail2ban 挡得住扫一波就走的路人,挡不住盯上你的专业爬虫。这时候该上根本手段了:

# /etc/ssh/sshd_config
PasswordAuthentication no
PermitRootLogin prohibit-password

关掉密码登录、禁掉 root 密码登录,改完 systemctl restart sshd。这里注意一点:PermitRootLogin 在 OpenSSH 7.0 之前写作 without-password,7.0 之后推荐用 prohibit-password,含义都是"只允许密钥登录、不允许密码"。

攻击者连密码入口都没了,fail2ban 就从"主力防线"变成"补充防线",日志自然清净。


版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。

评论