Inyección SQL

Inyección SQL
Información sobre la plantilla
Parte de la familia Base de Datos
Inyeccion SQL.png

Inyección SQL es un mecanismo de infiltración de código malicioso que se vale de una vulnerabilidad informática que contiene una aplicación en el nivel de validación de las entradas para ejecutar determinadas consultas en una base de datos. El origen de la vulnerabilidad radica en el incorrecto chequeo y/o filtrado de las variables utilizadas en un programa que contiene, o bien genera, código SQL.

Descripción

Se dice que existe o se produjo una inyección SQL cuando, de alguna manera, se inserta o "inyecta" código SQL invasor dentro del código SQL programado, con el fin de alterar las funcionalidades normales de la aplicación y lograr así que se ejecute el código "invasor" incrustado, en la base de datos.

Este tipo de intrusión normalmente es de carácter malicioso, dañino o espía, por tanto es un problema de seguridad informática, y debe ser tomado en cuenta por el programador de la aplicación para poder prevenirlo. Un programa elaborado con descuido o con ignorancia del problema, podrá resultar ser vulnerable, y la seguridad del sistema (base de datos) podrá quedar eventualmente comprometida. La intrusión ocurre durante la ejecución del programa vulnerable.

La vulnerabilidad se puede producir automáticamente cuando un programa "arma descuidadamente" una sentencia SQL en tiempo de ejecución, o bien durante la fase de desarrollo, cuando el programador explicita la sentencia SQL a ejecutar en forma desprotegida. En cualquier caso, siempre que el programador necesite y haga uso de parámetros a ingresar por parte del usuario, a efectos de consultar una base de datos; ya que, justamente, dentro de los parámetros es donde se puede incorporar el código SQL intruso. Al ejecutarse la consulta en la base de datos, el código SQL inyectado también se ejecutará y podría efectuar múltiples operaciones sobre la aplicación, como insertar registros, modificar o eliminar datos, autorizar accesos violando formularios de autenticación, e incluso, ejecutar otro tipo de código malicioso en la computadora.

Ejemplos

Ej:1

Este ejemplo demuestra una posible violación de la entrada a un sistema sin conocer la contraseña. //se reciben los datos

$us=$_POST['usuario'];
$pass=$_POST['pass'];
//se construye la consulta (sin antes filtrar o limpiar los datos) esto es lo vulnerable
$sql="SELECT * FROM usuarios WHERE user = '$us' AND password='$pass'";
//…
if(mysql_fetch_array($exc)){
echo "Inicio de sesión correcto"; 
}

Este es el típico sistema de verificación de contraseñas. Utiliza la instrucción mysql_fetch_array(funcion de mysql, que devuelve falso si no hay ningún resultado, en la 'querry', o petición), así que si no hay ningún resultado donde el usuario y el password coincidan, el resultado es false

¿Cómo hacer que devuelva ‘’’true’’’ y permita entrar?

  • Con el password correcto.
  • Inyectando código malicioso.

Inyectando código… se haría algo así:

Esta es la petición que solo deja pasar si se conoce el password

SELECT * FROM usuarios WHERE user = '$us' AND password='$pass'

Ahora, ¿cómo se puede hacer que nos devuelva ‘’’true’’’ aunque no se conozca el password, sabiendo que solo se puede modificar $pass y $us? Con un poco de creatividad: En el formulario se introduce:

  • de usuario: yosba
  • de password: ' OR ='

La sentencia SQL recibirá:

SELECT * FROM usuarios WHERE user = 'yosba' AND password='' OR ''=''

Devolverá true, si hay algún resultado, y como NADA siempre es igual a NADA, devolverá ‘’’true’’’, y así se vurla la ignorancia del programador de este sistema y se entra sin credenciales.

Otros posibles valores que devuelven true son:

  • usuario: yosba AND /* password: */ ='
  • usuario: ' OR 1=1 //

Ej:2

Existe un parámetro "nombreUsuario" que contiene el nombre de usuario a consultar, una inyección SQL se podría provocar de la siguiente forma: El código SQL original y vulnerable es:

