优化Fail2Ban正则需锚定行首^与行尾$、用\S+替代.*精简字符类、适配真实日志格式、结合jail语义过滤;示例:^Failed (?:password|publickey) for \S+ from (?:port \d+ )?ssh\d*$。

优化 Fail2Ban 正则表达式,核心是提升匹配精度、减少误判漏判,同时兼顾性能。关键不在“写得更全”,而在“抓得更准、边界更清、结构更稳”。
锚定行首行尾,避免碎片匹配
未加锚点的正则容易跨语义匹配,比如把成功登录日志里的“failure”子串误认为失败事件。
- 务必以 ^ 开头、$ 结尾,确保整行参与判断
- 错误示例:
Failed password for.*from <host></host>—— 可能匹配到Accepted password for user... Failed to bind socket这类混合行 - 正确写法:
^Failed password for \S+ from <host> \S*$</host>
精简字符类,禁用贪婪回溯
过度使用 .* 或嵌套量词会引发指数级回溯,既拖慢速度,又易因日志格式微变导致漏匹配。
- 用
\S+替代.*匹配用户名、端口等非空字段,明确边界 - 用非捕获组
(?:password|publickey)替代(password|publickey),省去分组开销 - 删除不影响封禁决策的细节,如具体端口号、协议版本(
ssh2)、时间戳等
适配真实日志格式,不依赖默认规则
不同系统、服务、日志轮转策略会导致格式差异。直接套用社区模板常出问题。
- 先用
tail -n 100 /var/log/auth.log | grep "Failed"抽取真实失败样本 - 观察字段顺序、空格数量、是否含 IPv6、是否有代理标记(如
via nginx) - 在
/etc/fail2ban/filter.d/sshd.local中自定义规则,优先于全局sshd.conf - 示例(适配含 IPv6 和 systemd-journal 的 Ubuntu 24.04):
^Failed (?:password|publickey) for \S+ from <addr> (?:port \d+ )?ssh\d*$</addr>
结合 jail 配置做语义过滤
单靠正则难覆盖所有场景,可借助 Fail2Ban 的上下文能力增强鲁棒性。
- 启用
ignoreself防止本机日志循环触发 - 设置
ignoreip白名单,排除运维跳板机和监控源 IP - 对高频合法行为(如 CI/CD 流水线 SSH 登录)添加
failregex排除项,例如:^Failed.*for gitlab-runner from <host></host>→ 加入ignoreregex - 用
maxlines限制多行日志匹配深度,防止单条长日志耗尽资源

















