SQL 注入修复视角
SQL 注入的根治手段是参数化查询(预编译):让 SQL 语句的结构在执行前确定,用户输入只作为参数数据传入,与语句结构彻底分离,输入中即使含引号与逻辑运算符也无法改变语句语义。需要注意,并非所有位置都能参数化——表名、列名、排序方向这类标识符无法用占位符替代,必须用白名单映射(代码中定义允许的固定值集合,逐项对应)。修复复查时重点关注三处:ORM 的 raw 或 execute 拼接、动态拼装的分页与筛选条件,以及存储过程内部的动态 SQL,这三处是参数化改造最常见的遗漏点。
基本信息
| 根治手段 | 占位符绑定参数(? 或命名占位符) |
|---|---|
| 例外位置 | 表名、列名、排序方向用白名单映射 |
| 复查点 | ORM 原生 SQL、拼接的分页与动态条件 |
| 临时缓解 | 转义与黑名单过滤,不能替代参数化 |
| 验证方式 | 修复后复测原注入点与等价路径 |
典型使用场景
- 修复方案评审:确认改造是否覆盖全部查询路径
- ORM 项目:排查 raw、execute 与拼接语句的调用点
- 动态排序:把用户选择的排序字段映射为固定列名
- 存储过程:检查内部动态 SQL 是否同样需要参数化
- 复测验证:对原问题点与等价请求做回归验证
修复示意(伪代码)
修复示意(伪代码)
不安全:语句 = SELECT * FROM orders WHERE id = + 用户输入
安全: 语句 = SELECT * FROM orders WHERE id = ?,以参数绑定用户输入
动态排序:
不安全:ORDER BY + 用户输入
安全: ORDER BY 白名单映射[用户输入](仅映射到固定列名)位置与手段
| 位置 | 可否参数化 | 手段 |
|---|---|---|
| WHERE 条件值 | 可行 | 占位符绑定参数 |
| INSERT 与 UPDATE 值 | 可行 | 占位符绑定参数 |
| 表名与列名 | 不可行 | 白名单映射到固定标识符 |
| 排序方向 | 不可行 | 映射为 ASC 或 DESC 固定值 |
| LIMIT 与 OFFSET | 可行 | 绑定整型参数并做范围校验 |
| 存储过程动态 SQL | 可行 | 过程内部同样使用参数化拼装 |
字符串转义与黑名单过滤只能作为临时缓解,不能替代参数化;更换数据库方言时过滤规则往往失效。
ORM 的 raw 与 execute 拼接仍然可以注入,需要逐个复查;存储过程内部的动态 SQL 同样需要参数化。