Je développe une application utilisant Hibernate. Lorsque je tente de créer une page de connexion, le problème de Sql Injection se pose . J'ai le code suivant:
@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;
}
}
Comment éviter l'injection SQL dans ce scénario? La syntaxe de création de table de la table loginInfo est la suivante:
create table login_info
(user_name varchar(16) not null primary key,
pass_Word varchar(16) not null);
Query q = sessionFactory.getCurrentSession().createQuery("from LoginInfo where userName = :name");
q.setParameter("name", userName);
List<LoginInfo> loginList = q.list();
Vous avez d’autres options aussi, voyez ce Nice article de.
Vous devez utiliser des paramètres nommés pour éviter les injections SQL. De plus (rien à voir avec l'injection SQL mais avec la sécurité en général) ne renvoie pas le premier résultat mais utilise getSingleResult donc s'il y a plus d'un résultat pour une raison quelconque, la requête échouera avec NonUniqueResultException et connexion ne sera pas réussie
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();
L'injection SQL se produit lorsqu'un attaquant non autorisé peut manipuler la requête processus de construction afin qu’il puisse exécuter une instruction SQL différente de celle de ce que le développeur de l'application a prévu à l'origine
La solution est très simple et directe. Vous devez juste vous assurer que vous utilisez toujours les paramètres de liaison:
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();
});
}
Maintenant, si certains essaient de pirater cette requête:
getPostCommentByReview("1 AND 1 >= ALL ( SELECT 1 FROM pg_locks, pg_sleep(10) )");
l'attaque par injection SQL sera empêchée:
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) ))]
L'injection SQL peut également se produire lors de l'utilisation de requêtes JPQL ou HQL, comme le montre l'exemple suivant:
public List<Post> getPostsByTitle(String title) {
return doInJPA(entityManager -> {
return entityManager.createQuery(
"select p " +
"from Post p " +
"where" +
" p.title = '" + title + "'", Post.class)
.getResultList();
});
}
La requête JPQL ci-dessus n’utilise pas de paramètres de liaison, elle est donc vulnérable à l’injection SQL.
Découvrez ce qui se passe lorsque j'exécute cette requête JPQL comme ceci:
List<Post> posts = getPostsByTitle(
"High-Performance Java Persistence' and " +
"FUNCTION('1 >= ALL ( SELECT 1 FROM pg_locks, pg_sleep(10) ) --',) is '"
);
Hibernate exécute la requête SQL suivante:
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:[()]
Vous devriez éviter les requêtes qui utilisent la concaténation de chaînes pour construire la requête de manière dynamique:
String hql = " select e.id as id,function('getActiveUser') as name from " + domainClass.getName() + " e ";
Query query=session.createQuery(hql);
return query.list();
Si vous souhaitez utiliser des requêtes dynamiques, vous devez utiliser l'API des critères à la place:
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 (requête) .getResultList ();
Pour plus de détails, consultez cet article .
Nous devrions toujours essayer d’utiliser des procédures stockées en général pour empêcher l’injection SQL. Si les procédures stockées ne sont pas possibles; nous devrions essayer de préparer des déclarations.
Paramètre de position dans HQL
Requête hqlQuery = session.createQuery ("à partir d'ordres en tant qu'ordres où orders.id =?");
Résultats de la liste = hqlQuery.setString (0, "123-ADB-567-QTWYTFDL"). List ();
paramètre nommé en HQL
Requête hqlQuery = session.createQuery ("de Employees as emp where emp.incentive>: incentive");
Résultats de la liste = hqlQuery.setLong ("incentive", new Long (10000)). List ();
liste de paramètres nommés dans HQL
Liste des éléments = new ArrayList (); items.add ("livre"); items.add ("horloge"); items.add ("encre");
Liste des résultats = session.createQuery ("de Cart en tant que panier où cart.item in (: itemList)"). SetParameterList ("itemList", items) .list ();
JavaBean en HQL
Requête hqlQuery = session.createQuery ("à partir de livres en tant que livres où book.name =: name et book.author =: author");
Résultats de la liste = hqlQuery.setProperties (javaBean) .list ();
Requête sqlQuery = session.createSQLQuery ("Select * from Books where author =?");
Résultats de la liste = sqlQuery.setString (0, "Charles Dickens"). List ();