Blog de Gonzalo

Inyección de sql

La inyección SQL consiste en insertar código SQL para alterar la base de datos de la página web. Se suele hacer en los formularios de login o en los formularios de alta de usuario o cuando se sabe que se va a interactuar con una base de datos.
Ejemplo:
Supongamos que tenemos un formulario de login donde se pide el nombre de usuario y damos al botón de enviar (o submit) y tenemos la siguiente query en php:

$query = "SELECT * FROM usuarios WHERE nombre = '" .$nombreusuario."';"

Se supone que la variable nombre de usuario contiene el nombre del usuario que se va a logear en nuestra aplicación. Pero alguien malintencionado podría introducir en el formulario otra cosa como por ejemplo juan';DROP TABLE usuarios; SELECT * FROM datos WHERE nombre LIKE '%'; y después de hacer la consulta select borra la tabla de usuarios.
Una solución sencilla sería usar la función mysql_real_escape_string y nos podría evitar muchos problemas. Aquí os pongo un ejemplo:
$prueba1 = mysql_real_escape_string('torrevieja');
$prueba2 = mysql_real_escape_string( "1;DROP TABLE nombre_alojamiento;");
$query = 'SELECT * from alojamiento where nombre_alojamiento = "'.$prueba1.'" and id_owner = '.$prueba2;
echo $query;
$res = mysql_query($query,$con);
var_dump($res);

Se puede observar que la segunda variable contiene un drop table. Al hacer var_dump del resultado de la consulta el resultado es false y si quitamos el drop table el resultado es true.
Pero a partir de PHP 7, hay que evitar la inyeccion de sql de dos maneras:

Evitar inyección de mysql con MYSQLI


//Conexióna  la base de datos
$mysqli = new mysqli('127.0.0.1', 'tu_usuario', 'tu_contraseña', 'pruebas');
...
//Con el siguiente codigo se 'prepara' la query para evitar la inyeccion de sql
$stmt = $conn->prepare("INSERT INTO alumnos (nombre, apellid, email) VALUES
(?, ?, ?)");
$stmt->bind_param("sss", $name, $apellido, $email);

$firstname = 'Juan';
$lastname = 'Pérez';
$email = 'juan@examplo.com';
$stmt->execute();

$firstname = 'Ana';
$lastname = 'López';
$email = 'Ana@examplo.com';
$stmt->execute();

$firstname = 'Pedro';
$lastname = 'Sandoval';
$email = 'Pedro@examplo.com';
$stmt->execute();

echo 'Los datos se han guardado correctamente';

$stmt->close();
$conn->close();

En la sentencia "insert" hay tres "s" que coincide con el número de valores que se van a insertar: nombre, apellido y email y la "s" quiere decir que se va a introducir un string, en este caso 3.
Lista de caracteres a poner según el tipo de valor
  • i - integer
  • d - double
  • s - string
  • b - BLOB

Evitar inyección de mysql con PDO


$conn = new PDO("mysql:host=127.0.0.1;dbname=pruebas", 'tu_usuario', 'tu_contraseña');
$stmt = $conn->prepare("INSERT INTO alumnos(nombre, apellido, email) VALUES (:nombre, :apellido, :email)");
$stmt->bindParam(':nombre', $nombre);
$stmt->bindParam(':apellido', $apellido);
$stmt->bindParam(':email', $email);

$firstname = 'Ana';
$lastname = 'López';
$email = 'Ana@examplo.com';
$stmt->execute();

$firstname = 'Pedro';
$lastname = 'Sandoval';
$email = 'Pedro@examplo.com';
echo 'Los datos se han guardado correctamente';
$conn = null;

Como se peude ver evitar la inyecciónd e sql es sencillo y fácil y puede ahorrar varios disgustos.