什么是 SQL 注入?
当恶意攻击者可以操纵查询构建过程以便执行与应用程序开发人员最初预期不同的 SQL 语句时,就会发生 SQL 注入
如何防止 SQL 注入攻击
解决方案非常简单直接。您只需要确保始终使用绑定参数:
public PostComment getPostCommentByReview(String review) {
return doInJPA(entityManager -> {
return entityManager.createQuery("""
select p
from PostComment p
where p.review = :review
""", PostComment.class)
.setParameter("review", review)
.getSingleResult();
});
}
现在,如果有人试图破解这个查询:
getPostCommentByReview("1 AND 1 >= ALL ( SELECT 1 FROM pg_locks, pg_sleep(10) )");
SQL注入攻击将被阻止:
Time:1, Query:["select postcommen0_.id as id1_1_, postcommen0_.post_id as post_id3_1_, postcommen0_.review as review2_1_ from post_comment postcommen0_ where postcommen0_.review=?"], Params:[(1 AND 1 >= ALL ( SELECT 1 FROM pg_locks, pg_sleep(10) ))]
JPQL 注射液
SQL 注入也可能在使用 JPQL 或 HQL 查询时发生,如以下示例所示:
public List<Post> getPostsByTitle(String title) {
return doInJPA(entityManager -> {
return entityManager.createQuery(
"select p " +
"from Post p " +
"where" +
" p.title = '" + title + "'", Post.class)
.getResultList();
});
}
上面的 JPQL 查询没有使用绑定参数,因此很容易受到SQL 注入的攻击。
看看当我像这样执行这个 JPQL 查询时会发生什么:
List<Post> posts = getPostsByTitle(
"High-Performance Java Persistence' and " +
"FUNCTION('1 >= ALL ( SELECT 1 FROM pg_locks, pg_sleep(10) ) --',) is '"
);
Hibernate 执行以下 SQL 查询:
Time:10003, QuerySize:1, BatchSize:0, Query:["select p.id as id1_0_, p.title as title2_0_ from post p where p.title='High-Performance Java Persistence' and 1 >= ALL ( SELECT 1 FROM pg_locks, pg_sleep(10) ) --()=''"], Params:[()]
动态查询
您应该避免使用字符串连接来动态构建查询的查询:
String hql = " select e.id as id,function('getActiveUser') as name from " + domainClass.getName() + " e ";
Query query=session.createQuery(hql);
return query.list();
如果要使用动态查询,则需要使用 Criteria API:
Class<Post> entityClass = Post.class;
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple> query = cb.createTupleQuery();
Root<?> root = query.from(entityClass);
query.select(
cb.tuple(
root.get("id"),
cb.function("now", Date.class)
)
);
return entityManager.createQuery(query).getResultList();