Java预编译语句条件空值检查触发Sonar SQL注入误报?
问题分析与解决方案
为什么Sonar触发告警?
Sonar的静态扫描是基于SQL语句的构建模式判断的:你通过字符串拼接直接修改了SQL的逻辑结构(NOT NULL/NULL是查询的核心条件分支),哪怕connected是布尔值,静态分析无法确保这个变量不会被外部输入污染(比如后续代码修改后,connected可能从用户输入转换而来),所以会判定存在SQL注入风险。
而单独保留search条件时,你用了?占位符传递参数,没有修改SQL结构,属于标准的预编译用法,所以Sonar认为这是安全的。
修复方案
方案1:参数化条件分支(推荐)
把布尔判断转换成参数化的SQL表达式,完全避免字符串拼接SQL结构:
String query = "SELECT * from my_table t " + "WHERE (t.connection_id IS NULL) = ? " + (search.isEmpty() ? "" : "AND (t.source LIKE ?)"); PreparedStatement statement = connection.prepareStatement(query); // 当connected为true时,需要connection_id IS NOT NULL,即(t.connection_id IS NULL)等于false statement.setBoolean(1, !connected); if (!search.isEmpty()) { // LIKE查询的通配符自行在参数中拼接,不要直接写入SQL statement.setString(2, "%" + search + "%"); }
这里利用布尔表达式等价转换:
connected = true→ 对应connection_id IS NOT NULL→ 等价于(t.connection_id IS NULL) = falseconnected = false→ 对应connection_id IS NULL→ 等价于(t.connection_id IS NULL) = true
方案2:拆分SQL语句(简单直接)
如果逻辑不复杂,也可以直接根据connected的值生成两个预编译SQL,彻底避免拼接:
PreparedStatement statement; if (connected) { String query = search.isEmpty() ? "SELECT * from my_table t WHERE t.connection_id IS NOT NULL" : "SELECT * from my_table t WHERE t.connection_id IS NOT NULL AND t.source LIKE ?"; statement = connection.prepareStatement(query); } else { String query = search.isEmpty() ? "SELECT * from my_table t WHERE t.connection_id IS NULL" : "SELECT * from my_table t WHERE t.connection_id IS NULL AND t.source LIKE ?"; statement = connection.prepareStatement(query); } if (!search.isEmpty()) { statement.setString(1, "%" + search + "%"); }
这种写法没有字符串拼接逻辑,Sonar会直接认可为安全的预编译用法。
是否可以忽略告警?
如果能100%确保connected变量永远不会被外部输入影响(比如只是内部业务逻辑的布尔标记,完全由代码控制,不会从接口参数、配置文件等外部来源获取),可以在Sonar中标记为误报。但从代码健壮性角度,更推荐用上面的修复方案,避免后续代码变更引入风险。
内容的提问来源于stack exchange,提问作者Ratoone
相关产品推荐
相关产品推荐

