规避SQL注入改用NamedParameterJdbcTemplate后查询结果含空值求方案
问题原因分析
你遇到的问题本质是参数绑定的使用场景错误:NamedParameterJdbcTemplate的参数绑定是用来处理SQL中的值,而非列名这类数据库标识符的。
当你把"ID"作为参数:id传入时,实际执行的SQL会变成:
select ID from user where 'ID' is not null order by ID
这里的'ID'是字符串常量,永远满足is not null的条件,所以会返回所有记录,包括ID为空的条目。
解决思路
根据你的实际需求,分两种情况处理:
情况1:列名固定(就是原SQL的ID)
直接把列名硬编码在SQL里,不需要参数化。这种写法完全没有SQL注入风险,Tenacity的标记大概率是误报。
String sql = "select ID from user where ID is not null order by ID"; NamedParameterJdbcTemplate jdbcNamesTpl = new NamedParameterJdbcTemplate(this.jdbcTemplate); jdbcNamesTpl.query(sql, mapper);
情况2:列名需要动态指定
如果列名是动态获取的(比如来自用户输入或配置),必须通过白名单校验确保列名合法,再拼接SQL:
- 定义允许使用的列名单
- 校验传入的列名是否在白名单内,非法则抛出错误
- 安全拼接SQL执行
// 允许的列名白名单 Set<String> allowedColumns = Set.of("ID", "NAME", "EMAIL"); String targetColumn = "ID"; // 假设这是动态获取的列名 // 校验列名合法性 if (!allowedColumns.contains(targetColumn)) { throw new IllegalArgumentException("非法的列名"); } // 安全拼接SQL String sql = String.format("select %s from user where %s is not null order by ID", targetColumn, targetColumn); NamedParameterJdbcTemplate jdbcNamesTpl = new NamedParameterJdbcTemplate(this.jdbcTemplate); jdbcNamesTpl.query(sql, mapper);
关键提醒
参数化查询只适用于处理用户可控的数值/字符串值,对于列名、表名、排序字段这类数据库标识符,不能用参数绑定,必须通过白名单校验来避免注入风险。
内容的提问来源于stack exchange,提问作者sandy
相关产品推荐
相关产品推荐

