命名参数未调用setparameter()会导致功能失效而非sql注入;in子句必须用setparameterlist();表名、字段名、排序方向不可参数化,须白名单校验;优先使用criteria api杜绝注入风险。

命名参数没调用 setParameter() 就等于没防注入
HQL 里写 :name 只是声明占位符,Hibernate 在 createQuery() 阶段完全不检查参数是否绑定。漏掉 query.setParameter("name", value),运行时直接抛 QueryParameterException,查不到数据——这不是注入,但功能当场失效。
常见错误包括:
-
:userName和setParameter("username", ...)大小写或拼写不一致 → 报错 - 只创建
Query对象,忘了后续绑定动作 → 查询逻辑中断,且没有任何编译期提示 - 误用已废弃的
setString("name", value)等旧方法 → Hibernate 6 中类型推导弱,枚举或自定义类型可能出错
IN 子句必须用 setParameterList()
把 List<long></long> 直接传给 setParameter("ids", idList) 是典型错误。Hibernate 会把这个 List 当作单个参数值处理,生成类似 WHERE id = ?(? 对应整个 List 对象),导致语法错误或全表扫描。
正确做法只有一种:
- 必须用
setParameterList("ids", idList),Hibernate 才会自动展开成WHERE id IN (?, ?, ?) - 别手动拼
"IN (" + String.join(",", ids) + ")"→ 注入风险 + 类型转换问题 - 空列表要单独判断:
setParameterList()不接受空集合,会抛异常
表名、字段名、排序方向无法参数化,必须白名单校验
HQL 和原生 SQL 都不支持把 FROM 后的表名、ORDER BY 后的字段、ASC/DESC 这类结构当参数绑定。任何字符串拼接都是非法且危险的。
例如这些写法全是错的:
session.createQuery("FROM " + tableName + " WHERE id = :id")session.createQuery("ORDER BY " + sortField + " " + sortOrder)
必须走硬性校验:
- 表名/字段名 → 映射到预设枚举或用
Set.of("user", "order", "product").contains(...)校验 - 排序方向 → 只允许字面量
"ASC"或"DESC",禁止动态传入
优先用 Criteria API,而不是手写 HQL
Criteria API 是唯一能从源头杜绝 HQL 注入的方式:整个查询由 Java 方法链构建,没有字符串参与拼接,字段名是 Java 属性名,拼错直接编译失败。
适用边界很明确:
- 简单条件、关联查询、类型安全场景 →
CriteriaBuilder是首选 - 需要
GROUP_CONCAT、复杂子查询嵌套、数据库特有函数时 → 回退到 HQL,但必须严格参数绑定
动态条件组装、排序字段、分页 offset/limit 的拼接,是最常被忽视的风险点——哪怕主查询写了参数化,这些地方漏了照样中招。











