jdbctemplate在spring boot 3中默认防sql注入,前提是使用?占位符+参数绑定;禁止字符串拼接sql、表名/列名需白名单校验;in查询须用namedparameterjdbctemplate;动态where应构建模板+分离参数列表。

JdbcTemplate 在 Spring Boot 3 中默认就防 SQL 注入,前提是别手抖拼字符串。它底层强制走 PreparedStatement,只要你不绕过参数绑定机制,攻击者输 ' OR 1=1 -- 这类 payload,数据库收到的永远是带引号的普通字符串值,不会被当 SQL 执行。
必须用 ? 占位符 + 参数数组或可变参数
这是最基础、也最容易翻车的一环。错误写法会直接废掉防护能力:
- ❌ 错误:字符串拼接 ——
jdbcTemplate.update("UPDATE user SET name = '" + name + "' WHERE id = " + id) - ✅ 正确:位置参数(推荐)——
jdbcTemplate.update("UPDATE user SET name = ? WHERE id = ?", name, id) - ✅ 正确:数组传参 ——
jdbcTemplate.query("SELECT * FROM user WHERE status = ? AND age > ?", new Object[]{status, minAge}, rowMapper)
Spring Boot 3 的 JdbcTemplate 会对所有含 ? 的 SQL 自动调用 Connection.prepareStatement(),参数由 JDBC 驱动做类型安全绑定,name 值哪怕含单引号、分号、注释符,都进不了语法解析阶段。
IN 查询必须用 NamedParameterJdbcTemplate
原生 JdbcTemplate 不支持动态长度的 IN 列表(比如 WHERE id IN (?, ?, ?)),硬写会触发 Invalid argument value: java.io.NotSerializableException 或运行时参数数不匹配。这时候不能靠字符串拼问号个数,得换工具:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- ✅ 注入
NamedParameterJdbcTemplate(Spring Boot 3 默认已配置) - ✅ 用
MapSqlParameterSource或Map传参:String sql = "SELECT * FROM user WHERE id IN (:ids)"; MapSqlParameterSource params = new MapSqlParameterSource("ids", Arrays.asList(1L, 2L, 3L)); namedJdbcTemplate.query(sql, params, rowMapper); - ⚠️ 注意:
:ids是一个整体参数,JDBC 驱动会把它展开成对应数量的 ? 并一一绑定,不是字符串替换
别在 SQL 字符串里拼表名、列名、ORDER BY 字段
JdbcTemplate 的参数绑定只对「值」生效,对「结构」无效。下面这些写法哪怕用了 ? 也完全不防注入:
- ❌
"SELECT * FROM " + tableName + " WHERE id = ?" - ❌
"SELECT * FROM user ORDER BY " + sortField + " " + sortOrder - ❌
"ALTER TABLE " + tableName + " DROP COLUMN " + columnName
这类场景必须白名单校验:
- 用枚举或静态 Map 映射合法字段名:
if (!ALLOWED_SORT_FIELDS.contains(sortField)) throw new IllegalArgumentException(); - 表名/列名若来自配置,应走配置中心 + 启动时校验,而非运行时拼接
动态 WHERE 条件要用 StringBuilder + 参数列表,别用字符串拼 SQL
常见需求如“按需组合查询条件”,错误做法是拼 SQL 字符串再执行;正确做法是构建 SQL 模板 + 分离参数:
- ✅ 安全写法:
StringBuilder sql = new StringBuilder("SELECT * FROM product WHERE 1=1"); List<object> params = new ArrayList(); if (minPrice != null) { sql.append(" AND price >= ?"); params.add(minPrice); } if (category != null) { sql.append(" AND category = ?"); params.add(category); } jdbcTemplate.query(sql.toString(), params.toArray(), rowMapper);</object> - ⚠️ 注意:
params.toArray()必须和?出现顺序严格一致,否则值会错位 - ⚠️
StringBuilder只拼固定结构部分,所有用户可控值必须进params
真正容易被忽略的是动态 SQL 场景下的参数顺序管理 —— 少一个 add(),或顺序颠倒,查出来的数据就可能不对,但不会报错,这种 bug 很难被测试覆盖到。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










