Skip to content

DEFENSA - Mitigations & Theory


PART A: Mitigations - Cómo Defenderse

1. Prepared Statements (MEJOR SOLUCIÓN)

PHP - MySQLi

✗ VULNERABLE:

php
$username = $_GET['username'];
$query = "SELECT * FROM users WHERE username = '" . $username . "'";
$result = mysqli_query($conn, $query);

✓ SEGURO - Procedural:

php
$username = $_GET['username'];
$stmt = $conn->prepare("SELECT * FROM users WHERE username = ?");
$stmt->bind_param("s", $username);  // "s" = string type
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
    echo $row['username'];
}

Tipos: "i" (int), "s" (string), "d" (double), "b" (blob)

PHP - PDO (Más moderno)

✓ SEGURO:

php
$username = $_GET['username'];
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ?");
$stmt->execute([$username]);

// Con named placeholders:
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username");
$stmt->execute(['username' => $username]);

Python - SQLAlchemy

✓ SEGURO:

python
from sqlalchemy import text
username = request.args.get('username')
query = text("SELECT * FROM users WHERE username = :username")
result = db.session.execute(query, {"username": username})

Python - Django ORM

✓ SEGURO (automático):

python
from django.contrib.auth.models import User
user = User.objects.filter(username=request.GET.get('username')).first()
# Django automáticamente escapa los parámetros

Node.js - Express

✓ SEGURO:

javascript
const username = req.query.username;
const query = 'SELECT * FROM users WHERE username = ?';
connection.query(query, [username], (error, results) => {
  // ...
});

Java - JDBC

✓ SEGURO:

java
String username = request.getParameter("username");
String query = "SELECT * FROM users WHERE username = ?";
PreparedStatement stmt = conn.prepareStatement(query);
stmt.setString(1, username);  // Posición 1, tipo String
ResultSet rs = stmt.executeQuery();

2. Input Validation

Validar Tipo de Dato

php
// ✓ ID debe ser número
$id = intval($_GET['id']);  // Convierte a INT
$query = "SELECT * FROM products WHERE id = " . $id;

// O mejor:
$id = filter_var($_GET['id'], FILTER_VALIDATE_INT);
if ($id === false) {
    die("ID inválido");
}

Validar Formato

php
// ✓ Email debe ser email
$email = filter_var($_GET['email'], FILTER_VALIDATE_EMAIL);
if ($email === false) {
    die("Email inválido");
}

// ✓ URL debe ser URL
$url = filter_var($_GET['url'], FILTER_VALIDATE_URL);

Whitelist de Valores

php
// ✓ Sort solo puede ser "name", "price", o "date"
$sort = $_GET['sort'];
$allowed = ['name', 'price', 'date'];

if (!in_array($sort, $allowed)) {
    die("Sort inválido");
}

$query = "SELECT * FROM products ORDER BY " . $sort;

Longitud Máxima

php
// ✓ Username máximo 50 caracteres
if (strlen($_GET['username']) > 50) {
    die("Username muy largo");
}
$username = substr($_GET['username'], 0, 50);

3. Least Privilege (Permisos Mínimos)

Crear usuario con permisos limitados

sql
-- ✗ MAL: Usuario con permisos amplios
CREATE USER 'app'@'localhost' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON *.* TO 'app'@'localhost';

-- ✓ BIEN: Solo lo necesario
CREATE USER 'app'@'localhost' IDENTIFIED BY 'strong_password';
GRANT SELECT, INSERT, UPDATE ON target_app.* TO 'app'@'localhost';
-- NO DROP, ALTER, CREATE, DELETE

Usuario solo lectura

sql
CREATE USER 'read_user'@'localhost' IDENTIFIED BY 'password';
GRANT SELECT ON target_app.* TO 'read_user'@'localhost';

Usuario para reportes

sql
CREATE USER 'report_user'@'localhost' IDENTIFIED BY 'password';
GRANT SELECT ON target_app.users, target_app.products TO 'report_user'@'localhost';

4. Deshabilitar Funciones Peligrosas

MySQL - Deshabilitar FILE Access

