必须严格绑定命名参数并校验大小写,in子句用setparameterlist()且空列表需前置判断,表名/字段名/排序方向须白名单校验,优先使用criteria api防注入。

不能只靠写 :param 就算防注入,必须调用 setParameter() 且参数名严格匹配,否则查不到数据或直接报错——这不是注入,但功能已失效。
命名参数写了但没绑定,等于白写
Hibernate 在 createQuery() 阶段完全不校验参数是否被绑定,只做语法解析。漏掉 query.setParameter("name", value),运行时抛 QueryParameterException,查询中断,且无任何编译提示。
-
:userName和setParameter("username", v)大小写不一致 → 报错 - HQL 写
:user_name却传"userName"→ 同样报错 - 只创建
Query对象,后续没调绑定 → 查询逻辑静默失败
IN 子句必须用 setParameterList()
把 List<long></long> 直接塞进 setParameter("ids", idList) 是典型错误:Hibernate 会把它当单个对象处理,生成类似 WHERE id = ?(? 指向整个 List),导致语法错误或全表扫描。
- ✅ 正确写法:
query.setParameterList("ids", idList)→ 自动展开为WHERE id IN (?, ?, ?) - ❌ 禁止手动拼字符串:
"IN (" + String.join(",", ids) + ")"→ 注入风险 + 类型转换失败 - ⚠️ 空列表要提前判断:
setParameterList()不接受空集合,会抛IllegalArgumentException
表名、字段名、排序方向无法参数化
HQL 和原生 SQL 都不支持把 FROM user 中的 user、ORDER BY name 中的 name、或 ASC/DESC 当作参数绑定。任何字符串拼接都是非法且高危的。
- ❌
createQuery("FROM " + tableName + " WHERE id = :id") - ❌
createQuery("ORDER BY " + sortField + " " + sortOrder) - ✅ 白名单硬校验:
if (!Set.of("user", "order", "product").contains(tableName)) throw new IllegalArgumentException(); - ✅ 排序方向只允许字面量:
"ASC"或"DESC",禁止动态传入
优先用 Criteria API,而不是手写 HQL
CriteriaBuilder 是唯一能从源头杜绝 HQL 注入的方式:整个查询由 Java 方法链构建,无字符串拼接,字段名是 Java 属性名,拼错直接编译失败。
- ✅ 适用场景:简单条件、关联查询、类型安全需求强的业务
- ⚠️ 回退 HQL 的边界:需要
GROUP_CONCAT、嵌套子查询、数据库特有函数时 - ⚠️ 回退后仍需严格参数绑定 + 白名单校验,不能放松
最易被忽略的是:空 IN 列表处理、大小写敏感的参数名匹配、以及把白名单校验当成可选步骤——这三处一旦松动,防护就形同虚设。











