如何使用JPA和Hibernate防止SQL注入?

Mr.*_*hoi 23 java sql hibernate jpa sql-injection

我正在使用hibernate开发一个应用程序.当我尝试创建一个登录页面时,出现了Sql Injection的问题.我有以下代码:

@Component
@Transactional(propagation = Propagation.SUPPORTS)
public class LoginInfoDAOImpl implements LoginInfoDAO{

@Autowired
private SessionFactory sessionFactory;      
@Override
public LoginInfo getLoginInfo(String userName,String password){
    List<LoginInfo> loginList = sessionFactory.getCurrentSession().createQuery("from LoginInfo where userName='"+userName+"' and password='"+password+"'").list();
    if(loginList!=null )
        return loginList.get(0);
    else return null;   
          }
      }
Run Code Online (Sandbox Code Playgroud)

在这种情况下如何防止Sql注入?loginInfo表的create table语法如下:

create table login_info
  (user_name varchar(16) not null primary key,
  pass_word varchar(16) not null); 
Run Code Online (Sandbox Code Playgroud)

Pet*_*sik 22

Query q = sessionFactory.getCurrentSession().createQuery("from LoginInfo where userName = :name");
q.setParameter("name", userName);
List<LoginInfo> loginList = q.list();
Run Code Online (Sandbox Code Playgroud)

你也有其他选择,请参阅mkyong的这篇好文章.


dim*_*ies 17

您需要使用命名参数来避免sql注入.另外(与sql注入没有任何关系,但一般都有安全性)不返回第一个结果但是使用getSingleResult所以如果由于某种原因有多个结果,查询将失败并出现NonUniqueResultException并且登录将不会成功

 Query query= sessionFactory.getCurrentSession().createQuery("from LoginInfo where userName=:userName  and password= :password");
 query.setParameter("username", userName);
 query.setParameter("password", password);
 LoginInfo loginList = (LoginInfo)query.getSingleResult();
Run Code Online (Sandbox Code Playgroud)


Vla*_*cea 5

什么是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();
    });
}
Run Code Online (Sandbox Code Playgroud)

现在,如果有人试图破解此查询:

getPostCommentByReview("1 AND 1 >= ALL ( SELECT 1 FROM pg_locks, pg_sleep(10) )");
Run Code Online (Sandbox Code Playgroud)

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) ))]
Run Code Online (Sandbox Code Playgroud)

JPQL注射

如以下示例所示,使用JPQL或HQL查询时,也可能发生SQL注入:

public List<Post> getPostsByTitle(String title) {
    return doInJPA(entityManager -> {
        return entityManager.createQuery(
            "select p " +
            "from Post p " +
            "where" +
            "   p.title = '" + title + "'", Post.class)
        .getResultList();
    });
}
Run Code Online (Sandbox Code Playgroud)

上面的JPQL查询不使用绑定参数,因此容易受到SQL注入的攻击。

看看执行此JPQL查询时会发生什么情况:

List<Post> posts = getPostsByTitle(
    "High-Performance Java Persistence' and " +
    "FUNCTION('1 >= ALL ( SELECT 1 FROM pg_locks, pg_sleep(10) ) --',) is '"
);
Run Code Online (Sandbox Code Playgroud)

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:[()]
Run Code Online (Sandbox Code Playgroud)

动态查询

您应该避免使用String串联的查询来动态构建查询:

String hql = " select e.id as id,function('getActiveUser') as name from " + domainClass.getName() + " e ";
Query query=session.createQuery(hql);
return query.list();
Run Code Online (Sandbox Code Playgroud)

如果要使用动态查询,则需要使用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)
    )
);
Run Code Online (Sandbox Code Playgroud)

返回entityManager.createQuery(query).getResultList();

有关更多详细信息,请查看本文