bash
# En /etc/mysql/my.cnf
[mysqld]
# Deshabilitar LOAD_FILE y INTO OUTFILE
skip-name-resolve
bind-address = 127.0.0.1

# Prevenir acceso a archivos
set-variable=secure_file_priv=/tmp

5. Error Handling

✗ MALO: Mostrar errores

php
if (!$result) {
    echo "Error: " . mysqli_error($conn);
    // ← Revela estructura de BD
}

✓ BIEN: Ocultar detalles

php
if (!$result) {
    error_log("DB Error: " . mysqli_error($conn));  // Log interno
    echo "An error occurred. Please try again later.";  // Usuario
}

Configuración de PHP

ini
display_errors = Off
log_errors = On
error_log = /var/log/php-errors.log

6. Web Application Firewall (WAF)

  • ModSecurity: Open source, reglas para SQLi
  • AWS WAF: Automático, cloudnative
  • Cloudflare: DDoS + SQLi protection

7. Rate Limiting

php
// Limitar intentos fallidos
$failed_attempts = get_failed_attempts($_SERVER['REMOTE_ADDR']);

if ($failed_attempts > 5) {
    http_response_code(429);  // Too Many Requests
    die("Too many attempts. Try again later.");
}

if (query_fails()) {
    increment_failed_attempts($_SERVER['REMOTE_ADDR']);
}

En Nginx

nginx
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

location /api {
    limit_req zone=api burst=20;
}

8. Logging & Monitoring

php
// Detectar queries sospechosas
if (strpos($query, "UNION") !== false || 
    strpos($query, "DROP") !== false) {
    error_log("SUSPICIOUS: " . $query);
    alert_security_team();
}

Resumen de Defensas

DefensaEfectividadRecomendación
Prepared Statements★★★★★USAR SIEMPRE
Input Validation★★★★☆Complementaria
Least Privilege★★★★☆Importante
Error Handling★★★☆☆Defensa en profundidad
WAF★★★★☆Capa extra buena
Rate Limiting★★★☆☆Complementaria

LA REGLA DE ORO: Usa Prepared Statements. TODO. EL. TIEMPO.



PART B: Theory - Conceptos Fundamentales

¿Por Qué Ocurre SQL Injection?

Falta de Separación entre Código y Datos

php
// ✗ MEZCLA código con datos
$sql = "SELECT * FROM users WHERE id=" . $_GET['id'];
// Usuario inyecta: ?id=1 OR 1=1 --
// Ahora es código, no dato

// ✓ SEPARA código de datos
$sql = "SELECT * FROM users WHERE id=?";
$params = [$_GET['id']];
// El ? indica: "aquí va DATO, no código"
// Se escapa automáticamente

Principios de Seguridad Violados

1. Principle of Least Privilege

Aplicación solo debe tener permisos necesarios.

sql
-- ✗ MAL
GRANT ALL PRIVILEGES ON *.* TO 'app'@'localhost';
-- Si SQLi ocurre = acceso total

-- ✓ BIEN
GRANT SELECT, INSERT, UPDATE ON target_app.* TO 'app'@'localhost';
-- Si SQLi ocurre = limitado

2. Defense in Depth

Múltiples capas de seguridad:

Capa 1: Input Validation
Capa 2: Prepared Statements (PRINCIPAL)
Capa 3: Least Privilege en BD
Capa 4: WAF
Capa 5: Rate Limiting
Capa 6: Monitoring

Si una falla, las otras protegen.

3. Never Trust User Input

NUNCA asumir entrada es válida.

php
// ✗ Asume validez
$sort = $_GET['sort'];
$query = "SELECT * FROM products ORDER BY " . $sort;

// ✓ Valida siempre
if (!in_array($sort, ['name', 'price', 'date'])) {
    die("Invalid sort");
}

OWASP Top 10 2021

#1 - Broken Access Control (puede resultar de SQLi)
#2 - Cryptographic Failures (SQLi + datos sin encriptar)
#3 - Injection ← SQL INJECTION AQUÍ
#4 - Insecure Design
#5 - Security Misconfiguration
...

MITRE ATT&CK Framework

