¿Qué es SQL Injection y cómo prevenirlo en PHP?

La seguridad web es un aspecto fundamental en el desarrollo de aplicaciones modernas, especialmente cuando se trabaja con lenguajes como PHP y bases de datos SQL. Una de las amenazas más comunes y peligrosas que enfrentan los desarrolladores es el SQL Injection, una técnica de ataque que permite a los ciberdelincuentes manipular las consultas SQL para acceder, modificar o eliminar información confidencial. Este tipo de vulnerabilidad puede comprometer la integridad de tu sistema, exponer datos sensibles y afectar la reputación de tu sitio web.

En este artículo aprenderás cómo funciona el SQL Injection, cómo identificar si tu aplicación PHP es vulnerable, y lo más importante: cómo proteger tu base de datos mediante buenas prácticas de programación segura. Exploraremos ejemplos reales de código vulnerable y cómo transformarlos en código PHP seguro utilizando prepared statements y validación de entradas. También abordaremos técnicas de prevención de ataques y herramientas que puedes usar para auditar la seguridad de tu sitio.

Si estás interesado en mejorar la seguridad web de tus proyectos, evitar vulnerabilidades SQL y aplicar estrategias efectivas para proteger tus datos, este artículo es para ti. Sigue leyendo y fortalece tu conocimiento en desarrollo seguro con PHP.

¿Cómo funciona el SQL Injection?

Cuando los datos del usuario se insertan directamente en una consulta SQL sin validación ni protección, el atacante puede alterar la lógica de la consulta.

<?php
$username = $_GET['user'];
$password = $_GET['pass'];

$conn = new mysqli("localhost", "root", "", "usuarios");

// Consulta vulnerable
$sql = "SELECT * FROM usuarios WHERE username = '$username' AND password = '$password'";
$result = $conn->query($sql);

if ($result->num_rows > 0) {
    echo "Acceso concedido";
} else {
    echo "Acceso denegado";
}
?>

Ataque de ejemplo:

Si el atacante accede a la URL con:

http://example.com/login.php?user=admin&pass=' OR '1'='1

La consulta se convierte en:

SELECT * FROM usuarios WHERE username = 'admin' AND password = '' OR '1'='1'

Esto siempre será verdadero, permitiendo el acceso sin credenciales válidas.

Veamos otro Ejemplo en un formulario web

Supongamos que tienes un formulario de búsqueda en tu sitio web que permite a los usuarios buscar productos por nombre:

<?php
$search = $_GET['search'];
$sql = "SELECT * FROM productos WHERE nombre LIKE '%$search%'";
$result = mysqli_query($conn, $sql);
?>

Si el usuario introduce:

search = ' OR 1=1 --

La consulta se convierte en:

SELECT * FROM productos WHERE nombre LIKE '%' OR 1=1 --%'

Esto hace que la condición OR 1=1 siempre sea verdadera, y el -- comenta el resto de la consulta. Como resultado, se devuelven todos los productos, ignorando el filtro original.

 ¿Cómo prevenir el SQL Injection?

La mejor forma de prevenirlo es nunca insertar directamente datos del usuario en las consultas SQL. En su lugar, usa consultas preparadas (prepared statements).

 Ejemplo seguro en PHP con MySQLi:

<?php
$username = $_GET['user'];
$password = $_GET['pass'];

$conn = new mysqli("localhost", "root", "", "usuarios");

// Consulta segura con prepared statements
$stmt = $conn->prepare("SELECT * FROM usuarios WHERE username = ? AND password = ?");
$stmt->bind_param("ss", $username, $password);
$stmt->execute();

$result = $stmt->get_result();

if ($result->num_rows > 0) {
    echo "Acceso concedido";
} else {
    echo "Acceso denegado";
}
?>

Ejemplo seguro con PDO:

$stmt = $pdo->prepare("SELECT * FROM usuarios WHERE username = :username AND password = :password");
$stmt->execute(['username' => $username, 'password' => $password]);

Validar y sanitizar los datos de entrada

Antes de usar cualquier dato del usuario, asegúrate de que cumple con el formato esperado.

Ejemplo:

if (!preg_match('/^[a-zA-Z0-9_]{3,20}$/', $username)) {
    die("Nombre de usuario inválido");
}

Esto evita que se introduzcan caracteres peligrosos.

Evitar mostrar errores SQL al usuario

Los mensajes de error pueden revelar detalles de la estructura de la base de datos.

Ejemplo inseguro

echo "Error: " . $conn->error;

Ejemplo seguro

Esto seria una buena practica para incluir en el código..

echo "Ha ocurrido un error. Intente nuevamente.";

Usar roles y permisos en la base de datos

No todos los usuarios deben tener acceso total. Crea usuarios con permisos limitados para las operaciones necesarias.

Ejemplo:

  • Usuario web_user solo puede hacer SELECTINSERT.
  • Usuario admin_user puede hacer DELETEUPDATE.

Mantener el software actualizado

Otra buena practica es actualizar regularmente PHP, el servidor web y el sistema de gestión de base de datos para corregir vulnerabilidades conocidas.

Conclusion

El SQL Injection sigue siendo una de las amenazas más relevantes en el ámbito de la seguridad web, especialmente en aplicaciones que interactúan con bases de datos mediante PHP. Comprender cómo funciona esta vulnerabilidad y aplicar buenas prácticas como el uso de consultas preparadas, la validación de entradas, y la gestión adecuada de errores y permisos, es esencial para proteger tus sistemas y datos.

Implementar estas medidas no solo fortalece la seguridad de tu aplicación, sino que también mejora la confianza de los usuarios y la reputación de tu proyecto. La prevención de ataques debe ser una prioridad desde las primeras etapas del desarrollo. Con el conocimiento adecuado y las herramientas correctas, puedes construir aplicaciones PHP seguras y resistentes frente a las amenazas más comunes.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Scroll al inicio