jdbcclient在spring boot 3.1+中默认防sql注入,但仅限严格使用bind()或命名参数绑定值;动态表名、列名、order by字段须白名单校验,in子句需交由namedparameterjdbctemplate处理。

用 JdbcClient 必须走参数绑定,否则等于裸奔
JdbcClient 在 Spring Boot 3.1+ 中默认防 SQL 注入,但只在你老老实实用 bind() 或命名参数时才生效。它底层封装的是 PreparedStatement,只要不手动拼 SQL 字符串,攻击者输 ' OR 1=1 -- 这类 payload,最终进数据库的只是带引号的普通字符串值,不会触发语法解析。
常见翻车点:
- ❌ 错误:用字符串拼接构建 SQL ——
"SELECT * FROM user WHERE name = '" + name + "'" - ✅ 正确:用
bind()绑定单个值 ——jdbcClient.sql("SELECT * FROM user WHERE name = ?").bind(0, name).query(new BeanRowMapper(User.class)) - ✅ 正确:用命名参数(推荐)——
jdbcClient.sql("SELECT * FROM user WHERE status = :status").bind("status", status).query(new BeanRowMapper(User.class))
JdbcClient 不支持动态 IN 列表,别硬凑问号
JdbcClient 原生不处理 WHERE id IN (?, ?, ?) 这种变长参数场景。试图用 String.format("IN (%s)", String.join(",", Collections.nCopies(ids.size(), "?"))) 拼 SQL,就等于绕过参数绑定机制,直接开后门。
正确做法是换用 NamedParameterJdbcTemplate 或手动拆解逻辑:
- ✅ 推荐:交给
NamedParameterJdbcTemplate处理 —— 它能自动展开:ids为对应数量的?并一一绑定 - ⚠️ 注意:
JdbcClient的bind()不接受集合类型直接传入IN子句;bind("ids", List.of(1L, 2L))会报错或被当单个对象序列化 - ⛔ 禁止:把
List转成字符串再塞进 SQL ——"IN ('" + String.join("','", ids) + "')"是典型高危写法
表名、列名、ORDER BY 字段不能参数化,必须白名单校验
JdbcClient 的参数绑定只对「值」起作用,对 SQL 结构(如表名、字段名、排序方向)完全无效。下面这些写法哪怕用了 bind(),也毫无防护力:
- ❌
"SELECT * FROM " + tableName + " WHERE id = ?" - ❌
"SELECT * FROM user ORDER BY " + sortField + " " + sortOrder - ❌
"ALTER TABLE " + table + " ADD COLUMN " + column + " VARCHAR(50)"
解决方案只有两个字:白名单。
- ✅ 把允许的表名、字段名、排序方向预先定义为枚举或常量集合
- ✅ 用
Enum.valueOf()或Set.contains()校验输入,不匹配直接拒掉 - ✅ 动态字段拼接前加断言 ——
if (!ALLOWED_SORT_FIELDS.contains(sortField)) throw new IllegalArgumentException("Invalid sort field")
和 JdbcTemplate 对比:JdbcClient 更轻但限制更多
JdbcClient 是 Spring Boot 3.1 引入的轻量级 JDBC 封装,目标是替代部分 JdbcTemplate 场景,但它不是全功能替代品。关键差异点:
- ✅
JdbcClientAPI 更简洁,链式调用清晰,适合简单 CRUD - ⚠️
JdbcClient不支持原生批量操作(如batchUpdate),得回退到JdbcTemplate - ⚠️
JdbcClient没有queryForObject/queryForList这类便捷方法,需自己配RowMapper - ✅ 两者在参数绑定安全机制上一致:都依赖
PreparedStatement,都只防「值注入」,不防「结构注入」
真正容易被忽略的是:很多人以为换了 JdbcClient 就“自动安全”了,结果在动态表名或 ORDER BY 上栽跟头 —— 那些地方从来就不在参数绑定的保护范围内。











