JPA SQL Injection y sus problemas

JPA SQL Injection es un problema del que muchos desarrolladores se olvidan ,ya que consideran que JPA esta totalmente protegido contra inyeccion de SQL. ¿Es esto cierto o podemos vernos afectados?. La realidad es que no estamos totalmente protegidos . Depende mucho de como se haya construido el código . Vamos a ver un ejemplo sencillo que nos ayude a entenderlo. Supongamos que tenemos una base de datos con los siguientes datos.

Vamos a construirnos un ejemplo con JPA que nos permita seleccionar datos de la tabla. El primer paso es definir las dependencias de Maven que vamos a utilizar.


<dependencies>

		<dependency>
			<groupId>org.hibernate.javax.persistence</groupId>
			<artifactId>hibernate-jpa-2.0-api</artifactId>
			<version>1.0.1.Final</version>
		</dependency>

	<dependency>
		<groupId>org.hibernate</groupId>
		<artifactId>hibernate-core</artifactId>
		<version>5.2.10.Final</version>
	</dependency>
	
	<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.42</version>
</dependency>
	
	</dependencies><dependencies>

		<dependency>
			<groupId>org.hibernate.javax.persistence</groupId>
			<artifactId>hibernate-jpa-2.0-api</artifactId>
			<version>1.0.1.Final</version>
		</dependency>

	<dependency>
		<groupId>org.hibernate</groupId>
		<artifactId>hibernate-core</artifactId>
		<version>5.2.10.Final</version>
	</dependency>
	
	<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.42</version>
</dependency>
	
	</dependencies>

El siguiente paso es definir la clase de Entidad que vamos a utilizar:


package com.arquitecturajava;


import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Persona {
	
	
	@Id
	private String nombre;
	private String apellidos;
	private int edad;
	
	public String getNombre() {
		return nombre;
	}
	public void setNombre(String nombre) {
		this.nombre = nombre;
	}
	public String getApellidos() {
		return apellidos;
	}
	public void setApellidos(String apellidos) {
		this.apellidos = apellidos;
	}
	public int getEdad() {
		return edad;
	}
	public void setEdad(int edad) {
		this.edad = edad;
	}
	public Persona(String nombre, String apellidos, int edad) {
		super();
		this.nombre = nombre;
		this.apellidos = apellidos;
		this.edad = edad;
	}
	public Persona() {
		super();
	}
	
}

Por último nos queda ver como queda el programa principal que va a realizar una consulta:


package com.arquitecturajava;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.TypedQuery;

public class Principal {

	public static void main(String[] args) {

		seleccionarPersona("pedro", "perez");

	}

	private static void seleccionarPersona(String nombre, String apellidos) {
		EntityManagerFactory emf = Persistence.createEntityManagerFactory("UnidadPersonas");
		EntityManager em = emf.createEntityManager();
		try {
			String sql = "select p from Persona p ";
			if (nombre != null || apellidos != null) {
				sql += " where ";
			}
			if (nombre != null) {

				sql +=  " nombre='" + nombre + "'";
			}
			if (apellidos != null) {

				if(nombre!=null) {
					sql += " and  apellidos='" + apellidos + "'";
				}else{
					
					sql += "  apellidos='" + apellidos + "'";
				}
				
			}

			TypedQuery<Persona> consulta = em.createQuery(sql, Persona.class);

			List<Persona> lista = consulta.getResultList();
			lista.forEach((p) -> {

				System.out.println(p.getNombre());

			});
		} catch (Exception e) {

			e.printStackTrace();
		} finally {
			em.close();

		}
	}
}

JPA SQL Injection

El programa principal se encarga de realizar una consulta JPA utilizando SQL dinámico y construyendo la consulta por partes.

 

En este caso estamos buscando una persona por nombre y apellidos , así pues pasamos ambos parámetros. El resultado por la consola confirma que la consulta funciona de forma correcta y que solo el registro de pedro cumple.

Ahora bien estamos ante una situación  comprometida ya que estamos construyendo la consulta de forma dinámica y nos pueden realizar un ataque de SQL Injection. ¿Cómo nos pueden atacar ? . Muy sencillo es suficiente con modificar el parámetro que recibimos  de apellidos por algo como “‘ or “=” “.

 

Esta modificación añadirá a la SQL una condición que siempre se cumple (inyectandola).


seleccionarPersona("pedro", <strong>"' or ''='");</strong>

La nueva SQL generada será:

select persona0_.nombre as nombre1_0_, persona0_.apellidos as apellido2_0_, persona0_.edad as edad3_0_ from Persona persona0_ where persona0_.nombre=’pedro’ and persona0_.apellidos=” or ”=”

El resultado por pantalla cambia y nos muestra todos los usuarios de la tabla  :

Tenemos un problema de JPA SQL Injection y hemos recibido un ataque. Para solventar estos casos deberemos utilizar el API de criteria que veremos en el próximo artículo.

Otros artículos relacionados:

  1. Introducción a Spring Data y JPA
  2. Un ejemplo de JPA Entity Graph
  3. JPA Single Table Inheritance
  4. JPA WikiPedia
It's only fair to share...Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedIn

About Cecilio Álvarez Caules

Cecilio Álvarez Caules Sun Certified Enterprise Architech (J2EE/JEE).

Sin comentarios todavía.

Deja un comentario