SQL注入人工审计应优先检查拼接字符串的WHERE条件和ORDER BY动态字段,尤其是用户输入直接参与SQL构造的位置,因其绕过预编译与ORM转义,属高危区。

SQL注入人工审计该从哪条语句入手
优先盯住拼接字符串的 WHERE 条件和 ORDER BY 动态字段,尤其是用户输入直接进 query 构造的地方。这类语句绕过预编译、躲过 ORM 自动转义,是高危区。
- 常见错误现象:后端用
str + user_input拼出 SQL,比如 Python 里"SELECT * FROM users WHERE name = '" + name + "'" - 使用场景:搜索框、分页排序(
ORDER BY ?)、多条件筛选(AND status IN (" + statuses + ")") - 参数差异:数字型输入容易被
int()拦住,但字符串型只要没走PreparedStatement或parameterized query就危险
怎么验证一个疑似点是否真能注入
别急着上 ' OR 1=1 -- ,先确认数据库类型和报错回显方式。不同 DB 对单引号、注释符、函数名的容忍度差别很大。
- 常见错误现象:输入
'报MySQLSyntaxErrorException或psycopg2.ProgrammingError,说明后端把错误堆栈直接吐给前端了 - 使用场景:在登录、密码重置、导出报表等接口的任意参数位置尝试闭合单引号
- 性能 / 兼容性影响:盲注(如
AND SLEEP(3))可能触发风控限流;PostgreSQL 不认--后面带空格的注释,得用/* */
复杂查询里哪些结构最常漏防
嵌套子查询、UNION SELECT、动态表名/列名、JSON 字段解析后的二次拼接——这些地方开发者往往觉得“已经够复杂了,没人会懂”,反而放弃参数化。
- 常见错误现象:
"SELECT * FROM " + table_name + " WHERE id = " + user_id,其中table_name来自配置或路由参数 - 使用场景:多租户系统按客户名切换表、ES 搜索结果反查 DB 时用
IN (SELECT ...)带入用户可控 ID 列表 - 参数差异:JDBC 的
setString()对列名无效;MyBatis 的${}是字符串替换,#{}才是预编译占位
为什么正则扫描工具总漏掉关键点
因为真正危险的不是 "' + input + '" 这种明眼人能看出来的拼接,而是经过两次编码、三次解包、一次 Base64 再 eval 的“合法”字符串组装。
- 常见错误现象:前端传
base64("name='admin'"),后端 decode 后直接拼进 SQL;或用json.loads()解析用户 JSON,再取其中字段拼查询 - 使用场景:低代码平台的条件构建器、API 网关的规则引擎、日志检索 DSL 转 SQL
- 性能 / 兼容性影响:某些框架对
eval()或exec()做了沙箱限制,但没拦住__import__('os').system()这类绕过写法
复杂点在于:漏洞不在一行代码里,而在数据流转的多个环节之间。一个参数从 HTTP 请求头进来,经中间件解密、鉴权模块校验、业务逻辑层格式化,最后才落到 DAO 层——漏掉其中任意一环的上下文还原,就等于没审。










