BlogStyle

BlogStyle

Por una blogósfera con estilo

Ser supersticioso es de mala suerte

Inyección SQL en Login

Miércoles, Mayo 14th, 2008 - 14:36 | Guardado en: MySQL, PHP, Seguridad Informática

Inyección SQL

Paseando por foros de programación web me eh dado cuenta que normalmente los programadores casi no saben de seguridad informática y por ende no saben como defenderse, este es un grave error.

Un tema crucial a la hora de crear una aplicación es la seguridad de esta y de sus usuarios. Sin duda existen muchas formas de vulnerar sistemas y esperemos irlas viendo poco a poco, hoy vamos a ver una de los tantos tipos de inyección SQL.

Vamos a saltarnos un login haciendonos pasar por el administrador, ya lo tengo preparado pero lo importante de esto es que se entienda porque se produce.

Vamos a analizar una aplicación donde debes identificarte para poder acceder al contenido. Veamos su método de autentificación de usuarios.

Primero el HTML

<fieldset>
<legend>Login</legend>
<form id="form1" method="post">
  <label for="user">Usuario</label>
<input id="user" name="user" type="text" />
  <label for="pass">Contraseña</label>
<input id="pass" name="pass" type="password" />
<input id="enviar" name="enviar" type="submit" value="Enviar" />
</form>
 
</fieldset>

Un Simple formulario común y corriente con 2 campos, uno para el usuario y otro para la contraseña con su respectivo botón.

El SQL

CREATE TABLE `usuarios` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `user` varchar(50) NOT NULL,
  `pass` varchar(50) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;

Una tabla llamada usuarios con 3 campos.

  • Id: Del tipo integer (solo números enteros) con una longitud máxima de 10 carácteres, no puede estar vacío y tiene la propiedad auto_increment.
  • user: Del tipo varchar con 50 carácteres como máximo y no puede estar vacío.
  • pass: Lo mismo que el de user.

Ahora pasamos al PHP

// Inciar primero una sesión ante todo
session_start();
 
// Utilizó el formulario
if($_POST['enviar']) {
 
	// Rescatamos variables
	$user = $_POST['user'];
	$pass = $_POST['pass'];
 
	// Limpiamos espacios en blanco
	$user = trim($user);
	$pass = trim($pass);
 
	// Si no esta vacio $user y $pass
	if(!empty($user) && !empty($pass)) {
 
		@mysql_pconnect("localhost", "root", "");
		@mysql_select_db("db");
 
		// ¡OJO!
		$sql = 'SELECT user, pass FROM usuarios WHERE user=\''.$user.'\' AND pass=\''.$pass.'\'';
		$consulta = mysql_query($sql);
		$datos = mysql_fetch_array($consulta);
 
			if($datos){
 
				// Le otorgamos la sesión
				$_SESSION['user'] = $user;
 
			}
 
	}
 
}

Parece una aplicación segura, muchas usan este tipo de reconocimiento de usuarios pero no lo es asi vamos a analizar el código.

Primero que nada iniciamos una sesión, luego un condicional para saber si usó el formulario, si así fue recuperamos y limpiamos las variable, si no están vacías conectamos y seleccionamos la base de datos.

Aqui viene lo más importante, la consulta que se le envía a la base de datos, como ves es esta:

$sql = ‘SELECT user, pass FROM usuarios WHERE user=.$user. AND pass=.$pass.;

Se lee así, “Selecciona los campos user y pass de la tabla usuarios donde el campo user sea igual a el valor de la variable $user y el campo pass igual a el valor de la variable $pass”.

Si los datos son correctos la base de datos te devuelve un usuario y sus datos son procesados por mysql_fetch_array(), la función lo que hace es convertir la información devuelta por la base de datos en un array pero si la función no tiene datos para procesar devuelve FALSE.

Por lo tanto si devuelve FALSE no le damos su sesión porque quiere decir que no hay ningún usuario con esos datos pero si devuelve TRUE quiere decir que los datos son correctos y le otorgamos la sesión.

Les dejo el ejemplo.

Tengo registrado 2 usuarios, entren con este.

Usuario = user
Contraseña = user

Intenten y verán que entran (si la información es correcta), pero ahora ¿cómo entrar sin tener la contraseña?.

Pues muy fácil, solo tienen que jugar con la consulta que le llega la base de datos para que te devuelva información.

Funciona de la siguiente manera:

Imagina que ingresaste lo siguiente.

Usuario = user
Contraseña = pass

La consulta llegua así, SELECT user, pass FROM usuarios WHERE user=’user’ AND pass=’pass’ pero como no tenemos ningún usuario con los siguientes datos la consulta no recupera ninguna información y por lo mismo mysql_fetch_array() no tiene datos para procesar y devuelve FALSE, con esto tu sesión es negada.

Entonces para que nos den nuestra sesión necesitamos que la consulta devuelva datos entonces confundimos a la setencia SQL, ejemplo imagina que ingresamos lo siguiente en el formulario:

Usuario = user
Contraseña = ‘ OR 1=’1

La consulta llegua así, SELECT user, pass FROM usuarios WHERE user=’user’ AND pass=” OR 1=’1′ que se leería de la siguiente manera, “Selecciona los campos user y pass de la tabla usuarios donde el campo user sea igual a user y el campo pass igual a (nada) o 1=1″ y 1 siempre va a ser igual a 1 entonces la consulta te devuelve a los usuarios ya que se cumple la condición y mysql_fetch_array() tiene datos para procesar por lo tanto devuelve TRUE y te entregan tu sesión.

Ahora inténtalo de nuevo, pero esta vez ingresa como administrador.

Solo tienes que ingresar esto:

Usuario = admin
Contraseña = ‘ OR 1=’1

Solución

Para reparar el script existen muchos metodos, uno de ellos y creo que de los más simples sería validar la entrada de los datos con las expresiones regulares.

Un ejemplo de ello:

	// Verificamos los datos introducidos
	if(ereg("^[A-Za-z0-9]+$", $user) && ereg("^[A-Za-z0-9]+$", $pass)){

Con esto solo dejamos introducir lestras (minúsculas y mayúsculas) y números del 0 al 9 mínimo una vez. Por cierto no acepta acentos y eñes, luego les muestro como se validan.

Con esto el script ya esta arreglado, lo pueden probar.

Aunque debe quedar claro que en la mayoría de los host viene activado por defecto la opción magic_quotes por lo que cuando ingresen las comillas cualquier persona por un formulario el mismo servidor les agregará el signo de escape ‘\’.

También que esta no es la única forma de jugar con la consulta, luego les muestro un código más seguro y como burlarlo. Espero les sirva.

Tags: , , ,

Trackback

1 Respuesta a “Inyección SQL en Login”

  1. Amir
    Junio 23rd, 2008 at 8:58

    eEee que haxorsito eres :)

Dejar una respuesta