Cuando hace un par de años era yo quien consultaba foros de seguridad informática para aprender a efectuar SQL Injection, nunca imaginé que algún día acabaría escribiendo sobre ello. No son muchos los artículos que están en español, pero aún así hay bastante contenido sobre ésta vulnerabilidad tan peligrosa. Lo cierto es que éste tema nunca ha dejado de apasionarme, de modo que voy a empezar a escribir una serie de artículos que irán gradualmente aumentando en dificultad y que pretenden ser un punto de partida para aquellos que quieran aprender sobre inyección SQL y sus consecuencias. La mejor manera de prevenir éstas vulnerabilidades, es conocerlas.

Hoy en día existen multitud de frameworks que sanitizan los parámetros HTTP entre cliente y servidor. Por tanto, el perfil de app web que suele sufrir la presencia de SQL Injection son apps escritas en plain PHP ( PHP a secas ), que aparte de ser el lenguaje más usado para el desarrollo web, también es conocido porque permite malas prácticas de programación. Por eso, para el tutorial de hoy, he escrito una aplicación web muy simple a la vez que vulnerable que permite indentificarse con usuario y contraseña. Se compone por una tabla llamada «users» en una BBDD de MySQL, y un fichero index.php en la parte del servidor.
Esquema y contenido de la tabla users

Script PHP
<?php
session_start();
if ( isset ($_POST['username']) && isset($_POST['pass']) ) {
$username = $_POST['username'];
$pass = $_POST['pass'];
$query = 'SELECT id FROM users WHERE username = "' . $username . '"' .
' AND pass = "' . md5($pass) . '";';
$c = mysqli_connect('localhost', 'test', 'pass', 'test');
$c or die('Error establishing database connection:' . mysqli_connect_error() );
if (( $result = mysqli_query($c, $query) )){
if ( mysqli_affected_rows($c) > 0 )
$_SESSION['user'] = $username;
else $error = TRUE;
mysqli_free_result($result);
} else {
die(mysqli_error($c));
}
mysqli_close($c);
}
?>
<!DOCTYPE html>
<html>
<head>
<title>SQL Injection tutorial</title>
</head>
<body style="background-color: #" >
<?php if ( isset ( $_SESSION['user'] ) ) : ?>
<h1>Welcome, <?=$_SESSION['user'];?></h1>
<hr/>
<?php else: ?>
<h1>Log-in</h1>
<form action="index.php" method="POST" >
<p>Username: <input type="text" name="username" value="" /></p>
<p>Password: <input type="password" name="pass" value="" /></p>
<?php if ( $error ) : ?>
<p style="color:red" >User or pass didn't match.</p>
<?php endif; ?>
<p><button type="submit" >Submit</button></p>
</form>
<?php endif; ?>
</body>
</html>
Lo que hace éste script es muy simple. Presenta un formulario para introducir los campos «usuario» y «contraseña«. Una vez rellenados y enviados, buscará coincidencias en la BBDD. Nótese que dichos parámetros se concatenan directamente dentro de la consulta SQL. Si encuentra resultados, guardará el nick del usuario en una variable de sesión y mostrará un mensaje de bienvenida. Si no, mostrará el formulario de nuevo y un mensaje indicando el error. Una captura de la vista:

Ya tenemos los preparativos para comenzar. En la segunda parte veremos cómo, sin conocer las credenciales, podremos acceder a la aplicación igualmente.