best - sql injection java example
¿Cómo prevenir la inyección SQL con JPA e Hibernate? (5)
¿Qué es la inyección SQL?
La inyección SQL se produce cuando un atacante malintencionado puede manipular el proceso de creación de consultas para que pueda ejecutar una declaración SQL diferente a la que el desarrollador de la aplicación había pensado originalmente.
Cómo prevenir el ataque de inyección SQL.
La solución es muy simple y directa. Solo tienes que asegurarte de usar siempre los parámetros de enlace:
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();
});
}
Ahora, si alguno está tratando de hackear esta consulta:
getPostCommentByReview("1 AND 1 >= ALL ( SELECT 1 FROM pg_locks, pg_sleep(10) )");
El ataque de inyección de SQL se evitará:
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) ))]
Inyección de JPQL
La inyección SQL también puede ocurrir cuando se utilizan consultas en JPQL o HQL, como lo demuestra el siguiente ejemplo:
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 consulta de JPQL anterior no usa parámetros de enlace, por lo que es vulnerable a la inyección de SQL.
Echa un vistazo a lo que sucede cuando ejecuto esta consulta JPQL de esta manera:
List<Post> posts = getPostsByTitle(
"High-Performance Java Persistence'' and " +
"FUNCTION(''1 >= ALL ( SELECT 1 FROM pg_locks, pg_sleep(10) ) --'',) is ''"
);
Hibernate ejecuta la siguiente consulta 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:[()]
Consultas dinámicas
Debe evitar las consultas que utilizan la concatenación de cadenas para generar la consulta de forma dinámica:
String hql = " select e.id as id,function(''getActiveUser'') as name from " + domainClass.getName() + " e ";
Query query=session.createQuery(hql);
return query.list();
Si desea usar consultas dinámicas, necesita usar Criteria API en su lugar:
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 ();
Para más detalles, echa un vistazo a este artículo .
Estoy desarrollando una aplicación utilizando hibernación. Cuando intento crear una página de inicio de sesión, surge el problema de la inyección de SQL. Tengo el siguiente código:
@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;
}
}
¿Cómo evitaré la inyección de SQL en este escenario? La sintaxis de creación de tablas de la tabla loginInfo es la siguiente:
create table login_info
(user_name varchar(16) not null primary key,
pass_word varchar(16) not null);
Parámetro posicional en HQL
Consulta hqlQuery = session.createQuery ("de Pedidos como pedidos donde orders.id =?");
Lista de resultados = hqlQuery.setString (0, "123-ADB-567-QTWYTFDL"). List ();
parámetro nombrado en HQL
Consulta hqlQuery = session.createQuery ("de Empleados como emp donde inc.incentive>: incentive");
Listar resultados = hqlQuery.setLong ("incentive", new Long (10000)) list ();
lista de parámetros nombrados en HQL
Listar artículos = new ArrayList (); items.add ("libro"); items.add ("reloj"); items.add ("tinta");
Listar resultados = session.createQuery ("desde el Carrito como el carrito donde cart.item en (: itemList)"). SetParameterList ("itemList", items) .list ();
JavaBean en HQL
Consulta hqlQuery = session.createQuery ("de Libros como libros donde book.name =: name and book.author =: author");
Listar resultados = hqlQuery.setProperties (javaBean) .list ();
- SQL nativo
Query sqlQuery = session.createSQLQuery ("Select * from Books donde author =?");
Listar resultados = sqlQuery.setString (0, "Charles Dickens"). List ();
Es necesario utilizar parámetros con nombre para evitar la inyección de SQL. Además (no tiene nada que ver con la inyección de SQL, sino con la seguridad en general), no devuelva el primer resultado, pero use getSingleResult, por lo que si hay más de un resultado por algún motivo, la consulta fallará con la excepción NonUniqueResultException y el inicio de sesión no será exitoso
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();
Siempre debemos tratar de utilizar los procedimientos almacenados en general para evitar la inyección de SQL. Si los procedimientos almacenados no son posibles; Deberíamos intentarlo para las declaraciones preparadas.
Query q = sessionFactory.getCurrentSession().createQuery("from LoginInfo where userName = :name");
q.setParameter("name", userName);
List<LoginInfo> loginList = q.list();
Tienes otras opciones también, mira este bonito article de mkyong.