如何修复Hibernate中Session.createQuery的HQL注入SonarQube漏洞?
HQL注入漏洞原因及修复方案
漏洞根源
SonarQube的告警不是针对你用setParameter绑定参数的代码,而是你暴露的public修饰的createQuery(String query)方法——这个方法直接接收外部传入的完整HQL字符串,然后创建Query对象。如果调用这个方法的地方直接把用户可控内容拼接进HQL后传入,或者没有对传入的HQL做严格校验,就会完全绕开参数绑定机制,引发HQL注入风险。
举个典型的危险调用场景:
String userInput = "恶意HQL片段"; String hql = "FROM Product WHERE label = '" + userInput + "'"; productDao.createQuery(hql);
这种拼接方式直接将用户输入嵌入HQL,SonarQube正是识别到你提供了一个可直接传入原始HQL的公共入口,所以触发了告警。
修复方案
1. 限制createQuery方法的访问范围
把createQuery的访问修饰符从public改为private或protected,仅允许DAO内部调用,切断外部直接传入任意HQL的路径。
修改后的代码示例:
@Repository(value = "ProductDao") public class ProductDao implements IProductDao { public static final String LABEL_LIKE = "labellike"; public static final String NUM_CODE = "n_code"; public static final String LABEL = "label"; public static final String STATUS = "status"; // 改为私有方法,仅内部使用 private Query createQuery(String query) { return sessionFactory.getCurrentSession().createQuery(query); } // 业务方法内部调用私有方法,全程用参数绑定 public List<Product> getProductsByLabel(String label) { String hql = "FROM Product WHERE label = :label"; Query query = createQuery(hql); query.setParameter("label", label); return query.list(); } // 其余代码详见原输入 }
2. 强制所有HQL使用参数绑定,禁止字符串拼接
在DAO的所有业务方法中,严格使用:参数名的占位符,通过setParameter绑定用户输入值,绝对禁止直接将用户输入拼接进HQL字符串。
3. 动态查询场景改用类型安全的API
如果需要动态生成查询条件(比如多条件组合查询),放弃手动拼接HQL,改用Hibernate的Criteria API或JPA的CriteriaQuery,这类API是类型安全的,能从根源避免注入风险:
public List<Product> getProductsByDynamicConditions(String label, Integer status) { CriteriaBuilder cb = sessionFactory.getCurrentSession().getCriteriaBuilder(); CriteriaQuery<Product> cq = cb.createQuery(Product.class); Root<Product> root = cq.from(Product.class); List<Predicate> predicates = new ArrayList<>(); if (label != null) { predicates.add(cb.equal(root.get(LABEL), label)); } if (status != null) { predicates.add(cb.equal(root.get(STATUS), status)); } cq.where(predicates.toArray(new Predicate[0])); return sessionFactory.getCurrentSession().createQuery(cq).getResultList(); }
4. 若必须保留公共查询入口,添加严格校验(不推荐)
如果一定要给外部提供查询能力,必须对传入的HQL做白名单校验,只允许预定义的合法HQL语句,拒绝任意自定义的HQL内容。这种方式维护成本极高,仅作为极端场景的备选方案。
内容的提问来源于stack exchange,提问作者Z4N4TI
相关产品推荐
相关产品推荐

