Hibernate 6 安全使用需严格参数绑定:命名参数须显式 setParameter()、IN 子句用 setParameterList()、表/字段/排序方向须白名单校验,动态查询优先用 Criteria API。

只要不用字符串拼接构造HQL,且所有用户输入都走 setParameter() 或 setParameterList() 绑定,Hibernate 6 就不会产生SQL注入——但漏绑、错绑、误用结构参数,会让查询直接失效或退化为拼接式危险操作。
命名参数必须显式调用 setParameter() 才生效
HQL 中写 :status 只是声明占位符,createQuery() 阶段完全不校验绑定状态。运行时才检查,没绑就抛 QueryParameterException,查不到数据,不是注入但功能崩了。
-
:userName和setParameter("username", value)大小写不一致 → 报错 - HQL 写
:user_name却传"username"→ 同样报错 - 只创建
Query,忘了后续setParameter()调用 → 查询中断,无任何编译提示
IN 子句必须用 setParameterList()
把 List 直接塞进 setParameter("ids", idList) 是典型错误。Hibernate 会把它当单个对象传,生成类似 WHERE id = ?(? 对应整个 List),导致语法错误或全表扫描。
- ✅ 正确:用
setParameterList("ids", idList),Hibernate 自动展开成WHERE id IN (?, ?, ?) - ❌ 禁止手动拼
"IN (" + String.join(",", ids) + ")"→ 注入+类型转换失败 - ⚠️ 空列表要单独判断:
setParameterList()不接受空集合,会抛异常
表名、字段名、排序方向无法参数化,必须白名单硬校验
HQL 和原生 SQL 都不支持把 FROM 表名、ORDER BY 字段、ASC/DESC 当参数绑定。任何字符串拼接都是非法且高危的。
- ❌
"ORDER BY " + sortField + " " + sortOrder→ 若sortOrder是"ASC; DROP TABLE user;",就完了 - ✅ 白名单校验示例:
if (!Set.of("userName", "createdAt", "status").contains(sortField)) throw new IllegalArgumentException(); - ✅ 排序方向只允许字面量
"ASC"或"DESC",禁止动态传入
复杂场景优先用 Criteria API,而不是手写 HQL
CriteriaBuilder 是唯一能从源头杜绝 HQL 注入的方式:整个查询由 Java 方法链构建,没有字符串参与拼接,字段名是 Java 属性名,拼错直接编译失败。
- ✅ 简单条件、关联查询、类型安全 → 用
CriteriaBuilder是首选 - ⚠️ 需要
GROUP_CONCAT、深度嵌套子查询、数据库特有函数 → 回退到 HQL,但必须严格参数绑定 - ⚠️ 原生 SQL(
createSQLQuery())只支持?1位置参数,不支持命名参数,且不能用setParameterList()
最容易被忽略的是:LIKE 模糊匹配的通配符必须拼在 Java 变量里,不是 HQL 里;空值传参虽不报错但可能引发意外逻辑;还有那些藏在动态 WHERE 构建里的 IN 和排序字段——它们往往不在主查询里,却最常出事。