consulta := "SELECT * FROM usuarios WHERE nombre = '" + nombreUsuario + "';"

Si se escribe un nombre, por ejemplo "Jorge", nada anormal sucederá, la aplicación generaría una sentencia SQL similar a la siguiente, que es perfectamente correcta, donde se seleccionarían todos los registros con el nombre "Jorge" en la base de datos:

SELECT * FROM usuarios WHERE nombre = 'Jorge';

Pero si un intruso escribe como nombre de usuario a consultar:

Jorge'; DROP TABLE usuarios; SELECT * FROM datos WHERE nombre LIKE '%

Se generaría la siguiente consulta SQL:

SELECT * FROM usuarios WHERE nombre = 'Alicia';
DROP TABLE usuarios;
SELECT * FROM datos WHERE nombre LIKE '%';

En la base de datos se ejecutaría la consulta en el orden dado, se seleccionarían todos los registros con el nombre 'Jorge', se borraría la tabla 'usuarios' y finalmente se seleccionaría toda la tabla "datos", que no debería estar disponible para los usuarios web comunes. En resumen, cualquier dato de la base de datos puede quedar disponible para ser leído o modificado por un usuario malintencionado.

Ej:3 Cuando se reciben parámetros por el método ‘’’GET_[]’’’ y no se filtran correctamente las variables: En este caso se le pasa al archivo uno.php el parámetro id con valor 4 para ser seleccionado ese registro: <a href="uno.php?id=4">Noticia 4</a> ...

$result = mysql_query("SELECT * FROM UNATABLA WHERE id=".$_GET['id']); 
$row = mysql_fetch_row($result);

... Esto sería vulnerable, de manera que si alguien conociendo el nombre de una tabla hace algo así:

http://tusitio.cu/uno.php?id=1%20UNION%20DROP%20TABLE%20UNATABLA

¿Qué pasaría en realidad?: Se ejecutaría la siguiente consulta:

SELECT * FROM UNATABLA WHERE id=1 UNION DROP TABLE UNATABLA

donde primero selecciona un registro y luego elimina la tabla completa.

Formas de evitar los ataques por inyección SQL.

Importante: Qué hacer para evitar estos errores? La inyección SQL es fácil de evitar, por parte del programador, en la mayoría de los lenguajes de programación que permiten desarrollar aplicaciones web. Es muy recomendable siempre validar correctamente los datos evitando que los usuarios puedan entrar caracteres como \ / “ ‘ o cualquier otros que no se correspondan con los datos que se piden. Ej:1 En el lenguaje PHP, hay diferentes funciones que pueden contrarestar ataques mediante inyección SQL. Para MySQL, la función a usar es mysql_real_escape_string:

 $query_result = mysql_query("SELECT * FROM usuarios WHERE nombre = \"" . mysql_real_escape_string($nombre_usuario) . "\"");

Tanbién con str_replace("x","'",$var) También con $var=htmlentities(addslashes($var));// Por cada var, aunque por defecto el addslashes está implícito en la config de PHP.

Ej:2 Encriptando las passwords:

$user=$_POST["user"];
$pass=$_POST["pass"];
 
//…
 
$pass=md5($pass); // La encriptamos.
$sql = "SELECT * FROM usuarios WHERE usuario='$user' AND contra='$pass'";

Suponiendo que en la Base de Datos esté almacenada la password encriptada; antes de colocar el parámetro pass en la consulta la encriptamos, de manera que si un malintencionado entrara un ‘ OR ‘’=’ el parámetro pass sería ‘ OR ‘’=’ pero al encriptarla sería como d20da3888278ec814f6a837f260b60df, entonces la consulta generada sería como:

SELECT * FROM usuarios WHERE usuario='yosba' AND contra='d20da3888278ec814f6a837f260b60df'

Y no lo que pretendía el intruso:

SELECT usuario, contra, tipo FROM usuarios WHERE usuario='yosba' AND contra='’ OR ‘’=’'

Fuentes