Tactic: Exploitation
Technique: T1190 - Exploit Public-Facing Application

Ciclo de Vida Completo

1. RECONNAISSANCE
   └─ Identifica punto de entrada web vulnerable

2. WEAPONIZATION
   └─ Prepara payload SQL malicioso

3. DELIVERY
   └─ Inyecta payload en parámetro

4. EXPLOITATION
   └─ BD ejecuta código SQL modificado

5. INSTALLATION
   └─ Escribe shell web o backdoor

6. COMMAND & CONTROL
   └─ Controla servidor comprometido

7. ACTIONS ON OBJECTIVES
   └─ Roba datos, modifica, escala privilegios

CWE (Common Weakness Enumeration)

CWE-89: SQL Injection

  • Impacto: Alto (confidentiality, integrity, availability)
  • Prevalencia: Muy común en aplicaciones legadas
  • Causa raíz: CWE-20 (Improper Input Validation)

CVSS Score

SQL Injection típica

Attack Vector: Network (0.85)
Attack Complexity: Low (0.77)
Privileges Required: None (0.85)
User Interaction: None (0.85)
Scope: Changed (1.0)
Confidentiality: High (0.56)
Integrity: High (0.56)
Availability: High (0.56)

= CVSS 9.9 CRÍTICO

Impacto Empresarial

Confidentiality (Confidencialidad)

- Robo de datos de clientes
- Robo de credenciales
- Robo de API keys
- GDPR: Multa €20M o 4% revenue

Integrity (Integridad)

- Modificación de datos de usuarios
- Cambio de precios
- Inyección de malware
→ Pérdida de confianza, responsabilidad legal

Availability (Disponibilidad)

- DROP TABLE (eliminación permanente)
- DELETE (eliminación de datos)
- Crash de aplicación
→ Downtime operacional, pérdida de ingresos

Secure Development Lifecycle (SDLC)

1. PLANNING
   └─ Requerimientos de seguridad

2. ANALYSIS
   └─ Threat modeling

3. DESIGN
   └─ Diseño seguro (separar código de datos)

4. DEVELOPMENT
   └─ Usar prepared statements SIEMPRE

5. TESTING
   └─ Pruebas de seguridad (SAST, DAST, pentesting)

6. DEPLOYMENT
   └─ Hardening, WAF, monitoring

7. MAINTENANCE
   └─ Parches, actualizaciones, code reviews

Code Review Process

Cada línea de código que accede a BD debe:
✓ Usar prepared statements
✓ Tener input validation
✓ Tener error handling
✓ Tener logging

Pull Request rechazado si no cumple

Tendencias Modernas (2024)

De:

  • Manual (probaba parámetros uno por uno)
  • Lento (blind SQLi demoraba horas)

A:

  • Automatizado (sqlmap hace todo)
  • Rápido (UNION en segundos)
  • Sofisticado (bypass WAF automático)

Futuro:

  • ORMs más seguros (SQLAlchemy, Django ORM)
  • Type-safe databases (Prisma, TypeORM)
  • Hardware security (TPM, Secure Enclaves)
  • AI/ML detection

Resumen - Principios Clave

  1. Separar código de datos → prepared statements
  2. Never trust user input → validación siempre
  3. Least privilege → usuario de BD con permisos mínimos
  4. Defense in depth → múltiples capas de seguridad
  5. Secure by default → configuración segura por defecto
  6. Monitor and log → detectar intentos
  7. Keep updated → patches de seguridad

LA REGLA MÁS IMPORTANTE

SI RECUERDAS SOLO UNA COSA: USA PREPARED STATEMENTS


Checklist Implementación Segura

  • [ ] Todos los queries usan prepared statements
  • [ ] Validación de input en cada parámetro
  • [ ] Usuario de BD tiene permisos limitados
  • [ ] Errores SQL no se muestran al usuario
  • [ ] Logging de queries sospechosas
  • [ ] WAF configurado y activo
  • [ ] Rate limiting habilitado
  • [ ] Auditoría de cambios en BD
  • [ ] Monitoreo en producción
  • [ ] Testing de seguridad periódico