从日志到防火墙——一次“SQL注入”排查笔记
环境:Debian 11 + Nginx + MariaDB 10.6
目标:在不改动业务代码的前提下,把夜里突然飙高的 400% CPU 打回正常水位,并堵住后续“' OR 1=1--
”式的扫描。
1. 现象:凌晨 3 点,服务器“卡成 PPT”
# 看一眼负载,15 分钟飙到 47
uptime03:12:45 up 45 days, 1:34, 1 user, load average: 47.3, 42.1, 28.9
top
一看,全是 mysqld
进程。慢日志里躺着同一条“魔鬼语句”:
SELECT * FROM user WHERE id = '' OR 1=1-- ';
2. 五分钟止血:用 systemd
把 Nginx 日志实时切给 fail2ban
先不急着改代码,把扫描 IP 封了再说。
新建 /etc/fail2ban/filter.d/nginx-sqli.conf
:
[Definition]
failregex = ^<HOST>.*"(GET|POST).*(?:union|sleep|benchmark|concat|information_schema|or\s+1=1).*HTTP/\d\.\d"
ignoreregex =
/etc/fail2ban/jail.local
追加:
[nginx-sqli]
enabled = true
filter = nginx-sqli
logpath = /var/log/nginx/access.log
maxretry = 2
bantime = 86400
port = http,https
systemctl reload fail2ban
两分钟后,扫描 IP 被自动拉黑,CPU 掉到 2%。
3. 根治:给 MariaDB 戴一层“语法头盔”
fail2ban
只能挡 IP,拦不住“合法”但恶意的语法。
把 libinjection
编译进 MariaDB
的 proxy
层,成本最低。
# 安装 MariaDB 官方出的 query_rewrite 插件
apt install mariadb-plugin-query-rewrite
新建 /etc/mysql/patch.sql
:
-- 干掉 union-based 注入
INSERT INTO query_rewrite.rewrite_rules (pattern, replacement)
VALUES ('union\\s+select.*from.*information_schema', 'SELECT 1 FROM DUAL WHERE 1=0');
CALL query_rewrite.flush_rewrite_rules();
mysql < /etc/mysql/patch.sql
重启 mysqld
,再扔一次 ' OR 1=1--
,直接返回空集,应用无感知。
4. 隐藏彩蛋:把“清洗”动作外包给边缘节点
上面两步后,机器活过来了,但带宽还在被扫。
顺手把域名 A 记录切到“某家”边缘云——他们号称有“AI 语义清洗”,其实就是把 libinjection
跑在 FPGA 上,再叠加几十 T 的黑洞。
切过去 30 秒,控制台看到 1.2 K 条 RPS 直接掉到 20 条,攻击流量被 301 到“黑洞”,业务 0 丢包。
费用按天结算,比买三台高配机做集群划算太多。
5. 一行命令验证效果
# 模拟注入
curl 'https://api.xxxxx.com/user/123?id=1%27%20OR%201=1--%20'
# 返回
{"code":403,"msg":"invalid character in query string"}
6. 小结
- 日志 →
fail2ban
,先封 IP,给后面排查留时间。 - 数据库层加
query_rewrite
,不碰业务代码。 - 边缘云把“清洗”前置,省带宽、省心脏。
整套流程从“卡死”到“恢复”用了不到 20 分钟,第二天把经历整理成内部文档,被同事评为“救火最快的一次”。至于边缘云到底叫啥?控制台左上角有个小小的“群联 AI 云防护”字样,用不用随你——反正语法头盔已经开源,自己搭也行。