Читать книгу Desarrollo de aplicaciones web con Jakarta EE - César Francisco Castillo - Страница 29
2.6.4 Consultas dinámicas y sus problemas
ОглавлениеGeneralmente, cuando trabajamos con consultas, sabemos cómo debemos construirlas para obtener los resultados deseados. No obstante, en otras situaciones no podremos saber o anticipar de qué manera deben ser construidas. Estas situaciones se presentan debido a que el usuario puede especificar un número variable de parámetros a la hora de trabajar en la aplicación. En ese caso, poder construir una cadena en tiempo de ejecución en función de los parámetros especificados por el usuario y convertirla luego en una consulta es una característica más que interesante. Estas consultas reciben el nombre de “consultas dinámicas”, ya que son definidas en tiempo de ejecución mediante la construcción de una cadena en partes, como se puede apreciar en la Figura 2.6.
Figura 2.6 Construcción de consultas dinámicas.
Nota: Gráfico adaptado de https://www.arquitecturajava.com/
Sin embargo, el precio que hay que pagar por esta característica es muy elevado en términos de rendimiento, ya que todas estas construcciones deben ser analizadas y luego traducidas a su correspondiente versión en SQL.
Observe el método buscarPorNombre(), que retorna un listado de facultades de acuerdo a su nombre y abreviatura. Aquí podemos ver que la cadena consulta se construye a partir de la concatenación de fragmentos de cadenas y nombres de parámetros. Esto tiene el problema de que por cada invocación la cadena será construida nuevamente.
Por otra parte, este código es frágil y propenso a las inyecciones SQL debido a que la consulta no está siendo parametrizada correctamente.
Probemos su funcionamiento ejecutándola desde el método main() con dos argumentos válidos:
Con estos valores como argumentos, la consulta generada tendría el siguiente aspecto:
SELECT idfacultad, abreviatura, nombre FROM Facultad WHERE ((nombre = ?) AND (abreviatura = ?))
y su resultado se observa en la Figura 2.7
Figura 2.7 Ejecución normal de consulta.
Ahora bien, si reemplazamos el valor del parámetro abreviatura por una cadena similar a “ ‘ or ‘ ’=’ ”, obtendremos una consulta con una condición que siempre será evaluada como verdadera, tal como se puede apreciar en el siguiente fragmento de código:
servicio.buscarPorNombre(“Facultad de Ciencias Exactas y Tecnologías”, “ ‘ or ‘ ‘=’ “);
Así, la nueva consulta que se genera tendría el siguiente aspecto:
SELECT idfacultad, abreviatura, nombre FROM Facultad WHERE (((nombre = ?) AND (abreviatura = ?)) OR (? = ?))
Como resultado, obtendremos el listado completo de las Facultades debido a una inyección SQL.
Figura 2.8 Salida luego de una inyección SQL.
Para solucionar este problema, debemos recurrir, en primera instancia, a las consultas parametrizadas. Para ello modificaremos el método buscarPorNombre(), como se puede apreciar a continuación:
Probemos de nuevo la ejecución del método main(), tanto con argumentos válidos como con no válidos, y veremos que la consulta que obtenemos siempre es la misma.
SELECT idfacultad, abreviatura, nombre FROM Facultad WHERE ((nombre = ?) AND (abreviatura = ?))
Este ha sido un pequeño ejemplo construido intencionalmente para que el lector pueda ver lo peligroso que resulta construir consultas dinámicas mediante concatenación.
En las próximas secciones estudiaremos Criteria API, que nos permite resolver casos como este y muchos otros de mejor manera.