应优先搜索SQL关键字、字符串拼接操作符和用户输入入口,而非execute/query调用;真正危险点在SQL拼接层,需检查用户输入是否直接参与拼接、过滤是否有效、动态对象是否经白名单校验。

直接搜 execute 和 query 函数调用,大概率漏掉真正危险的点——因为 SQL 注入的起点不在执行层,而在拼接层。
全局搜索 execute 和 query 为什么不可靠
- 这类函数只是“最后一跳”,比如
jdbcTemplate.query()、db.execute()、cursor.execute(),它们本身不决定是否安全,关键看传进去的 SQL 字符串是怎么构造的 - 大量项目封装了 DAO 层或使用 ORM(如 MyBatis、Hibernate、Django ORM),
execute调用可能藏在抽象方法里,实际拼接发生在上层 XML、注解或动态构建逻辑中 - Java 中
Statement.executeQuery()看似明显,但若 SQL 字符串来自buildSql()方法,而该方法内部用了+拼接用户输入,审计时只盯executeQuery就会跳过漏洞源头
应该优先搜索的关键词组合
-
SELECT、INSERT、UPDATE、DELETE、UNION(大小写不敏感,配合正则更准:(select|insert|update|delete|union)\s+from) -
${(MyBatis 动态参数,等同于字符串拼接,#{}才安全) -
+、.、%、.format(、f"、concat((所有运行时拼接操作符) -
getHeader(、getCookie(、getRequestURI(、file_get_contents((污染源入口,常被忽略)
拼接点附近必须检查的三件事
- 用户输入变量是否直接出现在拼接表达式中:例如
"WHERE id = " + request.getParameter("id")或f"ORDER BY {sort_field}" - 是否存在“看似过滤实则无效”的处理:如
StringEscapeUtils.escapeSql()(已废弃且不防注入)、addslashes()(宽字节绕过)、mysql_real_escape_string()(PHP 7+ 已移除,且不适用于预编译场景) - 动态表名/列名是否走白名单校验:例如
if (!allowedColumns.contains(sortField)) throw ...,没这步就危险
容易被绕过的典型场景
- 后台接口未鉴权却接收用户输入:比如
/admin/data.php或/jmreport/show,连 token 都不要,params字段直通 SQL 构造逻辑 - 二次注入:数据先入库(当时过滤了),后续导出、统计、报表生成时原样取出拼 SQL,此时过滤早已失效
- Header 注入:
request.getHeader("X-Forwarded-For")或$_SERVER['HTTP_REFERER']被拼进日志查询或权限判断 SQL,没人会去查 Header 来源
真正高危的点,往往藏在“看起来不像 SQL”的地方:一个 ${tableName}、一行 .format(user_input)、甚至一段从 Cookie 读出再拼进 WHERE 的代码。盯住拼接动作本身,比盯住 execute 调用有用十倍。











