Fail2Ban无法直接阻断SQL注入,只能基于Web日志中已记录的攻击痕迹(如union select、' OR '1'='1)进行IP封禁;其有效性取决于日志是否真实记录请求参数、filter正则是否精准匹配、jail配置是否适配firewalld、以及云平台安全组是否同步放行/拒绝。
Fail2Ban 本身不能直接阻断 SQL 注入扫描——它只能基于 Web 日志中已记录的攻击痕迹做 IP 封禁,且依赖你日志是否真存了 union select、' OR '1'='1 这类内容。
很多默认配置根本不会把 URL 参数写进 /var/log/nginx/access.log,导致 Fail2Ban “无料可筛”。
grep log_format /etc/nginx/nginx.conf,确保包含 $request_uri 或 $args;更稳妥的是显式启用完整请求行:log_format main '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent';
curl "https://yoursite.com/search?q=1%27%20OR%20%271%27%3D%271",然后立刻执行:tail -n 20 /var/log/nginx/access.log | grep -i "or.*1.*1"
LogFormat 是否含 %r,且 CustomLog 引用了它不能复用 sshd 的配置,必须新建 /etc/fail2ban/filter.d/nginx-sql.conf,且正则要防绕过。
failregex 必须以 ^<HOST> 开头,结尾保留 $,否则可能跨行误匹配(?=.*) 正向先行断言组合多个关键词,比如:unions+select|sleep(|'s*ors*'1's*=s*'1,避免只匹配单个词被绕过.* 匹配中间任意字符,性能差还易误杀;改用 [^&nr]{0,50} 限制长度fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-sql.conf,看是否真能捕获刚才的测试请求CentOS 7+/8 默认用 firewalld,不能用老式 iptables-allports,否则封禁不生效。
/etc/fail2ban/jail.local 中添加:[nginx-sql]enabled = truefilter = nginx-sqllogpath = /var/log/nginx/access.logmaxretry = 3bantime = 3600action = %(action_fwrich)s[name=%(__name__)s, port="http,https", protocol="tcp"]
action_fwrich 是 CentOS 上适配 firewalld 的内置动作,会自动调用 firewall-cmd --add-rich-rule
fail2ban-client status nginx-sql,确认 jail 已加载且有匹配计数' OR 1=1 -- 这种基础 payload最常见原因不是规则写得不够狠,而是日志没记全、或 Fail2Ban 没读到最新行。
logpath 路径和日志轮转设置是否冲突——logrotate 每天切日志时,Fail2Ban 默认不会自动跟踪新文件,需加 backend = systemd 或用 gamin 后端ausearch -m avc -ts recent | grep fail2ban,若有拒绝记录,执行:setsebool -P fail2ban_read_log on
真正难的不是写正则,而是让日志、filter、jail、firewalld 四者对齐——漏掉任一环,failregex 再准也形同虚设。