Uno de los ataques más famosos, peligrosos y antiguos de internet sigue siendo increíblemente efectivo hoy en día.
Se llama:
SQL Injection (SQLi)
Y aunque existen desde hace décadas, todavía miles de aplicaciones vulnerables siguen siendo explotadas diariamente.
La razón es simple:
Muchos desarrolladores aún concatenan datos directamente en consultas SQL sin validar correctamente la entrada del usuario.
En esta guía aprenderás:
- qué es SQL Injection
- cómo funciona
- ejemplos reales
- por qué es tan peligroso
- cómo prevenirlo correctamente
- errores comunes
- mejores prácticas modernas
Todo explicado paso a paso.
¿Qué es SQL Injection?
SQL Injection es un ataque donde un atacante manipula consultas SQL enviando datos maliciosos a través de formularios, URLs o parámetros.
El objetivo suele ser:
- acceder a información privada
- saltar autenticación
- modificar datos
- eliminar tablas
- obtener usuarios y contraseñas
- tomar control parcial de la aplicación
¿Por qué ocurre?
Porque la aplicación mezcla:
❌ datos del usuario
con
❌ código SQL
Ejemplo vulnerable clásico
Supongamos este login en PHP:
$user = $_POST['user'];
$pass = $_POST['pass'];
$sql = "SELECT * FROM users
WHERE username = '$user'
AND password = '$pass'";
Parece normal.
Pero aquí está el problema:
Los datos del usuario entran directamente en la consulta.
Cómo lo explota un atacante
En vez de escribir una contraseña normal:
' OR '1'='1
La consulta final queda así:
SELECT * FROM users WHERE username = 'admin' AND password = '' OR '1'='1'
Como '1'='1' siempre es verdadero:
✅ el login puede ser bypassed
✅ entra sin contraseña
Qué puede lograr un atacante con SQLi
Muchísimo más que saltarse un login.
1. Robar bases de datos
Usuarios
emails
teléfonos
direcciones
tarjetas
hashes
2. Obtener credenciales admin
Muchos ataques buscan paneles administrativos.
3. Borrar información
Ejemplo peligroso:
DROP TABLE users;
4. Modificar datos
Cambiar precios
inventario
roles
contraseñas
5. Obtener acceso al servidor
En algunos casos extremos:
- ejecutar comandos
- subir archivos
- obtener shell
Tipos de SQL Injection
SQL Injection clásica
La más conocida.
Manipulación directa de consultas.
Blind SQL Injection
La aplicación no muestra errores.
Entonces el atacante usa:
- tiempos de respuesta
- respuestas verdaderas/falsas
- comportamiento del sistema
para extraer información lentamente.
Time-Based SQLi
Ejemplo:
SLEEP(5)
Si la respuesta tarda 5 segundos:
✅ sabe que la inyección funcionó.
Error-Based SQLi
La aplicación muestra errores SQL directamente.
Ejemplo típico:
You have an error in your SQL syntax
Eso ayuda muchísimo al atacante.
Union-Based SQLi
Usa UNION SELECT para combinar consultas.
Ejemplo:
UNION SELECT username,password FROM users
Ejemplo real en URL
Aplicación vulnerable:
https://sitio.com/product.php?id=10
Atacante prueba:
?id=10 OR 1=1
o:
?id=10 UNION SELECT username,password FROM users
Cómo descubren vulnerabilidades los atacantes
Muchos usan herramientas automáticas.
sqlmap
Una de las más famosas.
Detecta y explota SQL Injection automáticamente.
Ejemplo:
sqlmap -u "https://sitio.com/product.php?id=1"
Puede:
- enumerar bases
- extraer tablas
- sacar usuarios
- romper autenticación
Por qué SQLi sigue existiendo
Porque muchos sistemas:
❌ usan código viejo
❌ concatenan strings
❌ no validan inputs
❌ no usan prepared statements
Cómo prevenir SQL Injection correctamente
La solución moderna principal:
Prepared Statements
Ejemplo seguro con PDO
$stmt = $pdo->prepare("
SELECT * FROM users
WHERE username = :user
AND password = :pass
");
$stmt->execute([
':user' => $user,
':pass' => $pass
]);
¿Por qué esto es seguro?
Porque:
✅ SQL y datos van separados
✅ el motor SQL interpreta valores como datos
✅ no como código
Prepared Statements vs concatenación
Malo
$sql = "SELECT * FROM users WHERE id = $id";
Bueno
$stmt = $pdo->prepare("
SELECT * FROM users WHERE id = ?
");
Validar inputs también importa
Prepared statements ayudan muchísimo.
Pero además debes validar:
- tipos
- tamaños
- formatos
- rangos
Ejemplo correcto
$id = (int) $_GET['id'];
Nunca confiar en input del usuario
Nunca.
Ni formularios.
Ni APIs.
Ni cookies.
Ni headers.
Ni uploads.
ORM y frameworks modernos
Muchos frameworks ayudan automáticamente:
- Laravel
- Symfony
- Django
- Ruby on Rails
Pero incluso con frameworks:
❌ puedes programar inseguro
Errores comunes
1. Escapar strings manualmente
Muchos hacen:
mysqli_real_escape_string()
Eso NO reemplaza prepared statements.
2. Mostrar errores SQL
Muy peligroso.
En producción:
display_errors = Off
3. Usar usuario root en MySQL
Nunca hagas esto.
Crea usuarios limitados.
4. No limitar permisos SQL
Tu aplicación NO necesita permisos globales.
Qué permisos mínimos usar
Ejemplo:
GRANT SELECT, INSERT, UPDATE ON tienda.* TO 'appuser'@'localhost';
Cómo detectar intentos SQLi
Revisa logs buscando:
UNION SELECT OR 1=1 SLEEP( -- ' "
Herramientas que ayudan a bloquear SQLi
WAF
Muchos WAF detectan patrones SQLi automáticamente.
Ejemplos:
- Cloudflare
- ModSecurity
Fail2Ban
Puede bloquear IPs que generen patrones sospechosos.
OWASP CRS
Las reglas OWASP para ModSecurity detectan SQLi comunes.
Cómo probar tu propia aplicación
Puedes hacer pruebas controladas.
Ejemplo:
?id='
Si aparecen errores SQL:
🚨 mala señal.
Qué hacer si descubres una vulnerabilidad
Inmediatamente
✅ corregir código
✅ cambiar credenciales
✅ revisar logs
✅ revisar accesos
✅ actualizar dependencias
SQL Injection en APIs
También ocurre muchísimo en:
- APIs REST
- filtros dinámicos
- búsquedas
- GraphQL mal implementado
SQLi en WordPress
Muchos plugins vulnerables han permitido:
- robo de usuarios
- takeover admin
- malware
Por eso actualizar plugins es crítico.
Cómo reducir superficie de ataque
✅ Prepared statements
✅ validación inputs
✅ WAF
✅ logs
✅ mínimos privilegios
✅ actualizaciones
✅ ocultar errores SQL
Ejemplo completo seguro con PDO
<?php
$stmt = $pdo->prepare("
SELECT id, name, email
FROM users
WHERE email = :email
");
$stmt->execute([
':email' => $email
]);
$user = $stmt->fetch();
Conclusión:
SQL Injection es uno de los ataques más famosos de internet porque durante años ha sido extremadamente efectivo.
La buena noticia es que hoy prevenirlo correctamente es mucho más sencillo que antes.
Si haces esto:
✅ prepared statements
✅ validación de inputs
✅ mínimos privilegios SQL
✅ WAF
✅ logs
✅ frameworks modernos
ya estarás muy por delante de muchísimas aplicaciones vulnerables.
La seguridad web no consiste en confiar en que nadie atacará tu sitio.
Consiste en asumir que tarde o temprano alguien lo intentará.
Y prepararte antes de que ocurra.
🔙 Volver al post pilar:
👉 Cómo montar una infraestructura web real desde cero