fail2ban 默认不匹配 phpMyAdmin 登录失败日志,因其失败记录写在 Web 服务器 access.log 中且响应码为 200,非标准 auth 日志或 401/403;需自定义 filter 解析含 /phpmyadmin/index.php、200 状态码及错误文本的请求行。
fail2ban 为什么没匹配到 phpMyAdmin 的登录失败日志
默认情况下 fail2ban 不会识别 phpmyadmin 的登录失败记录,因为它不走系统 auth 日志,而是写在 web 服务器的访问日志(如 /var/log/apache2/access.log 或 /var/log/nginx/access.log)里,且失败响应是 http 200(页面返回了错误提示),不是 401/403。所以用默认的 sshd 或 apache-auth 过滤器完全无效。
实操建议:
- 确认 phpMyAdmin 实际日志位置:Apache 下通常在
access.log,Nginx 下看error.log或自定义 access 日志;关键线索是含/phpmyadmin/index.php且响应码为200,但响应体含Wrong username or password或类似文本(需开启日志记录响应体或用mod_security等辅助) - 更可靠的做法是让 phpMyAdmin 主动写失败日志:在
config.inc.php中加$cfg['LoginCookieValidity'] = 30;并配合修改其登录逻辑——但这不现实;推荐改用 Web 服务器层记录:Apache 加SetEnvIfNoCase标记失败请求,Nginx 用log_if(1.7.0+) - 最常用且落地的方式:解析
access.log中特定 URL + 状态码 + User-Agent 组合,例如:"POST /phpmyadmin/index.php HTTP/1.1" 200且响应体未重定向(靠后续脚本或 fail2ban 的failregex多行匹配)
如何写能捕获 phpMyAdmin 暴力破解的 failregex
核心难点在于:同一行日志里没有“失败”语义,必须结合上下文(比如 POST 后紧跟 HTML 错误提示)。fail2ban 支持多行匹配,但需谨慎启用,否则影响性能或误判。
实操建议:
- Apache 场景下,在
/etc/fail2ban/filter.d/phpmyadmin-apache.conf中定义:
[Definition] failregex = ^<HOST> -.*"POST /phpmyadmin/index\.php.*HTTP/[^"]+" 200.*"phpMyAdmin.*Wrong.*password.*$ ignoreregex =
注意:failregex 必须匹配整行,<HOST> 是内置宏,别手写 IP 正则;如果日志有虚拟主机字段,可能需要调整开头匹配位置
立即学习“PHP免费学习笔记(深入)”;
- Nginx 更麻烦:默认 access log 不含响应体,得先配置
log_format加入$body_bytes_sent或用第三方模块;更可行的是监听error.log中 PHP 报错,如PHP message: Login failed.*from <HOST>(需 phpMyAdmin 开启$cfg['ServerDefault'] = 0;并配合自定义 error_log) - 测试正则是否生效:用
fail2ban-regex /var/log/apache2/access.log /etc/fail2ban/filter.d/phpmyadmin-apache.conf,观察 match 数量和提取的<HOST>
启用 jail 后封禁不生效的常见原因
看到日志匹配成功、fail2ban-client status phpmyadmin 显示已 ban 了 IP,但该 IP 还能继续请求——大概率是 action 配置没对上实际防火墙环境。
实操建议:
- 检查
action类型:默认iptables在较新系统(Ubuntu 22.04+/Debian 12+)可能不可用,需换成iptables-ipset-proto6或nftables;确认/etc/fail2ban/jail.local中写了:
[phpmyadmin] enabled = true filter = phpmyadmin-apache logpath = /var/log/apache2/access.log action = %(action_mwl)s maxretry = 3 bantime = 1h
-
%(action_mwl)s是安全选择,它同时写 iptables 和发邮件;但如果服务器用ufw,得手动写action = ufw并确保ufw已启用且未被其他规则绕过 - 检查
iptables链顺序:fail2ban 插入的f2b-phpmyadmin链必须在INPUT链中靠前位置,否则被前面的 ACCEPT 规则截断;运行iptables -L INPUT -n --line-numbers确认 - 云服务器(AWS/Aliyun)要注意:安全组在网络层拦截,fail2ban 的 iptables 规则根本收不到包,此时只能靠 WAF 或平台自带防护,fail2ban 仅作日志分析参考
phpMyAdmin 登录路径被改名后怎么适配
很多人把 /phpmyadmin 改成 /dbadmin 或随机路径来“防扫描”,这会让原有 failregex 完全失效——不是安全增强,只是把漏报变成 100% 漏报。
实操建议:
- 过滤器里别硬编码路径,改用变量或通配:
"POST /[^"]+/index\.php不可靠;稳妥做法是提取所有含index.php且参数带token和login_form的 POST 请求,再结合响应内容判断 - 更直接:统一入口加 HTTP Basic Auth(Apache 的
.htaccess或 Nginx 的auth_basic),这样失败日志会进auth.log,可直接复用apache-authfilter,省去所有定制成本 - 如果坚持用自定义路径,记得同步更新三处:
logpath(确认新路径被记录)、failregex(替换 URL)、ignoreip(排除自己运维 IP,否则改完路径自己也登不上)
真正难的不是写正则,而是确认你看到的日志确实是攻击者触发的、且没有被 CDN 或反向代理吃掉真实源 IP;X-Forwarded-For 在 fail2ban 里默认不解析,得在 filter 中显式启用 use_dns = no 和 backend = auto,并确保 logpath 解析的是最终真实 IP 字段。



















