martes, 18 de marzo de 2014

Evitar la inyección SQL desde PHP


Bienvenid@s, hoy vamos a ver dos de los ataques más comunes de inyección sql. Primeramente tenemos que entender el concepto de "inyección sql", la inyección sql es la inclusión de código sql a través de parámetros que son enviados a través de los métodos POST o GET, esta inclusión de código SQL malicioso trata de modificar la verdadera consulta, por otra que cambia el comportamiento por el cual la consulta fue programada y puede permitir al atacante acceder a zonas donde es necesaria una acreditación por ejemplo un "formulario de login" o tanto o más dañino como puede ser la obtención de cualquier información almacenada en el servidor, es decir, bases de datos, tablas y registros.

El primer ejemplo es uno de los más conocidos y es introducir código arbitrariamente en los campos de inicio de sesión de un login de usuarios, el código de esta inyección es básico -> ' or '1'='1 con esta simple inclusión de código en los campos usuario y password, un sistema inseguro daría una respuesta true(verdadera) permitiendo al atacante acceder sin apenas esfuerzo al panel de administración de la aplicación. las consecuencias son las que ya os podéis imaginar, desde la manipulación del sistema, robo de información, borrado de datos, etc, ...

Para evitar dicho ataque, primero tenemos que saber que herramientas estamos utilizando, por ejemplo si estamos utilizando la clase mysql que por cierto está obsoleta y no se recomienda utilizarla podríamos utilizar la función mysql_real_escape_string(), es aconsejable utilizar la clase mysqli que es una clase para mysql más avanzada y por supuesto más segura, entonces utilizaríamos la función mysqli_real_escape_string(), como última solución podríamos utilizar addslashes() que colocará una barra invertida en las comillas simples y dobles o stripslashes() que eliminará las comillas simples y dobles.

Ejemplo con mysqli:

$conexion = new mysqli("localhost", "root", "password", "basededatos");
$usuario = $conexion->real_escape_string($_POST["usuario"]);
$password = $conexion->real_escape_string($_POST["password"]);

$sql = "SELECT * FROM usuarios WHERE usuario='$usuario' AND password='$password'";
$resultado = $conexion->query($sql);
...


Otra forma segura de hacer consultas es utilizar la extensión PDO (PHP Data Objects), esta extensión nos va a permitir a través de la vinculación de parámetros evitar la inyección SQL, por ejemplo ...

$conexion = new PDO("mysql:host=localhost;dbname=basededatos;", "root", "password");
$usuario = $_POST["usuario"];
$password = $_POST["password"];
$sql = "SELECT * FROM usuarios WHERE usuario=:usuario AND password=:password";
$consulta = $conexion->prepare($sql);
$consulta->bindParam(":usuario", $usuario, PDO::PARAM_STR);
$consulta->bindParam(":password", $password, PDO::PARAM_STR);
$consulta->execute();
...


El segundo ejemplo es otro de los ataques de inyección sql más comunes, el atacante comprueba incluyendo una comilla simple en un parámetro, por ejemplo: http://localhost/index.php?id='

Si este regresa un error fatal o un warning, es que algo no ha ido bien al realizar la consulta y puede ser el foco de una inyección sql en toda regla, para automatizar dicho ataque, el atacante podría utilizar una herramienta como SQLMAP, e ir escalando privilegios, obteniendo bases de datos, tablas y registros.

Ademas de utilizar funciones que nos permitan escapar caracteres especiales como vimos en el primer ejemplo, tenemos que saber condicionar el tipo de datos que aceptamos para realizar la consulta, una de las formas más eficientes de lograrlo es a través de expresiones regulares como podemos ver en el siguiente ejemplo ...

$conexion = new mysqli("localhost", "root", "password", "basededatos");
$id = $_GET["id"];

//Sólo permitimos números
if (!preg_match("/^[0-9]+$/", $id))
{
//Por ejemplo lo expulsamos de la página
header("location: error.php");
}
else //De lo contrario ejecutamos la consulta
{
$sql = "SELECT * FROM productos WHERE id=$id";
$resultado = $conexion->query($sql);
...
}



No hay comentarios: