fail2ban无法直接识别sql注入,需依赖web日志中记录的请求参数,通过自定义filter匹配典型注入特征(如' or '1'='1、union select等),结合正确log_format、firewalld-rich-rules action及云平台安全组适配,才能实现有效封禁。

Fail2Ban 本身不能直接识别或屏蔽 SQL 注入请求——它不解析 HTTP 请求体、不解码 URL、不执行语义分析。所谓“屏蔽 SQL 注入源”,本质是借力 Web 日志 + 自定义 filter,匹配日志中暴露的典型注入特征(如 ' OR '1'='1、UNION SELECT、sleep( 等),再触发封禁。这要求你已有 Web 服务(如 Nginx/Apache)将原始请求 URI 或参数写入可读日志,且 Fail2Ban 能稳定消费该日志。
确认 Web 日志是否记录可疑 SQL 片段
Fail2Ban 的能力上限取决于日志里有没有“证据”。很多默认 Nginx 配置只记 $status 和 $request_time,根本不会把 id=1%20OR%201=1 这类内容写进 /var/log/nginx/access.log。
- 检查当前 access 日志格式:运行
grep log_format /etc/nginx/nginx.conf,确保包含$request_uri或$args;推荐显式记录完整请求行:log_format main '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent'; - 手动触发一次测试请求(如访问
/search?q=1'%20OR%20'1'='1),然后立刻执行:tail -n 20 /var/log/nginx/access.log | grep "OR.*1.*1"—— 若无输出,说明日志没存关键字段,filter 再准也无米下锅 - Apache 用户需确认
LogFormat含%r(即原始请求行),且CustomLog引用该格式
编写并启用针对 SQL 注入的自定义 filter
不能复用 sshd 的配置,必须新建 filter 文件匹配 Web 日志中的攻击模式。CentOS 下路径为 /etc/fail2ban/filter.d/nginx-sql.conf:
# [Definition] failregex = ^<host> - .*"(GET|POST).*\?(?=.*(?:union\s+select|select\s+.*from|insert\s+into|drop\s+table|sleep\(|benchmark\(|\'\s*or\s*\'1\'\s*=\s*\'1)).*$ ignoreregex =</host>
关键点:
-
<host></host>是 Fail2Ban 内置变量,自动提取 IP;正则末尾的$必须保留,否则可能跨行误匹配 - 使用
.*\?匹配问号后参数,再用(?=.*...)正向先行断言组合多个关键词,避免漏掉编码绕过(如%27替代单引号) - 不要在
failregex里写过于宽泛的规则(例如只匹配'或;),否则正常用户输入也会被误杀 - 保存后,用
fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-sql.conf测试是否真能捕获到你刚才写的测试请求
配置 jail 并指定正确 backend 和日志路径
CentOS 7/8 默认用 firewalld,而 Fail2Ban 旧版默认走 iptables,不匹配就会“显示封禁但实际放行”。
- 创建
/etc/fail2ban/jail.d/nginx-sql.local,内容必须包含:[nginx-sql] enabled = true filter = nginx-sql logpath = /var/log/nginx/access.log maxretry = 2 findtime = 600 bantime = 1h action = firewallcmd-rich-rules[name=%(__name__)s, port="http,https", protocol="tcp"] backend = systemd
-
action行必须用firewallcmd-rich-rules(非iptables),否则firewalld不认;若系统已切到nftables,则改用nftablesaction 并确保nft命令可用 -
logpath必须与你真实 Nginx 日志路径完全一致;CentOS 中常见路径是/var/log/nginx/access.log,不是/var/log/httpd/access_log - 修改后必须执行
fail2ban-client reload,systemctl restart fail2ban不会重载新 jail
验证封禁是否真实生效
最容易卡住的环节:日志有内容 → filter 能匹配 → Fail2Ban 显示 ban → 但 IP 仍能继续发请求。这几乎一定是防火墙动作未落地。
- 触发两次测试请求后,运行:
fail2ban-client status nginx-sql,确认 “Number of detected” 和 “Currently banned” 都 > 0 - 立即检查
firewalld规则:firewall-cmd --list-rich-rules | grep nginx-sql,应看到类似rule family="ipv4" source address="192.168.1.100" reject的输出 - 若无输出,检查
fail2ban-client get nginx-sql banaction是否返回firewallcmd-rich-rules;如果不是,说明action配置未生效或拼写错误 - 云服务器(如阿里云 ECS、腾讯云 CVM)若启用了安全组,Fail2Ban 的本地封禁完全无效——此时只能靠 WAF 或自定义 action 调用云 API
真正难的不是写正则,而是让每层都对齐:Nginx 得记全请求、filter 得精准抓特征、jail 得选对 action、firewalld 得真加规则、云平台得允许本地封禁。少一环,就变成“日志里看着很热闹,黑客照连不误”。











