You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 21:35:34