Mostrando entradas con la etiqueta Groovy. Mostrar todas las entradas
Mostrando entradas con la etiqueta Groovy. Mostrar todas las entradas

viernes, 16 de abril de 2010

Cláusulas dinámicas en Groovy: versión a prueba de Inyección SQL

Hola,

En una entrada anterior comentamos cómo crear dinámicamente una sentencia SQL partiendo de una lista de valores para una columna.
Ya advertimos que debido al uso de la concatenación de cadenas, el método sólo era válido si teníamos totalmente controlados los parámetros de entrada, ya que si no podíamos sufrir un ataque de Inyección SQL, pero con un poco más de trabajo, podemos crear una solución que nos proteja contra estos ataques, y es la que presentamos ahora:
Suponiendo la misma tabla que en la entrada anterior, lo que haremos en este caso es que la cadenas que vamos a concatenar colocará interrogantes (?) donde deberían ir los valores y luego pasaremos la lista de valores a la sentencia SQL para que la ejecute. Haciéndolo así Groovy usará un PreparedStatement para asignar los valores de los parámetros y estaremos protegidos contra un posible ataque de Inyección SQL. Veámoslo:

def parametrosMultiples = 'ABE,MUL,TAC,FRO' // o podría ser sólo 'ABE' o null
def listaParametrosMultiples = parametrosMultiples.split(',')
def condicionOR = listaParametrosMultiples.collect({'?'}).join(' OR TAB_CAMPO=')
def clausulaWhere = parametrosMultiples ? "WHERE TAB_CAMPO=${condicionOR}" : ''
def sentencia = "SELECT * FROM TAPP_TABLA ${clausulaWhere}" 
println sentencia
Resultado:
SELECT * FROM TAPP_TABLA WHERE TAB_CAMPO=? OR TAB_CAMPO=? OR TAB_CAMPO=? OR TAB_CAMPO=?

Y al ejecutarlo, le pasamos la lista de valores como parámetros:
//...
def sql = new Sql(ds); // ds es un DataSource que habremos obtenido de algún lado
sql.eachRow( sentencia
     ,Arrays.asList(listaParametrosMultiples)
     ,{
        ... // Aquí haremos algo para
        // cada fila resultado (it)
      }
     );
//...

Básicamente lo único que hemos hecho es usar la función collect para sustituir los valores del array de parámetros por interrogantes, y luego convertir el array en una lista, con Arrays.asList() para poder pasárselo al método eachRow.

Con estos sencillos cambios, cerramos un posible agujero en la seguridad.

Eso es todo de momento. ¡Feliz fin de semana!

EJ
Happy Coding!

jueves, 18 de marzo de 2010

Un poco de magia Groovy para construir clausulas SQL dinámicas

Para empezar, una entrada breve con un truco que aprendí/usé hace poco para construir una sentencia SQL dinámica usando Groovy. El problema reducido es el siguiente:
  • Dada una sentencia SQL que ha de hacer una comparación de una columna y cero, uno o varios valores, construir dinámicamente la sentencia teniendo en cuenta si se le pasa algún valor o varios.
Empezamos con la sentencia, que sería algo tal que así:
SELECT * FROM TAPP_TABLA WHERE TAB_CAMPO='VALOR'
donde podemos pasar cero, uno o varios valores.

La solución típica tiene unos cuantos if/else anidados, concatenaciones de cadenas etc. pero gracias a la mágia de Groovy, tenemos una solución sencilla y directa:

def parametrosMultiples = 'ABE,MUL,TAC,FRO' // o podría ser sólo 'ABE' o null
def condicionOR = parametrosMultiples?.split(',')?.join('\' OR TAB_CAMPO=\'')
def clausulaWhere = parametrosMultiples ? "WHERE TAB_CAMPO='${condicionOR}'" : ''
def sentencia = "SELECT * FROM TAPP_TABLA ${clausulaWhere}" 
println sentencia

Resultado:
SELECT * FROM TAPP_TABLA WHERE TAB_CAMPO='ABE' OR TAB_CAMPO='MUL' OR TAB_CAMPO='TAC' OR TAB_CAMPO='FRO'

Paso a paso:
  • En la primera linea: lo primero que hacemos es aplicar un split a la cadena que nos llega, lo cual la separa en trozos y lo convierte en una lista de valores.
  • En la misma linea: acto seguido hacemos un join de la lista lo cual nos vuelve a juntar todos los valores de la lista y los devuelve concatenados y separados por el separador que le indicamos. El separador está pensado para que enlace bien un valor con el siguiente, y la parte de inicio y fin se la pondremos después.
  • Resaltar que hemos añadido el interrogante ?. a ambas operaciones ya que si no lo hicieramos y el valor de la cadena parametrosMultiples es null, saltaría una NullPointerException.
  • Para evitar añadir la clausula WHERE si no es necesario, usamos el operador de asignación condicional: condición ? valorSiTrue : valorSiFalso.
  • Por último, interpolamos el valor de la variable clausulaWhere al final de la sentencia, haciendo uso de las facilidades de Groovy para introducir valores de variables en cadenas (usando dobles comillas y ${}). 
Veremos que si cambiamos el valor de parametrosMultiples por un valor simple o por null, la cadena devuelta es la correcta y no se produce ningún error.

Bueno, espero que este truquillo os de alguna idea de como poder usar la magia de Groovy para hacer algunas cosas de forma más sencilla.

¡Hasta la próxima!

PD: Resaltar que este truco es válido si nosotros mismos controlamos los valores que puede tomar la variable parametrosMultiples, ya que si no, al estar concatenando cadenas seríamos susceptibles a la Inyección SQL.