fail2ban 在哪里开始不够用

fail2ban 是好工具,也是正确的第一答案。本文说清楚它究竟在哪里到头、如何把它推得更远,以及它在任何配置下都做不到的事。

阅读约 8 分钟

先把功劳说在前面

fail2ban 在每个发行版的仓库里,一条命令即可安装,当晚就能封禁真实的攻击者。如果您有一台没人看管的暴露服务器,装上 fail2ban 严格优于您现在的处境,下面的内容没有一句在反驳这一点。

本文讲的是「今晚能封住真实攻击者」和「一年后在整个机器群上依然正确」之间的差距,因为意外都住在这段差距里,而它很少被写下来。

下面这些边界都不是 bug,而是 fail2ban 本质的必然结果:一个诞生于单台服务器、单个攻击者时代的日志解析守护进程。

边界一:它封的是地址,不是网段

这是最大的一条。攻击流量来自托管服务商,那里一个运营商持有整块地址。封掉 203.0.113.47,僵尸网络一小时内挪到 .48,而在那个也被封掉之前,您又要承受完整的一轮尝试。放到一个 /24 上,这就是您所配置阈值的 256 轮。

您可以用自定义 action 把每次封禁扩展到它所在的 /24 来近似解决,但这样一来您就要在 shell 里维护 CIDR 运算,一旦算错,封掉的就是您需要的东西。这个工具压根没有「网段」这个一等对象的概念。

可测量的效果是:在持续遭受攻击的服务器上,按网段封禁的防御会看到尝试数断崖式下跌,而按地址封禁的则停在轮换速率所决定的平台上。

边界二:封禁会过期,状态挺不过重建

默认的 bantime 以分钟计。这在可能误伤真实用户的共享主机上是合理默认值,在面向公网的服务器上则是错的:同一个僵尸网络今晚回来,从头再来。

您可以把 bantime 设为 -1 实现永久封禁,也应该这么做——但第二个问题随之出现。封禁列表存在 fail2ban 自己的数据库和运行中的防火墙里;重建机器、从镜像恢复或迁移到新主机,服务器学到的一切就都没了。

还有一个三阶版本:一台跑了两年的服务器,会积累出一个含数万条目的防火墙集合,而从来没有人审视过最老的那些是否还值得比对。

边界三:每台服务器都在孤军学习

这一条是结构性的,任何配置都修不好。您的每一台服务器都独立地发现每一个攻击者,而这份发现的代价就是您设定的阈值——五次、十次,无论多少。

十台服务器、同一个攻击者十遍、阈值被承受十遍。而其中每一次尝试都是一次真实的 sshd 分叉、一行真实的日志,以及一次「这一轮里某个复用密码恰好过了」的真实机会。

fail2ban 没有任何机制能让一台服务器的知识传到另一台。有可以订阅的社区封禁列表,它们有帮助,但内容通用且滞后数小时到数天;没有任何东西会告诉您:此刻正在敲三号服务器的那个地址,就是今早敲一号服务器的那个。

边界四:它静默失效

这条边界是真正让人丢掉服务器的那一条,也是最少被关注的一条。

fail2ban 依赖用正则表达式匹配日志行。发行版升级改变了某条 sshd 消息的格式;过滤器不再匹配;jail 仍然「在运行」并报告零封禁,看起来和太平的一周一模一样。软件包更新曾经把 jail.local 重置过。systemd 后端变更会让日志无人读取。服务在重启后没有起来。

在上述每一种情况下,您大概率拥有的那种监控——服务在跑吗?——都会回答「在」。真正能抓住问题的问题是:「它最近封过谁吗?这个数字看起来像我在日志里看到的攻击量吗?」——而几乎没有人问这个。

把 fail2ban 推得更远

如果您想继续用它——对小规模环境而言这是正当选择——下面是最要紧的改动,大致按优先级排列:

  • 设置 bantime = -1 并调大 findtime,这样慢速攻击者也会被抓到。上面再叠一个 recidive jail,让惯犯被升级处理。
  • 添加自定义 action 把封禁扩展到 /24,但先拿自己的地址段仔细验证运算是否正确。
  • 用标记为 persistent 的 nftables 集合让封禁挺过重启,或者在启动时从数据库恢复。
  • 监控封禁数量,而不是服务状态。当认证日志有失败而封禁数为零时告警。
  • 在做其他任何事之前先把您的管理地址写进 ignoreip,并从第二条连接确认您写对了。

托管代理多出什么

两样东西,而第二样在任何配置下都无法独自构建。

第一是运维底座:把子网封禁作为一等概念、封禁永久且开机恢复、从 sshd 配置中读出真实的 SSH 端口而不是想当然、安装时就把您的地址加入白名单,以及一个能回答「这东西还在工作吗」的控制台——这恰恰是真正会咬人的失效方式。

第二是共享信誉。每台受保护的服务器都会为一个公共数据库贡献数据,因此昨天攻击过别人的地址在到达您这里时就已被封禁,您永远不必承受它最初的 N 次尝试。单台主机上的日志解析器只能从针对这台主机的攻击中学习。

SSH Protector 在代理本地做判断,所以保护不依赖云端可达:连接中断时,本地策略照常运行。一台服务器永久免费,足以让它和 fail2ban 并行跑一周,比较各自都抓到了什么。

FAQ

现在还值得用 fail2ban 吗?
值得,作为基础层。它免费、在所有仓库里,而且在一台没有其他东西看管的服务器上,安装当天就能封禁真实攻击者。诚实的保留意见是:面对轮换网段的僵尸网络只封单个地址;封禁默认会过期;主机之间没有共享知识;以及静默的失效方式。
如何让 fail2ban 的封禁永久生效?
在相应 jail 中设置 bantime = -1。请注意,封禁列表此时只存在于 fail2ban 的数据库和运行中的防火墙里,因此重建或镜像恢复会丢失服务器学到的一切,而这个集合会在无人审视的情况下不断增长。同时也要让防火墙集合挺过重启,否则每次重启封禁都会丢失。
fail2ban 能封禁整个子网吗?
原生不能。它封的是出现在日志行里的那个地址。您可以写一个自定义 action,把每次封禁扩展到包含它的 /24,但这样就得自己维护 CIDR 运算,一旦出错就会封掉您需要的网段。这个工具里并不存在「网段」这个一等概念。
怎么确认 fail2ban 确实在工作?
运行 fail2ban-client status sshd,看被封数量,而不只是看服务是否处于活动状态。jail 在运行却一个都没封,同时认证日志里有失败记录,就意味着过滤器已经不再匹配——通常是发行版升级改变了某条 sshd 消息格式所致。请监控封禁数量,而不是进程。

并行跑一周看看

子网封禁、默认永久、共享信誉,以及一个能看出它是否活着的界面。一台服务器永久免费,无需信用卡。