使用Fail2ban防暴力破解的实战指南

描述

 

公网服务器只要开放 SSH,认证日志里通常很快就会出现针对 rootadmintest 等用户名的自动化尝试。单次失败不一定危险,真正需要处理的是同一来源在短时间内持续试探密码、用户名或 Web 登录接口。Fail2ban 的作用,就是从可信日志中识别这类重复失败,并调用本机防火墙动作临时封禁来源地址。

它适合做主机侧的第二道防线,但不能替代 SSH 密钥认证、MFA、来源网络限制、漏洞修复和集中式边界防护。攻击者可以轮换 IP,日志也可能缺失或被代理层改写;如果登录接口本身存在绕过或凭证已经泄露,单靠封禁失败次数并不能解决问题。

本文以常见的 Fail2ban 0.11/1.x 包为参考。不同 Linux 发行版、Fail2ban 打包方式和防火墙后端可能提供不同 action 文件,实际部署前必须以本机 fail2ban-client -V、配置测试结果和 /etc/fail2ban/action.d/ 内容为准。

文中占位符说明:

  • <管理网段> :允许运维登录的可信 CIDR,例如企业 VPN 出口网段,不能照抄示例地址。
  • <测试IP> :专门用于封禁验证、且不会中断当前管理会话的地址。
  • :sshd 实际监听端口,例如 22;修改端口不能替代认证加固。
  • :系统中的 systemd 单元,常见为 ssh.service 或 sshd.service
  • <日志文件> :目标服务真实写入的日志路径。
  • <备份目录> :受权限保护、空间充足的配置备份目录。
  • :启用的 jail 名称,例如 sshd

一、Fail2ban 到底做了什么

Fail2ban 的处理链路可以拆成五个部分:

  1. 日志来源 :文本日志、systemd journal 或其他受支持后端。
  2. filter :用 failregex 从失败日志中提取来源地址,使用  作为 IP/主机匹配标记。
  3. jail :把 filter、日志来源、时间窗口、重试次数和 action 组合起来。
  4. action :通过 nftables、iptables、firewalld 或其他机制执行 ban/unban。
  5. 状态数据库 :记录封禁信息,使服务重启后能够按配置处理既有状态。

最常见的三个时间参数是:

  • findtime :统计失败次数的时间窗口。
  • maxretry :窗口内达到多少次匹配后触发封禁。
  • bantime :封禁持续时间。

例如 findtime = 10mmaxretry = 5bantime = 1h,表示同一来源在 10 分钟统计窗口内达到 5 次匹配后,封禁 1 小时。这里的“失败次数”不是 Fail2ban 主动尝试登录得出的,而是 filter 对日志行的匹配结果。如果日志格式变了、日志没写来源 IP,或者正则过宽,封禁判断就会失效或误伤。

因此 Fail2ban 部署的核心并不是“把服务启动起来”,而是证明四件事:日志确实存在、filter 只匹配真实失败、action 与本机防火墙兼容、运维入口不会被误封。

二、先建立现状证据,不要直接安装启用

1. 确认 SSH 暴露面

检查 sshd 实际监听地址和端口:


			   bashsudo ss -lntp | grep -E 'sshd|:22([[]]|$)' sudo sshd -T | grep -E '^(port|listenaddress|passwordauthentication|permitrootlogin|pubkeyauthentication) ' 

sshd -T 输出的是展开后的有效配置,通常比只搜索 /etc/ssh/sshd_config 更可靠,因为后者可能包含 Include 和 Match 段。若命令提示权限或主机密钥问题,应在 root 权限和正确环境中执行,不要据此猜测生效配置。

示例输出:


			   textport 22 passwordauthentication no permitrootlogin prohibit-password pubkeyauthentication yes 

判断时重点关注:

  • 是否仍允许密码认证。
  • root 是否可以直接登录。
  • 监听地址是否为所有网卡。
  • 云安全组、边界防火墙或 NAT 是否把端口暴露到公网。

即使 PasswordAuthentication no,日志里仍可能出现用户名枚举、密钥尝试或握手滥用。Fail2ban 可以减少重复来源,但更优先的措施仍是限制来源网段和关闭不需要的认证方式。

2. 找到真实认证日志

Debian/Ubuntu 常把 SSH 认证写入 /var/log/auth.log,RHEL 系常见 /var/log/secure;启用 journald 后也可以直接读取服务单元。不能只凭发行版名称假定路径,应现场确认:


			   bashsudo journalctl -u  --since '30 minutes ago' --no-pager sudo test -r /var/log/auth.log && sudo tail -n 50 /var/log/auth.log sudo test -r /var/log/secure && sudo tail -n 50 /var/log/secure 

命令输出可能含用户名、来源 IP 和主机信息,提交工单或共享截图前应脱敏。需要区分真正的认证失败与正常噪声,例如连接在认证前断开、健康检查探测、管理员输错一次密码。没有日志证据时,不应先写自定义正则。

3. 查看当前防火墙体系

Fail2ban 的 action 必须与主机实际防火墙一致:


			   bashsudo nft list ruleset sudo iptables-save sudo firewall-cmd --state 

