Una de las vulnerabilidades comunes que vemos en las auditorías de código es la presencía de Inyecciones de código SQL. Hoy contaremos un caso particular pero muy didáctico.
Habitualmente este tipo de vulnerabilidades se deben a que el programador utiliza querys en las que concatena variables obtenidas del usuario sin realizar una validación previa adecuada. El ejemplo típico de este tipo de consultas es el siguiente:
String id = request.getParameter(“producto”);
String consulta=”SELECT * FROM registros WHERE id=” + id;
Statement query = conn.createStatement();
ResultSet resultado = query.executeQuery(consulta);
Como podemos apreciar se está concatenando a la consulta el parametro “id“, obtenido directamente de la entrada de usuario a través de “request.getParameter“.
La solución que se plantea siempre es la utilización de consultas parametrizadas, más conocidas como PreparedStatement, hay muchos recursos en la red sobre ellas (hoy estamos en JAVA):
http://download.oracle.com/javase/6/docs/api/java/sql/PreparedStatement.html
http://prepared-statement.blogspot.com/
Sin embargo esto no es la panacea, una implementación incorrecta de las consultas parametrizadas puede llevar al traste la fortificación del aplicativo con un riesgo adicional asociado: la falsa sensación de seguridad.
En el siguiente ejemplo vemos una mala implementación de consulta parametrizada:
String id = request.getParameter(“producto”);
String consulta=”SELECT * FROM registros WHERE id=” + id;
PreparedStatement consultaprep = conn.prepareStatement(consulta);
ResultSet resultado = consultaprep.executeQuery();
Como podemos apreciar el programador hace uso de “PreparedStatement” pero mantiene la filosofía del primer ejemplo: contatena las variables sin realizar un filtrado previo.
Soluciones hay muchas y muy variadas en función de las condiciones de entorno. El ejemplo de hoy es muy sencillo y podría resolverse limpiamente utilizando “PreparedStatement” de la siguiente manera:
String id = request.getParameter(“producto”);
String consulta = “SELECT * FROM registros WHERE id = ?”;
PreparedStatement consultaprep = conn.prepareStatement(consulta);
consultaprep.setString(1, id);
ResultSet resultado = consultaprep.executeQuery();
Como vemos la consulta no concatena la variable. Una ventaja adicional es que este tipo de consultas habitualmente mejoran también el rendimiento. Como nota, destacar que en entornos complejos la solución no es tan simple.