SQL Injection explicado

Introducción

La técnica de ataque de SQL Injectión (Inyección de SQL) explota una vulnerabilidad de la capa de acceso a datos de la aplicación. Es genérica a cualquier aplicación, no solo, como mucha gente cree, a aplicaciones web aunque debido al mayor acceso a través de internet así como al "descuido" de los desarrolladores web en muchas ocasiones a la hora de tratar los parametros GET ha hecho que este tipo de ataque se popularice en la web.

Anatomía del ataque

Un ataque basado en inyección de sql responde a una estructura de código en la que vamos a realizar una consulta o comando sobre una base de datos que contiene algunos parametros que nos suministra el usuario.

El problema se plantea cuando no se comprueba que dichos parametros sean válidos sino que el programador se ha limitado a concatenarlos en las partes correspondientes de la consulta, por ejemplo:

string consulta = "SELECT Count(*) FROM Users WHERE Name='" +
                   txtNombre.Text + "' AND Password = '" + txtPassword.Text + "'";

dicha consulta en principio devuelve el número de usuarios cuyo nombre y password coincide con los suministrados en los campos de texto indicados. El problema asociado a un atáque SQL Injection viene dado, no porque el código sea incorrecto sino porque se asume que los parametros de entrada son correctos, es decir, no se tienen en cuenta todas las posibilidades. Así si suponemos los siguientes valores para los campos

txtNombre.Text -> "Jorge"
txtPassword.Text -> "' OR '1' = '1"

la cadena resultante al ejecutar lo anterior será:

SELECT Count(*) FROM Users WHERE Name='Jorge' AND Password='' OR '1' = '1';

Que como vemos ha inyectado una consulta SQL que no estaba prevista (de ahí el nombre del ataque) y que modifica nuestra consulta original de forma que, sin importar el nombre de usuario o la contraseña devolverá el número total de usuarios de la base de datos por lo que si nuestro mecanismo se basa en comprobar si el número de campos devuelto es mayor que cero para permitir el acceso al usuario con este ataque nos lo habríamos saltado.

El atáque no acaba ahí, podemos encontrar ejemplos mucho peores y malintencionados, por ejemplo, siguiendo con el ejemplo anterior podríamos utilizar en el campo texto password lo siguiente:

'; DELETE * FROM Users; --';

que daría lugar a

SELECT Count(*) FROM Users WHERE Name='Jorge' AND Password='';
DELETE * FROM Users;
-- El resto de la query queda como un comentario;

que borrará todos los usuarios de nuestra base de datos.

Averiguando la estructura de la base de datos

En general las técnicas de inyectado de SQL se basan en la presencia de mensajes de error no controlados para intentar adivinar la estructura de la base de datos, por ejemplo si el registro de error de PHP o ASP está activado o bien mediante mensajes de excepción no controlados de la aplicación.

Existen diversas técnicas (que no voy a tratar aquí) para forzar errores cuya salida nos de pistas sobre la estructura de la base de datos, por ejemplo, indicandonos que una determinada tabla o campo no existe. En general las estrategias se basan en el uso de nombres más o menos comunes para determinadas tablas, por ejemplo es muy comun que la tabla que recoje los usuarios de la aplicación se llame "users" o "usuarios".

Previniendo SQL Injection

El primer paso para prevenir los ataques basados en SQL injection es ser consciente de que un usuario no siempre va a proporcionarte la entrada que tu piensas.

El segundo paso es realizar algo que es básico en seguridad: validación de datos. Para cada dato sea cual sea, proviniente de un usuario de la aplicación debemos asegurarnos de que sea válido y del tipo adecuado. Por ejemplo, Delphi tiene una función muy útil llamada QuotedStr que envuelve entre comillas el contenido de una variable de forma que si tenemos el ejemplo anterior

consulta := 'SELECT Count(*) FROM Users WHERE Name=" +
            QuotedSql(txtNombre.Text) + " AND Password = " + QuotedStr(txtPassword.Text);

que, para el caso txtPassword.Text -> "' OR '1' = '1'" nos devolvería lo siguiente

'SELECT Count(*) FROM Users WHERE Name='Jorge' AND Password = ''' OR ''1''=''1''';

que es una cadena válida en Delphi y que en SQL quiere decir que el password debe ser igual a la cadena OR '1'='1'

Para más información

  • Advanced SQL Injection - Pdf en inglés de Chris Anley explicando algunas de las técnicas más relevantes de SQL injection
  • Sql Injection - Pdf en español de la revista @rroba. Muy completo y con bastantes ejemplos prácticos. Muy recomendable.
  • Técnicas de Sql Injection - Pdf en españo. Otro muy interesante manual sobre SQL Injection que incluye además un breve repaso sobre SQL y trazas de salida de asp para sql injection.
6
Average: 6 (2 votes)
Your rating: None