【发布时间】:2013-05-08 10:31:01
【问题描述】:
在使用 JPA Criteria API 时,直接使用 ParameterExpression 而非变量有什么优势?例如。当我希望在字符串变量中按名称搜索客户时,我可以写类似
private List<Customer> findCustomer(String name) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Customer> criteriaQuery = cb.createQuery(Customer.class);
Root<Customer> customer = criteriaQuery.from(Customer.class);
criteriaQuery.select(customer).where(cb.equal(customer.get("name"), name));
return em.createQuery(criteriaQuery).getResultList();
}
有了参数,这就变成了:
private List<Customer> findCustomerWithParam(String name) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Customer> criteriaQuery = cb.createQuery(Customer.class);
Root<Customer> customer = criteriaQuery.from(Customer.class);
ParameterExpression<String> nameParameter = cb.parameter(String.class, "name");
criteriaQuery.select(customer).where(cb.equal(customer.get("name"), nameParameter));
return em.createQuery(criteriaQuery).setParameter("name", name).getResultList();
}
为了简洁起见,我更喜欢第一种方式,尤其是当查询因可选参数而变长时。使用像 SQL 注入这样的参数有什么缺点吗?
【问题讨论】:
-
我不能代表 JPA,但我发现 OpenJPA 在内部将 Criteria 查询转换为 JPQL,这可以通过使用 OpenJPA 特定的功能来打印(参见 openjpa.apache.org/builds/2.1.1/apache-openjpa/docs/…)。第一个查询转换为“SELECT c FROM Customer c WHERE c.name = 'test Customer'”。这意味着它不使用参数,因此如果将其进一步转换为 SQL,则相应的准备好的语句将不使用参数。第二个版本翻译为 JPQL “SELECT c FROM Customer c WHERE c.name = :name”,所以我将使用参数。
-
经过更多测试后,我发现使用 JPQL 编写相同的查询并使用名称“' OR 'x'='x”会注入 JPQL。使用条件 API 时,OpenJPA 记录的生成的 JPQL 看起来完全相同。然而,OpenJPA 记录的实际 SQL 然后使用带有参数值“' OR 'x'='x”的预准备语句,而不是 JPQL 案例中的 ''。这意味着 SQL 注入在这里不起作用!不幸的是,我不知道这有多可靠。这似乎是一个未记录的功能。
-
提示:我刚刚尝试了querydsl.com,它的语法更加简洁易读。似乎默认使用参数来防范sql注入。
-
也就是说,如果不使用参数,是否可以进行SQL注入?