我正在使用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;
}
}
如何在这种情况下阻止Sql Injection?loginInfo表的create table语法如下:
create table login_info
(user_name varchar(16) not null primary key,
pass_word varchar(16) not null);
答案 0 :(得分:22)
Query q = sessionFactory.getCurrentSession().createQuery("from LoginInfo where userName = :name");
q.setParameter("name", userName);
List<LoginInfo> loginList = q.list();
你也有其他选择,请参阅mkyong的这个好article。
答案 1 :(得分: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();
答案 2 :(得分:5)
当恶意攻击者可以操纵查询时,就会发生SQL注入 构建过程,以便他可以执行与以下语句不同的SQL语句 应用程序开发人员最初的意图
解决方案非常简单直接。您只需要确保始终使用绑定参数即可:
$ kubectl run busybox --image busybox:1.28 --restart=Never --rm -it busybox -- sh
If you don't see a command prompt, try pressing enter.
/ # nslookup kubernetes.default
Server: 10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name: kubernetes.default
Address 1: 10.96.0.1 kubernetes.default.svc.cluster.local
/ # exit
pod "busybox" deleted
现在,如果有人试图破解此查询:
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();
});
}
将防止SQL注入攻击:
getPostCommentByReview("1 AND 1 >= ALL ( SELECT 1 FROM pg_locks, pg_sleep(10) )");
使用JPQL或HQL查询时,也可能发生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注入的攻击。</ p>
查看执行此JPQL查询时发生的情况:
public List<Post> getPostsByTitle(String title) {
return doInJPA(entityManager -> {
return entityManager.createQuery(
"select p " +
"from Post p " +
"where" +
" p.title = '" + title + "'", Post.class)
.getResultList();
});
}
Hibernate执行以下SQL查询:
List<Post> posts = getPostsByTitle(
"High-Performance Java Persistence' and " +
"FUNCTION('1 >= ALL ( SELECT 1 FROM pg_locks, pg_sleep(10) ) --',) is '"
);
您应该避免使用String串联的查询来动态构建查询:
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:[()]
如果要使用动态查询,则需要使用Criteria API:
String hql = " select e.id as id,function('getActiveUser') as name from " + domainClass.getName() + " e ";
Query query=session.createQuery(hql);
return query.list();
返回entityManager.createQuery(query).getResultList();
有关更多详细信息,请查看this article。
答案 3 :(得分:0)
我们应该总是尝试使用存储过程来防止SQL注入..如果存储过程不可行;我们应该尝试准备陈述。
答案 4 :(得分:0)
HQL中的位置参数
查询hqlQuery = session.createQuery(&#34;来自订单作为订单,其中orders.id =?&#34;);
列出结果= hqlQuery.setString(0,&#34; 123-ADB-567-QTWYTFDL&#34;)。list();
HQL中的命名参数
查询hqlQuery = session.createQuery(&#34;来自Employees as emp,其中emp.incentive&gt;:incentive&#34;);
列出结果= hqlQuery.setLong(&#34;激励&#34;,新龙(10000))。list();
HQL中的命名参数列表
List items = new ArrayList(); items.add(&#34;书&#34); items.add(&#34;时钟&#34); items.add(&#34;油墨&#34);
列出结果= session.createQuery(&#34;从购物车作为购物车,其中cart.item在(:itemList)&#34;)。setParameterList(&#34; itemList&#34;,items).list()
HQL中的JavaBean
查询hqlQuery = session.createQuery(&#34;来自Books书籍,其中book.name =:name和book.author =:author&#34;);
列出结果= hqlQuery.setProperties(javaBean).list();
查询sqlQuery = session.createSQLQuery(&#34;从书籍中选择*,作者=?&#34;);
列出结果= sqlQuery.setString(0,&#34; Charles Dickens&#34;)。list();
答案 5 :(得分:0)
我想在这里添加一个特殊的SQL注入,可以在搜索中使用Like查询。
让我们说我们有一个查询字符串,如下所示:
queryString = queryString + " and c.name like :name";
设置name参数时,大多数人通常会使用它。
query.setParameter("name", "%" + name + "%");
现在,如上所述,由于TypedQuery不能注入传统参数“ 1 = 1 ”,因此默认情况下,Hibernate将对其进行处理。
但是这里可能存在特殊的SQL注入,这是因为LIKE查询结构使用了下划线
下划线通配符用于精确匹配其中的一个字符 MySQL的含义,例如,从用户喜欢的用户中选择* 'abc_de';这将产生以abc开头,以end结尾的用户输出 带有de,并且之间只有1个字符。
现在,如果在我们的情况下,如果我们设置
以此类推。
理想解决方案:
为减轻这种情况,我们需要使用前缀对所有下划线进行转义。
___将变成\ _ \ _ \ _(相当于3个原始下划线)
反之亦然,反之亦然,还会导致需要%的转义的注入。