某些命令可能因组件未安装而失败,这本身就是判断依据。不要同时启用多个相互不清楚的防火墙管理层。比如系统由 firewalld 管理 nftables 时,直接手写 nft 规则和再让 Fail2ban 管理链,可能导致重载后规则丢失或顺序变化。

将当前规则保存为只读基线:


			   bash#!/usr/bin/env bash set -euo pipefail BACKUP_DIR="<备份目录>" STAMP="$(date +%Y%m%d-%H%M%S)" sudo install -d -m 0700 "${BACKUP_DIR}" if command -v nft >/dev/null 2>&1; then   sudo nft list ruleset      | sudo tee "${BACKUP_DIR}/nft-rules-${STAMP}.txt" >/dev/null fi if command -v iptables-save >/dev/null 2>&1; then   sudo iptables-save      | sudo tee "${BACKUP_DIR}/iptables-rules-${STAMP}.txt" >/dev/null fi 

这些文件用于差异核对,不应不加分析地直接回灌整个生产防火墙。全量恢复规则可能覆盖同时发生的合法变更;真正恢复前必须由防火墙责任人审核。

三、安装 Fail2ban

Debian/Ubuntu


			   bashsudo apt-get update sudo apt-get install fail2ban 

RHEL 系发行版

Fail2ban 常来自 EPEL 等额外仓库。先按照企业镜像源规范启用适配当前系统版本的仓库,再安装:


			   bashsudo dnf install fail2ban 

不要为了安装单个包临时接入未经审核的公网软件源。安装后先确认版本和文件,不急着启用服务:


			   bashfail2ban-client -V rpm -ql fail2ban 2>/dev/null | head -n 30 || true dpkg -L fail2ban 2>/dev/null | head -n 30 || true 

再检查系统是否已经存在旧配置:


			   bashsudo find /etc/fail2ban -maxdepth 2 -type f -print | sort sudo systemctl status fail2ban --no-pager 

如果服务此前已运行,当前任务就不是“首次安装”,而是变更已有安全策略。此时必须先导出有效配置和现有 ban 状态,不能覆盖原文件。

四、配置原则:只写 local 覆盖,不改发行版默认文件

