MySQL SQL 风险拦截:AST 规则、观察模式和可回退阻断
MySQL SQL 风险拦截:AST 规则、观察模式和可回退阻断
SQL 风险控制是缩小影响面,不是用 AST 规则消灭慢 SQL。确定性高的无条件更新可以阻断,其余风险先观察、限流并结合执行计划与统计信息判断。
先在网关做可解释的预检
对无条件UPDATE、DELETE、明显缺失关联条件的 Join 等高确定性模式,可以在提交前要求显式确认或拒绝。对于大扫描、隐式转换和深层子查询,先标记、限流或进入审核队列;最终仍应结合EXPLAIN、表统计信息和调用方身份判断。
| 信号 | 合适的处置 | 不宜据此断言的事 |
|---|---|---|
| 无 WHERE 的写操作 | 默认拒绝或人工确认 | 业务一定有问题 |
| 隐式类型转换 | 提示参数类型并验证索引 | 一定会全表扫描 |
| Join 条件缺失 | 阻断或要求白名单 | 查询结果一定错误 |
| 预估扫描行数偏大 | 限流、异步执行或审核 | 运行时一定超时 |
风险分数只作为排序依据
如果引入轻量模型,应当输出命中规则、输入特征和模型版本。不要只返回一个不透明分数。阈值需要按业务域配置,并保留白名单与快速回退开关。
def assess(sql: str, estimated_rows: int) -> list[str]: findings = [] normalized = sql.strip().lower() if normalized.startswith(("update ", "delete ")) and " where " not in normalized: findings.append("写操作缺少 WHERE 条件") if estimated_rows > 1_000_000: findings.append("预估扫描行数较高,建议复核执行计划") return findings让止损动作可恢复
线上先以观察模式运行:记录命中情况、实际耗时和人工结论,再决定哪些规则可以阻断。阻断响应应说明规则编号和申诉方式,审计记录只保存必要的 SQL 指纹与脱敏参数。发生误杀时,能按调用方或规则快速回退,比一套复杂的解析器更重要。
