判断数据是否泄露不能仅看日志中是否有select或union select,需结合执行结果、权限上下文及敏感对象访问行为交叉验证;盲注等无回显攻击在日志中仅显示为普通select,但已实际探库或窃密。

单纯看日志里有没有 SELECT 或 UNION SELECT 不能判断是否已泄露数据——攻击成功与否,得结合执行结果、权限上下文和敏感对象访问行为交叉验证。
查不到返回结果的 SELECT 不代表没泄露
很多 SQL 注入是盲注(Blind SQLi),比如用 AND SLEEP(5) 或 AND (SELECT COUNT(*) FROM users) > 0 探测结构,不显式返回数据。这类语句在审计日志里只是一条普通 SELECT,但实际已在提取信息。
- 重点盯住带条件分支、子查询嵌套、或调用系统函数(如
USER()、VERSION()、LOAD_FILE())的语句 - 检查同一会话中是否紧跟着大量相似结构的查询(如反复查询
information_schema.tables表名、字段名),这是典型的枚举行为 - MySQL 审计日志中若出现
sql_text字段含INFORMATION_SCHEMA或sys.schema_table_statistics,基本可判定正在探库
general_log 和 slow_query_log 的差异直接影响检测粒度
general_log 记所有语句,但开销大、日志爆炸;slow_query_log 只记执行超时的语句,容易漏掉快但恶意的注入(比如查单条 admin 用户的哈希值)。
- 生产环境建议启用
general_log到文件 + 日志轮转(log_output = FILE+expire_logs_days = 1),避免写满磁盘 - 若只能用
slow_query_log,把阈值设低(如long_query_time = 0.1),并配合log_queries_not_using_indexes = ON捕获低效但可能恶意的扫描式查询 - 注意:
slow_query_log不记录失败语句(如语法错误、权限拒绝),而真实攻击常伴随大量报错试探,这部分必须靠错误日志补全
权限上下文比 SQL 本身更能说明泄露风险
一条 SELECT * FROM users 在只读账号下只是越权读取,在 root 账号下却可能连同密码哈希、密钥字段一并拖走。
- 审计日志中必须关联
user、host、privilege_used(如 KingbaseES 的audit_record字段)三者,缺一不可 - 发现
user = 'app_user'却执行了SELECT ... FROM mysql.user,属于高危权限滥用,即使没返回结果也要告警 - PyMySQL 错误日志中若频繁出现
err.OperationalError: (1142, "SELECT command denied"),说明攻击者正在试权限边界,是泄露前的明确信号
异常流量特征要和数据库操作时间对齐
Web 层 WAF 或 Nginx 日志里的“可疑参数”(如 ' OR '1'='1)只是输入侧线索,必须匹配到数据库层对应时间窗口内的真实执行行为,才能确认落地。
- 用
client_ip+timestamp(精确到秒)做跨系统关联,注意时区是否一致(MySQL 默认用系统时区,应用服务器可能用 UTC) - 如果 Web 日志显示某 IP 在
14:23:05提交了恶意 payload,但数据库审计日志里该 IP 在14:23:07执行了一条SELECT COUNT(*) FROM credit_cards,这就是强证据链 - 避免只依赖单一来源:WAF 拦截了 99% 的注入,剩下那 1% 绕过规则的才是真泄露点,必须靠数据库日志兜底
最易被忽略的是日志字段缺失问题——比如 MySQL 官方审计插件默认不记录 sql_text 的完整内容(被截断为 1024 字节),而关键的 UNION SELECT load_file('/etc/passwd') 可能刚好卡在截断位置。上线前务必验证日志是否真正捕获了完整语句体。