jail.conf 和 filter.d/*.conf 可能在升级软件包时变化。生产配置应写入 jail.localjail.d/*.local 或对应的本地 filter 文件,并通过版本管理保留变更记录。

先备份现有配置:


			   bash#!/usr/bin/env bash set -euo pipefail BACKUP_DIR="<备份目录>" STAMP="$(date +%Y%m%d-%H%M%S)" sudo install -d -m 0700 "${BACKUP_DIR}" sudo tar -C /etc -czf "${BACKUP_DIR}/fail2ban-${STAMP}.tar.gz" fail2ban sudo sha256sum "${BACKUP_DIR}/fail2ban-${STAMP}.tar.gz"    | sudo tee "${BACKUP_DIR}/fail2ban-${STAMP}.tar.gz.sha256" >/dev/null 

备份需要确认能读取、校验和匹配,并按企业要求复制到独立位置。把备份留在同一台可能被入侵的主机上,不构成完整灾备。

五、为 SSH 配置一个最小可用 jail

systemd 环境建议优先使用 journal 后端,避免日志路径在不同发行版间不一致。创建 /etc/fail2ban/jail.d/sshd.local


			   ini[sshd] enabled = true backend = systemd port =  filter = sshd findtime = 10m maxretry = 5 bantime = 1h ignoreip = 127.0.0.1/8 ::1 <管理网段> 

关键点如下:

  • 使用 backend = systemd 时通常不再填写 logpath,日志匹配由 filter 的 journal 条件和系统日志决定。
  • port  必须与 sshd 实际监听端口一致。也可以使用服务名 ssh,但自定义端口应直接写数字。
  • ignoreip  只加入经过确认的固定运维出口、堡垒机和本机地址。不要把整个办公网、云 VPC 或所有私网段无条件放行。
  • maxretry  过小会误伤人工操作,过大则削弱效果。需要根据 MFA、密码策略、用户规模和历史日志基线调整。
  • bantime  不是越长越好。动态公网 IP 可能很快重新分配给正常用户,永久封禁会积累误伤。

如果系统使用文本认证日志,可改为:


			   ini[sshd] enabled = true backend = auto port =  filter = sshd logpath = <日志文件> findtime = 10m maxretry = 5 bantime = 1h ignoreip = 127.0.0.1/8 ::1 <管理网段> 

<日志文件> 应替换为已经确认存在且由 root 控制的真实路径,例如某些系统上的 /var/log/auth.log。不要让非特权业务用户能够写入 Fail2ban 信任的日志,否则攻击者可能伪造日志触发对任意 IP 的封禁。

六、先测试配置和正则,再启动服务

1. 解析全部配置


			   bashsudo fail2ban-client -t sudo fail2ban-client -d > /tmp/fail2ban-effective-config.txt 

-t 用于测试配置;-d 会输出解析后的配置,便于确认最终采用的 backend、port、logpath 和 action。输出可能很长,应重点搜索目标 jail:


			   bashgrep -nE "['(add|set)', ''" /tmp/fail2ban-effective-config.txt 

如果版本不支持某个选项,必须根据本机 fail2ban-client --help 和包内示例调整,不要带着语法错误强行重启服务。

2. 用历史日志验证 filter

文本日志可直接测试:


			   bashsudo fail2ban-regex    <日志文件>    /etc/fail2ban/filter.d/sshd.conf    --print-all-matched 

systemd journal 可以先导出一个受控时间窗口,再通过标准输入测试:


			   bashsudo journalctl -u     --since '24 hours ago'    --no-pager    | sudo fail2ban-regex - /etc/fail2ban/filter.d/sshd.conf 

示例输出:


			   textFailregex: 87 total Ignoreregex: 0 total Lines: 1250 lines, 0 ignored, 87 matched, 1163 missed 

这只是示例输出,实际数量必须来自目标主机。判断不能只看 matched 大于 0,还要抽查匹配行:

  • 是否都是认证失败,而不是成功登录或服务启动日志。
  •  提取到的是实际来源地址。
  • 没有把 sshd 监听地址、代理地址或日志中的其他 IP 当成攻击源。
  • 多行日志、IPv6 地址和不同认证方式是否覆盖。

不要通过真实爆破生产 SSH 来“测试效果”。用历史日志和 fail2ban-regex 足以验证 filter;action 另用隔离测试 IP 验证。

七、灰度启用:防止把自己锁在服务器外

启动 Fail2ban 会创建或修改防火墙规则,可能影响远程连接。执行前必须满足:

  • 已有第二条管理通道,例如云控制台、带外管理、串口或另一条堡垒机链路。
  • 当前管理出口已核对并加入精确 ignoreip
  • 已备份 Fail2ban 配置和防火墙规则基线。
  • fail2ban-client -t  通过。
  • 已在同版本测试机验证 jail 与 action。
  • 维护窗口和回滚责任人已确认。

先启动但不要断开当前 SSH 会话:


			   bashsudo systemctl enable --now fail2ban sudo systemctl status fail2ban --no-pager sudo journalctl -u fail2ban --since '10 minutes ago' --no-pager 

从第二个已验证的管理终端重新登录,确认认证正常后,再查看 jail:


			   bashsudo fail2ban-client status sudo fail2ban-client status sshd 

示例输出:


			   textStatus for the jail: sshd |- Filter |  |- Currently failed: 1 |  `- Total failed: 12 `- Actions    |- Currently banned: 2    |- Total banned: 3    `- Banned IP list: 198.51.100.20 2001:20 

示例地址来自文档保留网段,不能作为真实封禁列表。需要确认 jail 已启动、失败计数会更新、action 没有报错,同时运维来源没有进入 banned 列表。

八、验证防火墙 action,而不是只看客户端状态

Fail2ban 状态显示 banned,不一定代表数据包确实被防火墙丢弃。应检查对应后端规则:


			   bashsudo nft list ruleset | grep -i -A 20 -B 5 f2b sudo iptables-save | grep -i f2b sudo firewall-cmd --direct --get-all-rules 2>/dev/null | grep -i f2b || true 

具体链名和 set 名取决于 action,不要依赖固定名称写清理脚本。

在具备隔离测试源且不会影响管理连接时,可以由授权人员执行一次人工 ban/unban:


			   bashsudo fail2ban-client set sshd banip <测试IP> sudo fail2ban-client status sshd sudo fail2ban-client set sshd unbanip <测试IP> 

<测试IP> 绝不能是当前 SSH 客户端、堡垒机、负载均衡健康检查或共享 NAT 出口。执行前先记录测试 IP 的责任人和验证时间,执行后必须确认已解除封禁。

九、误封后的处理与回滚

1. 只解除一个 IP

如果通过控制台确认某个合法来源被封禁,优先做最小范围处理:


			   bashsudo fail2ban-client set  unbanip <被误封IP> sudo fail2ban-client status  

随后从日志确认它为什么达到阈值,再决定是否调整认证客户端、阈值或可信网段。不要一误封就把整个 jail 永久关闭。

2. 暂停单个 jail

紧急情况下可以停止目标 jail:


			   bashsudo fail2ban-client stop  sudo fail2ban-client status 

影响范围是该 jail 不再继续检测和封禁,对应 action 通常会清理自身规则,但必须实际检查防火墙。恢复前先修正配置并测试:


			   bashsudo fail2ban-client -t sudo fail2ban-client start  sudo fail2ban-client status  

3. 回滚整个 Fail2ban 变更

若配置或 action 导致范围性故障,先通过带外通道保留证据,然后:


			   bashsudo systemctl stop fail2ban sudo systemctl status fail2ban --no-pager sudo nft list ruleset | grep -i f2b || true sudo iptables-save | grep -i f2b || true 

服务正常停止时通常会执行 actionstop 清理规则,但不能假定一定成功。确认网络恢复后,从变更前备份恢复 /etc/fail2ban,再执行配置测试。恢复备份会覆盖现有配置,操作前应先把故障版本另存以便复盘:


			   bash#!/usr/bin/env bash set -euo pipefail BACKUP_ARCHIVE="<备份目录>/fail2ban-<时间戳>.tar.gz" FAILED_COPY="<备份目录>/fail2ban-failed-$(date +%Y%m%d-%H%M%S).tar.gz" sudo tar -C /etc -czf "${FAILED_COPY}" fail2ban sudo tar -C /etc -xzf "${BACKUP_ARCHIVE}" sudo fail2ban-client -t 

通过测试后再启动服务,并从第二管理链路验证。不要直接执行 nft flush ruleset 或清空全部 iptables 规则来恢复访问,这会同时移除其他安全策略,扩大事故范围。

十、参数怎么定:从日志基线出发

1. maxretry

maxretry = 3 看似更严格,但共享 NAT、自动化任务使用旧密钥、运维工具并发连接时很容易误封整个出口。建议先统计历史窗口内同一来源的失败分布,再决定阈值。

可以从 SSH journal 中抽取近期失败日志做人工分析,具体正则需根据本机日志格式调整:


			   bashsudo journalctl -u  --since '7 days ago' --no-pager    | grep -E 'Failed password|Invalid user|authentication failure'    > /tmp/sshd-failures-sample.log sudo fail2ban-regex    /tmp/sshd-failures-sample.log    /etc/fail2ban/filter.d/sshd.conf    --print-all-matched 

不要用未经验证的 awk 字段位置直接统计 IP,因为 OpenSSH 日志格式会随认证方式和消息类型变化。应先让 Fail2ban 自身 filter 验证提取结果,或使用结构化日志解析工具。

2. findtime

窗口太短只拦截高速爆破,无法发现低速尝试;窗口太长则更容易把零散的正常失败累积在一起。SSH 公网入口通常可以从 10 分钟到 1 小时的小范围灰度开始,但最终值必须由业务登录行为和安全策略决定。

3. bantime

较短 bantime 能降低共享地址误封影响,较长 bantime 能减少重复来源消耗。Fail2ban 的部分版本支持递增封禁,例如:


			   ini[DEFAULT] bantime.increment = true bantime.factor = 2 bantime.maxtime = 1d 

这些选项必须先用本机版本测试。启用后要监控长期封禁数量和误伤,不能把递增封禁等同于永久黑名单。

十一、ignoreip 白名单也要有生命周期

ignoreip 能避免堡垒机、VPN 出口和自动化节点被封禁,但它同时绕过该 jail 的检测处置。白名单过宽,攻击者一旦进入可信网络就不会被 Fail2ban 阻断;白名单长期不清理,旧办公出口或已回收云地址也可能被新租户继承。

先查看 jail 当前生效的忽略列表:


			   bashsudo fail2ban-client get sshd ignoreip sudo fail2ban-client status sshd 

配置审查应逐项记录地址归属、用途、负责人、批准单和到期时间。建议遵循:

  • 使用最小的单 IP 或精确 CIDR,不把整个 VPC、办公网络或 RFC1918 私网全部放行。
  • 同时评估 IPv4 与 IPv6;只登记 IPv4 出口不代表 IPv6 管理路径安全。
  • 优先登记稳定的堡垒机/VPN 出口,而不是每位管理员不断变化的家庭公网 IP。
  • 不依赖未经控制的主机名作为长期信任边界。DNS 变化、启动时解析行为和版本差异会让范围不可预测。
  • 临时白名单必须有自动到期或工单复查,不能只添加不移除。

SSH_CONNECTION 的第一列通常是 sshd 看到的客户端地址,可以作为核对线索:


			   bashprintf '%s ' "${SSH_CONNECTION:-not-an-ssh-session}" 

这条值可能是堡垒机、NAT 或代理地址,不能把脚本输出自动追加到 ignoreip。必须与网络拓扑和认证日志交叉确认。

白名单变更会减少防护范围,也属于安全策略变更。执行前备份配置、确认第二管理通道并保存有效配置;修改后先测试:


			   bashsudo fail2ban-client -t sudo fail2ban-client -d > /tmp/fail2ban-effective-config.after-ignoreip 

审核差异后再重新加载:


			   bashsudo fail2ban-client reload sudo fail2ban-client get sshd ignoreip sudo fail2ban-client status sshd 

执行后从白名单内和非白名单的受控测试源分别验证。前者应保持可管理,后者触发失败时仍应被 jail 统计。回滚时恢复上一版 local 配置、运行 fail2ban-client -t,再 reload,并确认有效列表回到变更前状态。

不要因为一个合法用户被封禁,就把其整个运营商网段加入白名单。正确处理是先 unban 单个 IP,确认失败原因;如果是客户端保存了旧密码或自动化重复认证,应修复客户端。白名单只能基于明确的网络信任关系,不是误封的快捷补丁。

十二、为 Web 登录接口写自定义 filter

Web jail 比 SSH 更容易配置错误,因为客户端地址可能经过反向代理,日志字段也由应用决定。前提是访问日志中的来源 IP 可信:代理必须覆盖而不是盲目信任客户端提交的 X-Forwarded-For,应用和 Web 服务器只能接受来自受信代理的转发头。

假设应用日志经过验证后具有以下固定格式:


			   text2026-07-16T1001Z login_failed remote_addr=192.0.2.10 user=alice reason=bad_password 

可以创建 /etc/fail2ban/filter.d/app-login.local


			   ini[Definition] failregex = ^S+s+login_faileds+remote_addr=s+user=S+s+reason=bad_passwords*$ ignoreregex = 

再创建 jail:


			   ini[app-login] enabled = true filter = app-login backend = auto logpath = <日志文件> port = http,https findtime = 10m maxretry = 8 bantime = 30m ignoreip = 127.0.0.1/8 ::1 <管理网段> 

上线前同时准备匹配样本和不应匹配样本:


			   bashsudo fail2ban-regex    <日志样本文件>    /etc/fail2ban/filter.d/app-login.local    --print-all-matched    --print-all-missed 

需要重点防止三类误匹配:

  • 成功登录行也包含相似字段。
  • 应用把用户输入原样写入日志,攻击者可注入换行或伪造 remote_addr
  • 反向代理后日志中的地址其实是代理 IP,导致封禁所有用户共用的入口。

如果 Fail2ban 位于应用节点,而所有请求都来自负载均衡器,那么本机 L3/L4 防火墙通常只能看到负载均衡器地址。即便日志中有真实客户端 IP,封禁该 IP 的本机防火墙规则也可能拦不到它,因为数据包源地址已经变成代理地址。此时应在 WAF、反向代理或统一边界层实施限速与封禁,而不是在应用节点假装规则有效。

十三、action 选择:nftables、iptables 与 firewalld

Fail2ban 包通常带有多种 action,例如 nftables、iptables 和 firewalld 相关文件。可先列出本机实际可用项:


			   bashsudo find /etc/fail2ban/action.d -maxdepth 1 -type f    ( -name '*nft*' -o -name '*iptables*' -o -name '*firewall*' )    -printf '%f ' | sort 

不要从其他版本文档复制一个本机不存在的 banaction 名称。若确实需要覆盖默认 action,应在测试机验证,并通过 fail2ban-client -d 确认最终命令。示例:


			   ini[DEFAULT] banaction = nftables-multiport 

这个名称仅适用于本机存在对应 action 文件且 nftables 为批准后端的环境。使用 firewalld 时,应选择与其生命周期兼容的 action,并验证 firewall-cmd --reload 后 Fail2ban 规则是否仍然存在或能正确恢复。

IPv6 也需要验证。公网 SSH 同时监听 0.0.0.0 和 [::] 时,只封 IPv4 会留下直接绕过路径。检查 jail 是否能从日志提取 IPv6、action 是否创建了相应规则,并用受控 IPv6 测试源完成灰度。

十四、日志轮转、journal 和状态数据库

1. 文本日志轮转

使用 backend = autopolling 等文本日志后端时,要验证 logrotate 后 Fail2ban 能继续跟踪新文件。先查看轮转配置:


			   bashsudo grep -R "<日志文件>" /etc/logrotate.conf /etc/logrotate.d 2>/dev/null sudo fail2ban-client get  logpath 

不要为了测试直接强制轮转生产大日志,除非已经评估服务的 reopen 行为、磁盘空间和回滚。可以在测试环境执行同配置轮转,再观察 jail failure counter 是否继续更新。

2. systemd journal

journal 后端避免了路径和 inode 轮转问题,但仍依赖 journald 保留足够时间的日志。检查当前占用和持久化方式:


			   bashsudo journalctl --disk-usage sudo systemd-analyze cat-config systemd/journald.conf 

如果日志因空间策略或速率限制过早丢失,Fail2ban 无法从不存在的事件中判断攻击。修改 journald 参数会影响整机日志,必须单独评估磁盘和合规要求,本文不建议为 Fail2ban 盲目调大。

3. Fail2ban 数据库

常见包会使用 /var/lib/fail2ban/fail2ban.sqlite3 保存持久状态。路径和保留时间以有效配置为准:


			   bashsudo fail2ban-client -d | grep -E 'dbfile|dbpurgeage' sudo ls -lh /var/lib/fail2ban 2>/dev/null 

不要在服务运行中直接删除或手工编辑 SQLite 文件。数据库异常时先停服务、备份文件、检查日志,并按当前版本维护方式处理。删除数据库会丢失封禁历史,属于有影响操作。

十五、监控和日常巡检

1. 本机状态巡检


			   bashsudo systemctl is-active fail2ban sudo fail2ban-client ping sudo fail2ban-client status sudo fail2ban-client status sshd sudo journalctl -u fail2ban --since '1 hour ago' --no-pager    | grep -E 'ERROR|WARNING|Ban |Unban ' 

关注指标不应只有“封了多少 IP”,还包括:

  • 日志读取是否持续正常。
  • filter failure counter 是否长期为零或突然暴涨。
  • action 是否报命令失败。
  • 当前封禁数量是否异常增长。
  • 误封工单数量。
  • SSH 成功与失败登录趋势。
  • 边界层是否仍有大量连接压到主机。

如果接入第三方 Fail2ban exporter,Prometheus 指标名会随实现不同而变化,必须以实际 exporter 暴露的指标为准,不能照抄不存在的指标。部署 exporter 时还要限制监听地址和访问权限,避免暴露封禁列表等安全信息。

2. 审计脚本

下面脚本只读取状态和日志,不修改防火墙:


			   bash#!/usr/bin/env bash set -euo pipefail JAIL_NAME="" command -v fail2ban-client >/dev/null 2>&1 || {   echo "fail2ban-client not found" >&2   exit 1 } sudo systemctl status fail2ban --no-pager sudo fail2ban-client ping sudo fail2ban-client status sudo fail2ban-client status "${JAIL_NAME}" echo "Recent Fail2ban warnings and errors:" sudo journalctl -u fail2ban --since '24 hours ago' --no-pager    | grep -E 'ERROR|WARNING' || true echo "Fail2ban-managed firewall objects:" if command -v nft >/dev/null 2>&1; then   sudo nft list ruleset | grep -i -A 10 -B 3 f2b || true fi if command -v iptables-save >/dev/null 2>&1; then   sudo iptables-save | grep -i f2b || true fi 

该脚本不会判断某个 IP 是否恶意。封禁列表涉及安全处置,仍需关联认证日志、资产归属、威胁情报和变更记录。

十六、长期重复来源与 recidive jail

普通 jail 只处理目标服务在当前时间窗口内的失败。某个来源可能每隔几小时重复被不同 jail 短暂封禁,却在解封后继续尝试。Fail2ban 随包提供的 recidive filter 可以读取 Fail2ban 自身的 Ban 日志,对反复触发者施加更长封禁。

启用前先确认 Fail2ban 确实写文件日志:


			   bashsudo fail2ban-client -d | grep -E 'logtarget|dbfile' sudo test -r /var/log/fail2ban.log && sudo tail -n 30 /var/log/fail2ban.log sudo test -r /etc/fail2ban/filter.d/recidive.conf &&    sudo sed -n '1,160p' /etc/fail2ban/filter.d/recidive.conf 

如果 logtarget 仅指向 systemd journal,/var/log/fail2ban.log 不存在,就不能照抄文件型 recidive 配置。应先根据本机版本确定受支持的日志来源;不要为了一个 jail 随意改变全局日志路径。

文件日志条件满足后,可在测试环境评估:


			   ini[recidive] enabled = true filter = recidive backend = auto logpath = /var/log/fail2ban.log findtime = 1d maxretry = 5 bantime = 1w ignoreip = 127.0.0.1/8 ::1 <管理网段> 

这些时间值只是便于理解配置关系,不是所有企业都适用的推荐默认值。recidive 的误封影响更大:移动网络、家庭宽带和云代理的公网地址会重新分配,长时间封禁可能落到无关用户;共享 NAT 下,一个用户的失败也会影响整个出口。

上线前要用已有 Fail2ban 日志测试:


			   bashsudo fail2ban-regex    /var/log/fail2ban.log    /etc/fail2ban/filter.d/recidive.conf    --print-all-matched 

抽查匹配是否来自真实 Ban 记录,并确保 recidive 自己产生的日志不会形成错误递归。完成配置测试后,只在单台非关键节点灰度,观察长期封禁列表和误伤。

recidive 不是威胁情报系统。是否进行跨主机、跨业务的长期阻断,应由集中安全平台结合资产、ASN、代理、地理位置和攻击行为判断。主机上的一个 jail 不应直接把地址同步为企业全网永久黑名单。

十七、多机与容器环境的边界

Fail2ban 默认是单机状态:A 节点看到的失败不会自动让 B 节点封禁。如果同一服务后面有多台主机,攻击请求经负载均衡分散后,单机阈值可能永远达不到。可选方案包括在统一入口限速、集中日志检测后调用边界防火墙、WAF 或安全平台策略。

把封禁 IP 从一台主机自动同步到全网,是影响范围很大的安全自动化。必须处理 NAT 共享地址、IPv6、过期时间、冲突恢复、审计和回滚,不能用一个未经认证的消息队列脚本直接广播。

在容器和 Kubernetes 环境中还要确认网络路径:

  • Fail2ban 运行在哪个网络命名空间。
  • 日志中的地址是否为真实客户端地址。
  • 封禁规则作用于宿主机、Pod 还是入口网关。
  • CNI、Service 和 kube-proxy/eBPF 数据路径是否会经过该规则。
  • Pod 重建后状态是否丢失。

如果目标是保护 Ingress 登录接口,通常优先使用 Ingress Controller 原生限速、WAF、身份平台锁定策略和集中安全控制;Fail2ban 更适合能同时看到可信日志和真实数据包来源的节点。

十八、出现大量失败后,先判断是否已经失陷

Fail2ban 只能对日志中观察到的失败做反应。攻击者如果已经获得有效密钥、复用被盗会话或通过漏洞进入系统,可能只产生一次成功登录,完全不会触发 maxretry。因此发现暴力破解时,不能把“已封禁攻击 IP”当作事件结束。

1. 固化时间线和原始证据

先记录告警时间、主机时区、jail、来源地址、失败总数和当前封禁状态。导出目标窗口的原始日志,文件放入受保护的取证目录:


			   bash#!/usr/bin/env bash set -euo pipefail EVIDENCE_DIR="<取证目录>" START_TIME="<开始时间>" END_TIME="<结束时间>" sudo install -d -m 0700 "${EVIDENCE_DIR}" sudo journalctl -u     --since "${START_TIME}"    --until "${END_TIME}"    --output=short-iso-precise    --no-pager    | sudo tee "${EVIDENCE_DIR}/ssh-journal.log" >/dev/null sudo journalctl -u fail2ban    --since "${START_TIME}"    --until "${END_TIME}"    --output=short-iso-precise    --no-pager    | sudo tee "${EVIDENCE_DIR}/fail2ban-journal.log" >/dev/null sudo sha256sum    "${EVIDENCE_DIR}/ssh-journal.log"    "${EVIDENCE_DIR}/fail2ban-journal.log"    | sudo tee "${EVIDENCE_DIR}/SHA256SUMS" >/dev/null 

<开始时间> 和 <结束时间> 应使用 systemd 能解析、且包含明确时区的时间格式。日志中含账号和 IP,应限制访问并按取证流程保存。不要为了节省空间先截断或清理原日志。

2. 检查是否存在异常成功认证


			   bashsudo journalctl -u     --since '<开始时间>'    --until '<结束时间>'    --no-pager    | grep -E 'Accepted (password|publickey)|session opened' last -Fai | head -n 50 sudo lastb -Fai | head -n 50 

last 和 lastb 依赖 wtmp/btmp,文件可能被轮转、损坏或未启用,不能单独作为无入侵证明。需要把成功登录来源、账号、密钥指纹、sudo 记录、堡垒机审计和云平台登录记录关联起来。

如果系统启用了 auditd,可补充查询:


			   bashsudo ausearch -m USER_LOGIN,USER_AUTH    -ts '<开始时间>'    -te '<结束时间>'    -i 

不同 audit 版本接受的时间格式有限,应先看 ausearch --help。没有 audit 记录不能据此假定没有登录。

3. 只读检查账号、密钥和持久化入口


			   bashgetent passwd sudo stat /etc/passwd /etc/shadow /etc/group /etc/sudoers sudo find /root /home    -xdev    -type f    ( -name authorized_keys -o -name authorized_keys2 )    -printf '%TY-%Tm-%Td %TH:%TM:%TS %u:%g %m %p ' sudo systemctl list-timers --all --no-pager sudo find /etc/cron.d /etc/cron.daily /var/spool/cron    -xdev -type f -printf '%TY-%Tm-%Td %TH:%TM:%TS %u:%g %m %p '    2>/dev/null 

判断要与资产基线和配置管理记录比较。文件修改时间异常是线索,不是确定入侵的结论;正常补丁、账号开通和自动化也会改变这些文件。

继续采集进程和网络快照:


			   bashps -eo user,pid,ppid,lstart,etime,cmd --forest sudo ss -plant sudo lsof -nP -i 2>/dev/null 

命令输出可能含敏感参数。不要直接把完整进程命令行贴到公开工单,先按安全流程脱敏。

4. 怀疑失陷时不要在原机“边查边修”

如果发现未知成功登录、陌生密钥、异常提权、可疑外连或持久化项,应升级为安全事件。网络隔离、磁盘快照、密钥吊销和主机重建都属于高影响操作:

  • 影响范围 :隔离会中断业务,吊销凭证可能影响自动化和其他主机。
  • 执行前检查 :确认资产、依赖、当前会话、证据保全和安全负责人。
  • 快照/备份 :按取证要求保存磁盘、内存或云审计,避免普通备份覆盖证据。
  • 灰度 :先从负载均衡摘除受影响节点,确认冗余容量,再隔离网络。
  • 执行后验证 :检查没有生产流量继续进入,凭证已轮换,相关横向资产已排查。
  • 回滚 :安全隔离通常不应在原因未查清时直接回滚;恢复服务应使用可信镜像重建并重新纳管。

不要在已疑似失陷的主机上只改密码、安装 Fail2ban 后继续运行。攻击者可能拥有 root 权限或持久化后门,原机已经不能作为可信执行环境。凭证轮换应从干净终端完成。

5. 区分攻击噪声与需要升级的事件

以下证据更接近常见互联网扫描:大量不存在用户名、分散来源、没有成功认证、服务与文件基线无变化。以下证据需要立即升级:同一失败来源随后成功登录、非预期账号成功、登录后出现 sudo、密钥或定时任务变化、异常外连、日志缺口或清理痕迹。

结论必须由日志、审计、配置差异和进程网络证据共同支撑。Fail2ban 的 Total banned 只是处置计数,不能说明主机是否安全。

十九、Fail2ban 之外必须同时完成的 SSH 加固

1. 关闭不必要的密码认证

修改 sshd 是高风险操作,错误配置会造成远程失联。变更前保持当前会话、准备带外入口、备份配置,并用 sshd -t 做语法检查。示例流程:


			   bash#!/usr/bin/env bash set -euo pipefail BACKUP_DIR="<备份目录>" STAMP="$(date +%Y%m%d-%H%M%S)" sudo install -d -m 0700 "${BACKUP_DIR}" sudo cp -a /etc/ssh/sshd_config    "${BACKUP_DIR}/sshd_config.${STAMP}" sudo sshd -t sudo sshd -T | grep -E '^(passwordauthentication|permitrootlogin|pubkeyauthentication) ' 

实际修改建议写入受控的 sshd_config.d 文件,但要先确认主配置包含对应 Include,且选项没有被后续 Match 段改变。完成后运行:


			   bashsudo sshd -t sudo systemctl reload  sudo systemctl status  --no-pager 

reload 仍是有影响操作。保留原会话,从第二终端验证密钥登录成功后再退出。若失败,立即通过原会话恢复备份、执行 sshd -t,再 reload。不能在未验证新会话前关闭唯一连接。

2. 入口网络限制

能通过安全组、ACL、VPN 或堡垒机把 SSH 只开放给管理网段时,应优先缩小暴露面。防火墙变更必须先确认当前来源 IP、冗余管理通道、规则优先级和云平台回滚方式,再做精确灰度。不要在 SSH 会话中直接把默认策略改为 DROP,而没有先放行当前管理路径。

3. 账号与密钥治理

  • 禁止共享账号,使用可审计的个人身份。
  • 定期轮换密钥,撤销离职人员和泄漏密钥。
  • 对高权限访问使用 MFA、短期证书或集中身份系统。
  • 限制 sudo 权限,记录提权审计。
  • 及时修复 OpenSSH 和系统漏洞。
  • 对异常成功登录、非工作时间登录和新来源登录单独告警。

Fail2ban 主要处理失败行为;真正危险的往往是一次成功的异常登录,所以成功认证监控同样重要。

二十、配置纳管与批量变更

多台服务器不应靠手工编辑 jail.local。应把本地覆盖文件纳入配置管理,按操作系统、Fail2ban 版本、防火墙后端和服务角色生成配置。模板变量至少包括管理网段、SSH 端口、日志后端和阈值,敏感通知凭证必须从密钥系统注入。

每次发布前在同版本测试节点执行:


			   bashsudo fail2ban-client -t sudo fail2ban-client -d > /tmp/fail2ban-effective-config.new sudo diff -u    <变更前有效配置文件>    /tmp/fail2ban-effective-config.new 

有效配置输出可能因顺序或运行环境存在差异,需要人工关注 jail、filter、backend、ignoreip 和 action。批量发布建议按“测试节点 → 单台生产 → 单可用区小批 → 全量”进行,每批验证远程登录、jail 状态、防火墙规则和误封告警。

Fail2ban 支持通过客户端重新加载配置:


			   bashsudo fail2ban-client -t sudo fail2ban-client reload sudo fail2ban-client status 

reload 仍可能改变现有 jail 和防火墙规则,不能视为无影响操作。当前版本支持的 reload 选项以 fail2ban-client --help 为准,不要复制 --restart--unban 等版本相关参数。批量变更必须保留暂停开关和上一版配置,任何一批出现登录异常都停止扩散。

二十一、告警分级和处置证据

Fail2ban 的 Ban 日志不应全部升级为同一优先级。可以根据资产暴露面和关联证据分层:

  • 单一来源少量失败、无成功登录:保留低级别统计,观察是否重复。
  • 同一来源跨多个账号或 jail:提高优先级,关联边界日志和威胁情报。
  • 大量分布式来源低速尝试:主机阈值可能失效,应由入口层限速或集中检测。
  • 失败后出现成功登录、sudo、密钥变化或异常外连:立即按疑似失陷升级。
  • Fail2ban action error、日志停止读取或封禁数量异常为零:作为防护失效告警,而不是“没有攻击”。

每条高优先级告警至少保留主机、jail、来源地址、首次/末次时间、失败次数、封禁时长、对应原始日志位置和后续成功认证检查。来源 IP 是线索,不等同于攻击者身份;VPN、代理、Tor、云主机和共享 NAT 都会影响归属判断。

处置完成后记录 unban、白名单、阈值调整或边界阻断的操作人和工单号。若调整 filter,必须附带修改前后的匹配样本与 fail2ban-regex 结果,证明没有把成功事件或代理地址纳入匹配。若只是临时 unban,还要说明导致合法失败的客户端何时修复,避免同一问题反复触发。

安全监控还应关注数据缺失:Fail2ban 进程存活但日志源断开、journal 保留不足、filter 因服务升级不再匹配,都可能让封禁数突然归零。把“零 Ban”直接当作环境安全,会形成盲区。

二十二、上线检查清单

在生产启用前逐项确认:

  • 日志来源真实、持续、不可被低权限用户伪造。
  • fail2ban-regex  已在真实历史样本上验证匹配和漏匹配。
  • 可信管理来源已精确加入 ignoreip
  • IPv4 和 IPv6 路径都已评估。
  • action 与 nftables、iptables 或 firewalld 的实际管理方式一致。
  • 配置测试通过,有第二管理通道。
  • Fail2ban 配置和防火墙规则基线已备份。
  • 先在测试机验证,再对单台非关键节点灰度。
  • 启动后从第二终端验证登录,并检查真实防火墙规则。
  • 已写明误封解除、单 jail 停止和整体回滚步骤。
  • 有误封率、action error 和异常登录告警。
  • SSH 密钥、MFA、入口限制和账号治理已同步落实。

结语

Fail2ban 的价值不是让日志里“Ban”越多越好,而是把重复恶意尝试变成可验证、可回滚的本机处置。可靠部署必须从真实日志出发,用 fail2ban-regex 证明 filter,用防火墙规则证明 action,再通过第二管理链路证明不会锁死运维入口。

当系统规模扩大到多节点、反向代理或 Kubernetes 后,日志中的客户端 IP 与防火墙实际看到的源地址可能已经不同。此时应把处置上移到能够看见真实流量的入口层。无论架构怎样变化,Fail2ban 都只能是分层防御的一环:缩小暴露面、强化身份、持续修补和监控异常成功登录,才是抵御暴力破解的主体措施。

 


打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分