必须接入数据库审计日志才能实时发现SQL注入,因其记录真实执行语句,可识别OR 1=1、UNION SELECT等载荷;Web日志仅存URL编码参数,无法还原SQL逻辑且漏报盲注、报错注入。

数据库审计日志记录的是真实执行的 SQL 语句
Web 日志(如 Nginx access.log)只存编码后的 URL 参数,比如 /user?id=1%27%20OR%201%3D1,根本看不出这是 OR 1=1 还是正常业务参数。而数据库审计日志直接捕获 mysqld 或 postgres 实际解析并准备执行的语句,例如:{"sql_text":"SELECT * FROM users WHERE id = 1 OR 1=1"} —— 括号、空格、逻辑运算符全在,语法结构完整。
这意味着你能直接匹配布尔注入的 OR\s+1\s*=\s*1、报错注入的 UPDATEXML\(、堆叠注入的分号结尾,甚至识别出 EXECUTE IMMEDIATE 这类高危动态执行模式。
MySQL 8.0+ 和 PostgreSQL 的审计启用方式差异大
不同数据库开启审计的方式和输出格式差别明显,硬套同一套解析逻辑必丢数据:
- MySQL 8.0+ 推荐用
log_statement = 'ALL'(需配置log_output = 'TABLE'或'FILE'),避免用已弃用的general_log(性能差、CSV 表无索引、仅对新连接生效) - PostgreSQL 必须安装
pg_audit扩展,并设pgaudit.log = 'read, write'、pgaudit.log_parameter = on(否则看不到实际传入的字符串值)、pgaudit.log_catalog = off(防系统表查询干扰) - SQL Server 要启用
SERVER AUDIT,重点捕获BATCH STARTED和EXECUTE事件,尤其注意含分号的多语句,如SELECT 1; DROP TABLE logs;
别用单条正则硬扫“union”“select”,要组合上下文判断
单纯匹配关键字误报极高——业务里 UNION SELECT 完全合法。真正该盯的是「语法异常 + 语义可疑」的组合:
-
OR\s+1\s*=\s*1出现在 WHERE 条件中,且前面是单引号闭合(如id='1' OR 1=1) -
UNION ALL SELECT.*?FROM.*?information_schema或目标表名含mysql.user、pg_user -
EXTRACTVALUE\(、FLOOR\(RAND\(0\)等报错函数调用,括号内有空格或换行变体 - 语句中同时出现注释符(
--或/* */)和分号,且紧跟在非标准位置(如字段名后、函数调用中间)
Logstash / Fluentd 解析时优先用结构化解析器,不是 grok
MySQL 审计日志是 JSON 格式,PostgreSQL pg_audit 是带引号的纯文本,Oracle 又是另一套。用一条 %{SQL} grok 模式强行覆盖所有变体,维护成本高、漏报严重。
更稳的做法:
- 对 MySQL JSON 日志,用
json插件直接提取sql_text字段,再在该字段上做轻量正则匹配 - 对
pg_audit文本日志,用dissect提取双引号内的 SQL 片段(如AUDIT: "SELECT ..."→%{sql}),比 grok 更快、更少被换行或注释破坏 - 禁用自定义
%{SQL_INJECTION_PATTERN}这类不可维护的宏;规则写在 filter 阶段,保持可读可调试
真正难的不是写规则,而是把不同数据库的日志统一成可比较的字段结构——一旦解析失准,后续所有检测都建立在流沙之上。

















