本页内容
- 工作原理;配置 Fail2ban(启用 jail、跟踪日志、故障排查、将自身 IP 地址加入白名单、手动封禁、手动解封、结论)
- 启用 jail
- 跟踪日志
- 故障排查
- 将自身 IP 地址加入白名单
- 手动封禁
- 手动解封
- 结论
Fail2ban 会监控日志文件中的登录失败记录,并暂时封禁频繁失败的来源 IP 地址,使其无法访问主机。这是一种防御密码猜测暴力破解攻击的手段。在暴露于互联网的主机上部署 Fail2ban 非常有用。
Debian 12 上的 Fail2ban 版本为 1.0.2。
root@posti:~# fail2ban-client version
1.0.2
要查看 Fail2ban 当前是否正在运行,可以使用 fail2ban-client 向服务器发送 ping 命令。如果 Fail2ban 正在运行,服务器会回复 "pong"。
root@posti:/etc/fail2ban# fail2ban-client ping
Server replied: pong
root@posti:/etc/fail2ban#
工作原理
Fail2ban 将过滤器(filter)、动作(action)和受监控的文件组合成一个 jail(监狱)。发行版自带多个 jail,但需要手动启用才能生效。filter 用于定义如何检测认证失败,action 定义了如何执行封禁和解封。
如果在 findtime 时间窗口内,来自同一 IP 地址的登录失败次数达到 maxretry,就会触发封禁。随后该 IP 会被封禁 bantime 秒。封禁持续 bantime 秒后自动解除,该 IP 可再次访问主机。Fail2ban 同时支持 IPv4 和 IPv6。
更多信息可阅读 /usr/share/doc/fail2ban/ 目录下的文件。
配置 Fail2ban
在 Debian GNU/Linux 系统上,Fail2ban 默认安装并启用了 sshd jail,且采用了合理的默认设置。这一配置位于 /etc/fail2ban/jail.d/defaults-debian.conf 文件中。这是默认情况下唯一生效的 jail,其他 jail 必须由系统管理员手动启用。
因此,如果你只需要监控 SSH 登录并封禁行为异常的入侵者,则无需进行额外配置。
遗憾的是,在 Debian 12 上,Fail2ban 可能无法使用默认设置正常工作。Debian 12 将 rsyslog 软件包标记为可选,这意味着它可能不会被安装,日志因此只会被收集到 journald 中 [wiki.debian.org/Rsyslog]。
在 ISPConfig 系统上,Fail2ban 可以正常工作,因为 ISPConfig 自动安装程序会安装 rsyslog,并且 ISPConfig Perfect Server 教程也要求安装 rsyslog。
安装了 rsyslog 后,日志文件会出现在 /var/log/ 目录下,因此 Fail2ban 的默认配置能够找到这些日志文件。如果未安装 rsyslog,则必须修改 Fail2ban 配置,使其从 systemd journal 读取日志。在 jail.local 的 [DEFAULT] 段中添加 backend = systemd,如下所示:
[DEFAULT] backend = systemd
启用 jail
文档建议将所有自定义修改放在 .local 文件中。这样可以避免在发行版提供的文件被维护者升级或修改时出现冲突 [可阅读文件 /usr/share/doc/fail2ban/README.Debian.gz]。
例如,要启用 pure-ftpd jail,只需在文件 /etc/fail2ban/jail.local 中添加以下内容(如果该文件不存在则先创建):
[pure-ftpd] enabled = true
方括号中的 jail 名称用于开启该 jail 的配置段。
修改完成后,使用以下命令强制重新读取配置文件:
systemctl reload fail2ban
此时该 jail 应该已经在运行,可以使用 fail2ban-client 进行验证:
root@posti:/etc/fail2ban# fail2ban-client status pure-ftpd Status for the jail: pure-ftpd |- Filter | |- Currently failed: 0 | |- Total failed: 106 | `- File list: /var/log/syslog `- Actions |- Currently banned: 0 |- Total banned: 4 `- Banned IP list: root@posti:/etc/fail2ban#
由于 jail.local 中只设置了该 jail 的 "enabled",其余设置均为发行版的默认配置。这些默认值通常都比较合理,因此一般无需进一步配置。如有需要,可在 jail.local 中该 jail 的段落添加覆盖 .conf 文件中设置的项。
以下示例修改了 pure-ftpd jail 的 findtime、maxretry 和 bantime:
[pure-ftpd] enabled = true findtime = 2h maxretry = 6 bantime = 1d
fail2ban-client 以秒为单位显示时间,但在配置文件中可以使用更直观的格式,例如使用 10h 代替 36000 秒。man jail.conf 中的 "TIME ABBREVIATION FORMAT" 章节介绍了这些易用的时间输入格式。
fail2ban-client 提供将易用时间格式转换为秒的选项。
# fail2ban-client --str2sec 1d3h7m
97620
跟踪日志
要确定应启用哪些 jail,需要跟踪主机上运行的服务所产生的日志。像 logwatch 或 pflogsumm 这样能够生成日志摘要的工具会很有帮助。直接阅读原始日志既耗时又枯燥。
查看主机上运行的服务是否已有对应的 jail 可用,可以阅读 jail.conf 文件。
当日志中出现值得关注或令人担忧的内容时,就该深入排查了。例如,pflogsumm 发送的邮件摘要中包含如下内容:
136 unknown[91.224.92.40]: SASL LOGIN authentication failed: UGFzc3... 136 hostname srv-91-224-92-40.serveroffer.net does not resolve to a... 123 unknown[193.32.162.23]: SASL LOGIN authentication failed: UGFzc... 123 hostname mail.whatami.co does not resolve to address 193.32.162.23
这表明 IP 91.224.92.40 在尝试登录邮件服务时失败了 136 次,另外还有一个类似的案例。Fail2ban 本应阻止如此多次的尝试。要查明为何没有生效,需要查看 Fail2ban 的日志。
root@posti:/etc/apt/apt.conf.d# grep 91.224.92.40 /var/log/fail2ban.log | head 2024-02-18 00:01:38,718 fail2ban.filter [996]: INFO [postfix-sasl] Found 91.224.92.40 - 2024-02-18 00:01:38 2024-02-18 00:11:50,261 fail2ban.filter [996]: INFO [postfix-sasl] Found 91.224.92.40 - 2024-02-18 00:11:50 2024-02-18 00:21:54,337 fail2ban.filter [996]: INFO [postfix-sasl] Found 91.224.92.40 - 2024-02-18 00:21:54 2024-02-18 00:32:14,232 fail2ban.filter [996]: INFO [postfix-sasl] Found 91.224.92.40 - 2024-02-18 00:32:14 2024-02-18 00:42:37,921 fail2ban.filter [996]: INFO [postfix-sasl] Found 91.224.92.40 - 2024-02-18 00:42:37 2024-02-18 00:53:06,796 fail2ban.filter [996]: INFO [postfix-sasl] Found 91.224.92.40 - 2024-02-18 00:53:06 2024-02-18 01:03:35,293 fail2ban.filter [996]: INFO [postfix-sasl] Found 91.224.92.40 - 2024-02-18 01:03:35 2024-02-18 01:14:03,765 fail2ban.filter [996]: INFO [postfix-sasl] Found 91.224.92.40 - 2024-02-18 01:14:03 2024-02-18 01:24:24,628 fail2ban.filter [996]: INFO [postfix-sasl] Found 91.224.92.40 - 2024-02-18 01:24:24 2024-02-18 01:34:43,876 fail2ban.filter [996]: INFO [postfix-sasl] Found 91.224.92.40 - 2024-02-18 01:34:43 root@posti:/etc/apt/apt.conf.d#
该 IP 大约每隔 10 分钟尝试连接一次,而 Fail2ban 的 postfix-sasl jail 确实检测到了它。
不妨先确认一下该 IP 是否可能属于本机的合法用户——也许只是其智能手机或其他设备仍在使用旧密码,并以固定间隔尝试连接。我使用 geoiplookup 来查看 IP 来自哪个国家。我的用户都来自本国,因此来自国外的用户往往是不怀好意的攻击者。geoiplookup 来自 Debian 软件包 geoip-database 和 geoip-bin。
$ geoiplookup 91.224.92.40
GeoIP Country Edition: LT, Lithuania
要查明为何该 IP 未被封禁,可查看该 jail 的 findtime:
root@posti:/etc/apt/apt.conf.d# fail2ban-client get postfix-sasl findtime 600 root@posti:/etc/apt/apt.conf.d#
我最近遇到了这类缓慢攻击:攻击者知道 findtime 为 10 分钟,于是以更长的间隔尝试登录,从而规避封禁。在本例中这一策略确实奏效了。为了让失败的登录真正触发封禁,可以增大该 jail 的 findtime,例如增大到 10 小时。在 jail.local 文件的 [postfix-sasl] 段中添加:
findtime = 10h
随后在执行 systemctl reload fail2ban 后,该 jail 的 findtime 就变长了:
root@posti:/etc/fail2ban# fail2ban-client get postfix-sasl findtime 36000 root@posti:/etc/fail2ban#
入侵者尝试入侵的另一种方式是坚持不懈。即使被封禁,他们也会等到封禁结束后继续猜测密码。虽然可以延长 bantime,但这会给合法用户带来麻烦——他们可能只是输错了密码,却要在 bantime 结束前都无法访问自己的账户。Fail2ban 提供了一个针对惯犯的 jail,名为 recidive。其工作原理是在 Fail2ban 日志中查找某个 IP 被反复封禁的记录,然后对其执行长时间封禁,例如一周。
以下摘录来自 logwatch 报告:
--------------------- pam_unix Begin ------------------------
sshd:
Authentication Failures:
unknown (212.70.149.150): 59 Time(s)
在日志文件中搜索该 IP 显示:
2024-02-21 03:42:39,121 fail2ban.filter [895]: INFO [sshd] Found 212.70.149.150 - 2024-02-21 03:42:38 2024-02-21 03:42:39,508 fail2ban.actions [895]: NOTICE [sshd] Ban 212.70.149.150 2024-02-21 03:52:38,386 fail2ban.actions [895]: NOTICE [sshd] Unban 212.70.149.150 2024-02-21 03:54:33,560 fail2ban.filter [895]: INFO [sshd] Found 212.70.149.150 - 2024-02-21 03:54:33 2024-02-21 03:54:35,364 fail2ban.filter [895]: INFO [sshd] Found 212.70.149.150 - 2024-02-21 03:54:35 2024-02-21 04:00:37,017 fail2ban.filter [895]: INFO [sshd] Found 212.70.149.150 - 2024-02-21 04:00:36 2024-02-21 04:00:39,021 fail2ban.filter [895]: INFO [sshd] Found 212.70.149.150 - 2024-02-21 04:00:38 2024-02-21 04:06:43,036 fail2ban.filter [895]: INFO [sshd] Found 212.70.149.150 - 2024-02-21 04:06:42 2024-02-21 04:06:45,039 fail2ban.filter [895]: INFO [sshd] Found 212.70.149.150 - 2024-02-21 04:06:44 2024-02-21 04:06:45,426 fail2ban.actions [895]: NOTICE [sshd] Ban 212.70.149.150 2024-02-21 04:16:44,302 fail2ban.actions [895]: NOTICE [sshd] Unban 212.70.149.150 2024-02-21 04:19:04,868 fail2ban.filter [895]: INFO [sshd] Found 212.70.149.150 - 2024-02-21 04:19:04
Fail2ban 按预期工作,发现了错误的登录尝试并发出了 10 分钟的封禁。在封禁期间,攻击者无法访问本机,但封禁解除后又会卷土重来。这看起来是一次严重的入侵尝试。解决方法是启用 recidive jail,并将 maxretry 设低、bantime 设长。
我倾向于使用较短的初始封禁时间,比如 10 分钟。如果真实用户被封禁,只需等待这段时间,希望他能借此找出正确密码再试。那些在同一天内再次被封禁的用户,会被封禁一周。recidive jail 的默认值可在 jail.conf 文件中找到,其中 bantime 为 1 周、findtime 为 1 天,我觉得基本合理。但我会把 maxretry 设为 2,以便更快地封禁攻击者。我在 jail.local 中添加如下内容:
[recidive] enabled = true maxretry = 2
在我看来,超过一周的封禁并不值得。最终,旧的 IP 地址会在各处被封禁或列入黑名单,攻击者便会更换新的 IP。而旧的 IP 会被分配给某个无辜的新互联网用户,不该因为该 IP 前任持有者的恶行而受到惩罚。
故障排查
在操作系统启动或 Fail2ban 重启后,状态会被恢复,因此封禁会持续到 bantime 结束。正因如此,测试和故障排查过程中可能会涉及重启操作。
要测试配置,可以使用 test 选项:
fail2ban-server --test
要查看某个 IP 是否被封禁,较新版本的 Fail2ban 可以执行
# fail2ban-client banned 43.131.9.186
[['recidive']]
该命令会列出当前封禁了指定 IP 的 jail 列表。
较旧版本的 Fail2ban 没有该命令。可以逐个 jail 进行测试,方法如下:
# fail2ban-client status recidive | tr " " "\n" | grep 43.163.219.232
43.163.219.232
如果输出中显示了该 IP,说明它位于被封禁 IP 列表中。其中 tr 命令的作用是将被封禁 IP 列表(它是一整行)拆分为每行一个 IP。
要查看某个 IP 的详细情况,可在 fail2ban.log 中查找:
root@posti:/etc/mysql# grep 43.131.9.186 /var/log/fail2ban.log | cut --characters=-80 2024-03-06 09:00:40,295 fail2ban.filter [3574846]: INFO [sshd] Found 2024-03-06 09:02:53,954 fail2ban.filter [3574846]: INFO [sshd] Found 2024-03-06 09:02:55,958 fail2ban.filter [3574846]: INFO [sshd] Found 2024-03-06 09:04:34,193 fail2ban.filter [3574846]: INFO [sshd] Found 2024-03-06 09:04:36,195 fail2ban.filter [3574846]: INFO [sshd] Found 2024-03-06 09:04:36,388 fail2ban.actions [3574846]: NOTICE [sshd] Ban 43 2024-03-06 09:04:36,626 fail2ban.filter [3574846]: INFO [recidive] Fo 2024-03-06 09:14:35,180 fail2ban.actions [3574846]: NOTICE [sshd] Unban 2024-03-06 09:15:10,073 fail2ban.filter [3574846]: INFO [sshd] Found 2024-03-06 09:16:55,919 fail2ban.filter [3574846]: INFO [sshd] Found 2024-03-06 09:16:58,522 fail2ban.filter [3574846]: INFO [sshd] Found 2024-03-06 09:18:44,972 fail2ban.filter [3574846]: INFO [sshd] Found 2024-03-06 09:20:30,018 fail2ban.filter [3574846]: INFO [sshd] Found 2024-03-06 09:20:30,499 fail2ban.actions [3574846]: NOTICE [sshd] Ban 43 2024-03-06 09:20:30,620 fail2ban.filter [3574846]: INFO [recidive] Fo 2024-03-06 09:20:30,899 fail2ban.actions [3574846]: NOTICE [recidive] Ba 2024-03-06 09:20:32,021 fail2ban.filter [3574846]: INFO [sshd] Found 2024-03-06 09:30:29,289 fail2ban.actions [3574846]: NOTICE [sshd] Unban
以详细模式转储 Fail2ban 配置,可以查看各项设置用于排查:
# fail2ban-client -vvv -d
将自身 IP 地址加入白名单
也许你自己的主机被封禁了,或者你希望确保某些外部主机即使行为异常也永远不会被封禁。这些 IP 地址可以加入白名单。默认情况下没有任何地址被加入白名单,你可以通过以下命令验证:
root@posti:~# fail2ban-client get sshd ignoreip
No IP address/network is ignored
root@posti:~
ignoreip 设置可以放在每个 jail 的段落中,但由于该设置应作用于所有 jail,因此最好将其放在 [DEFAULT] 段中。最理想的做法是将 ignore 设置为内部子网,这样你所有的主机都不会被封禁。以下来自 jail.local 的开头部分:
[DEFAULT] ignoreip = 92.237.123.96/27
[DEFAULT] 段还可以包含影响所有 jail 的其他设置。例如,可以在其中添加 findtime = 10h。
手动封禁
要测试封禁时会发生什么,可以手动设置封禁。建议先使用一个 bantime 较短的 jail 进行测试,这样即使误封了自己,也能在一段时间后恢复。例如:
# fail2ban-client set sshd banip 8.8.4.4</>
如果某个 IP 行为异常,但你无法让 Fail2ban 检测到它并自动封禁,则可以在 recidive jail 中手动封禁该 IP,从而将其清除一周。
# fail2ban-client set recidive banip 8.8.4.4
使用 CIDR 表示法可以对整个子网进行封禁:
fail2ban-client set recidive banip 5.188.87.0/24
手动解封
解除封禁是可行的,但需要考虑:如果不良行为持续,该 IP 很可能会被再次封禁。因此你应该先查明发生了什么(例如通过阅读日志),并解决导致异常行为的问题。
# fail2ban-client set recidive unbanip 8.8.4.4
该 IP 可能在多个 jail 中被封禁。要解除该 IP 在所有 jail 中的封禁,可使用
# fail2ban-client unban 8.8.4.4
不过我很少需要这样做。我的 bantime 为 10 分钟(recidive jail 除外,其为 1 周),因此我只需从 recidive jail 解除封禁,其他 jail 的封禁早已过期。如果你没有使用 recidive jail,IP 可能会同时在多个 jail 中被封禁,此时该命令就很有用。
要解除所有 jail 中所有 IP 的封禁,可执行
fail2ban-client unban --all
结论
Fail2ban 增加了密码猜测的难度,但并不能完全阻止攻击者尝试访问主机。对于 SSH,强制使用 SSH 密钥可通过禁止密码登录来提供更强的安全保护。对于其他服务,多因素认证可在仅知道密码的情况下阻止登录。