Sécurité

Prevención de inyección SQL: Guía completa

Cómo prevenir ataques de inyección SQL en tu aplicación web. Queries parametrizadas, ORMs, validación y WAF.

18 mars 20264 min de lectureWarDek Team

La inyección SQL es una de las vulnerabilidades más antiguas de la web — y sigue siendo una de las más devastadoras. A pesar de ser conocida desde hace más de 25 años, sigue apareciendo en el OWASP Top 10. Un solo campo de búsqueda mal protegido puede dar acceso completo a tu base de datos.

¿Qué es la inyección SQL?

Un ataque de inyección SQL ocurre cuando un atacante introduce código SQL malicioso a través de un input de usuario que la aplicación inserta directamente en una consulta SQL sin sanitizar.

Ejemplo clásico

// ❌ VULNERABLE — concatenación directa
const query = `SELECT * FROM users WHERE email = '${email}' AND passwd = '${passwd}'`;

Un atacante introduce como email: [email protected]' --

La consulta resultante:

SELECT * FROM users WHERE email = '[email protected]' --' AND passwd = 'lo_que_sea'

El -- comenta el resto de la consulta. El atacante accede como admin sin conocer la contraseña.

Tipos de inyección SQL

In-band (clásica)

El atacante obtiene los resultados directamente en la respuesta de la aplicación.

Union-based: el atacante usa UNION SELECT para extraer datos de otras tablas:

' UNION SELECT username, passwd FROM admin_users --

Error-based: los mensajes de error del servidor revelan la estructura de la BD.

Blind (ciega)

La aplicación no muestra datos pero responde de forma diferente según la consulta sea verdadera o falsa.

Boolean-based: el atacante hace preguntas sí/no:

' AND (SELECT SUBSTRING(passwd,1,1) FROM users WHERE id=1) = 'a' --

Time-based: la aplicación tarda más en responder si la condición es verdadera:

' AND IF(1=1, SLEEP(5), 0) --

Out-of-band

El atacante extrae datos a través de canales alternativos (DNS, HTTP) cuando la respuesta directa no es posible.

Impacto de una inyección SQL

Prevención: Queries parametrizadas

La defensa principal contra inyección SQL. Sin excepciones.

Node.js con pg (PostgreSQL)

// ❌ VULNERABLE
const result = await client.query(`SELECT * FROM users WHERE email = '${email}'`);

// ✅ SEGURO — query parametrizada
const result = await client.query('SELECT * FROM users WHERE email = $1', [email]);

Node.js con mysql2

// ✅ SEGURO — query parametrizada
const [rows] = await connection.execute(
  'SELECT * FROM users WHERE email = ? AND status = ?',
  [email, 'active']
);

PHP con PDO

// ✅ SEGURO — prepared statement
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email');
$stmt->execute(['email' => $email]);

Python con psycopg2

# ✅ SEGURO — query parametrizada
cursor.execute("SELECT * FROM users WHERE email = %s", (email,))

Prevención: ORM

Los ORMs (Object-Relational Mapping) generan queries parametrizadas automáticamente:

Prisma

// ✅ SEGURO — Prisma parametriza automáticamente
const user = await prisma.user.findUnique({
  where: { email: userInput },
});

Sequelize

// ✅ SEGURO
const users = await User.findAll({
  where: { email: userInput },
});

Django ORM

# ✅ SEGURO
user = User.objects.filter(email=user_input).first()

Cuidado: los ORMs protegen contra inyección SQL en sus métodos estándar. Si usas raw queries, la protección desaparece:

// ❌ PELIGROSO incluso con Prisma
const result = await prisma.$queryRawUnsafe(`SELECT * FROM users WHERE email = '${email}'`);

// ✅ SEGURO — raw query parametrizada
const result = await prisma.$queryRaw`SELECT * FROM users WHERE email = ${email}`;

Defensas adicionales

Validación de inputs

Valida todos los inputs antes de usarlos en consultas:

import { z } from 'zod';

const searchSchema = z.object({
  email: z.string().email(),
  limit: z.number().int().min(1).max(100).default(10),
  page: z.number().int().min(1).default(1),
});

Principio de mínimo privilegio

El usuario de base de datos de tu aplicación NO debe tener permisos de:

-- Crear usuario con permisos mínimos
CREATE USER app_user WITH PASSWD 'strong_passwd';
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app_user;
-- NO conceder DDL ni admin

WAF (Web Application Firewall)

Un WAF como Cloudflare, AWS WAF o ModSecurity puede detectar y bloquear patrones de inyección SQL en las peticiones antes de que lleguen a tu aplicación.

No sustituye las queries parametrizadas, pero añade una capa de defensa.

Mensajes de error genéricos

Nunca expongas errores SQL al usuario:

// ❌ PELIGROSO
catch (error) {
  res.status(500).json({ error: error.message });
  // Revela: "relation "users" does not exist"
}

// ✅ SEGURO
catch (error) {
  logger.error({ error: error.message }, 'Database query failed');
  res.status(500).json({ error: 'Internal server error' });
}

Checklist anti-SQLi

Cómo WarDek detecta inyección SQL

WarDek analiza tu aplicación web en busca de vectores de inyección SQL:


Escanea tu sitio web gratis con WarDek — OWASP, NIS2, RGPD, AI Act en un solo escaneo.

#sql-injection#seguridad-web#base-datos#vulnerabilidades

Scannez votre site gratuitement

WarDek détecte les vulnérabilités mentionnées dans cet article en quelques secondes.

Retour à Sécurité