LIVE: New phishing campaigns targeting mobile users —View latest threats →

Back to Tutorials
Avanzado 14 min de lectura

Inyección SQL: cómo funciona y cómo detenerla

La inyección SQL ha sido la principal vulnerabilidad web durante décadas. Descubre exactamente cómo funciona un ataque y aprende las defensas que la eliminan.

10 de enero de 2026

Por qué sigue existiendo la inyección SQL

La inyección SQL se documentó por primera vez en 1998. Ha aparecido en todas las listas OWASP Top 10 desde su creación. Ha sido responsable de algunas de las mayores brechas de datos de la historia: TalkTalk (4 millones de registros), Heartland Payment Systems (130 millones de números de tarjeta) e innumerables casos más.

La razón por la que persiste no es la complejidad. La inyección SQL es fácil de entender y, lo que es crucial, fácil de prevenir. Persiste porque los desarrolladores concatenan la entrada del usuario en las consultas SQL sin pensar en las consecuencias, a menudo bajo presión de tiempo y sin formación en seguridad.

Este tutorial muestra exactamente cómo funciona y las técnicas concretas que la eliminan.

Cómo funciona normalmente una consulta SQL

Considera un formulario de inicio de sesión. La aplicación toma un nombre de usuario y una contraseña y los comprueba contra la base de datos:

SELECT * FROM users WHERE username = 'alice' AND password = 'secretpass';

Si la consulta devuelve una fila, el usuario queda autenticado. Este es el comportamiento normal y esperado.

La vulnerabilidad surge cuando un desarrollador construye esta consulta concatenando cadenas directamente a partir de la entrada del usuario:

# Código Python vulnerable
query = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "';"

La suposición es que los usuarios proporcionarán valores normales. Los atacantes no lo hacen.

El ataque: escapar de la cadena

SQL usa comillas simples para delimitar los valores de tipo cadena. Si un atacante proporciona un nombre de usuario que contiene una comilla simple, puede escapar de la cadena prevista e inyectar su propio SQL.

Entrada del atacante:

  • Nombre de usuario: ' OR '1'='1
  • Contraseña: anything

Consulta resultante:

SELECT * FROM users WHERE username = '' OR '1'='1' AND password = 'anything';

Como OR '1'='1' es siempre verdadero, esta consulta devuelve todos los usuarios. El inicio de sesión tiene éxito para el primer usuario de la base de datos, normalmente un administrador.

Saltarse por completo la comprobación de la contraseña:

  • Nombre de usuario: admin'--
  • El -- es un comentario SQL; todo lo que le sigue se ignora
SELECT * FROM users WHERE username = 'admin'--' AND password = 'anything';
-- Se convierte en:
SELECT * FROM users WHERE username = 'admin';

Se omite la autenticación. El campo de contraseña nunca se comprueba.

Más allá de la autenticación: extraer datos

La inyección SQL no se limita a saltarse la autenticación. Los ataques más graves extraen datos de toda la base de datos.

Inyección basada en UNION

El operador SQL UNION combina los resultados de dos sentencias SELECT. Un atacante puede usarlo para recuperar datos de otras tablas:

-- Consulta original
SELECT name, description FROM products WHERE id = 1;

-- Inyectada
SELECT name, description FROM products WHERE id = 1
UNION SELECT username, password FROM users--;

Esto añade todos los nombres de usuario y contraseñas a los resultados de productos devueltos al atacante.

Inyección SQL a ciegas

Muchas aplicaciones no muestran a los usuarios los errores de la base de datos ni los resultados de las consultas. La inyección SQL a ciegas extrae datos bit a bit haciendo preguntas de verdadero/falso:

-- ¿Es el primer carácter de la contraseña del administrador una 'a'?
SELECT * FROM users WHERE id = 1 AND SUBSTRING(password, 1, 1) = 'a';

Si la página se comporta de forma diferente cuando la condición es verdadera frente a cuando es falsa, el atacante puede inferir la respuesta. Herramientas automatizadas como sqlmap pueden extraer bases de datos enteras mediante inyección a ciegas en cuestión de minutos.

Consultas fuera de banda y apiladas

En algunos sistemas de bases de datos, los atacantes pueden:

  • Ejecutar múltiples sentencias (consultas apiladas): eliminar tablas, crear cuentas de puerta trasera
  • Leer archivos del sistema de archivos del servidor (LOAD_FILE() en MySQL)
  • Escribir archivos en el servidor (creando potencialmente una web shell)
  • Desencadenar conexiones de red para exfiltrar datos fuera de banda

En el peor de los casos, la inyección SQL significa un compromiso completo del servidor, no solo la exposición de datos.

Las defensas que realmente funcionan

Defensa 1: consultas parametrizadas (sentencias preparadas)

Esta es la defensa principal y elimina la inyección SQL, no simplemente la reduce.

Con una consulta parametrizada, el código SQL y los datos se envían a la base de datos por separado. La base de datos compila primero la plantilla SQL y luego enlaza los valores proporcionados por el usuario. Los valores nunca pueden interpretarse como SQL: siempre se tratan como datos.

Python con consulta parametrizada:

# Seguro
cursor.execute(
    "SELECT * FROM users WHERE username = %s AND password = %s",
    (username, password)
)

Java con PreparedStatement:

PreparedStatement stmt = conn.prepareStatement(
    "SELECT * FROM users WHERE username = ? AND password = ?"
);
stmt.setString(1, username);
stmt.setString(2, password);

Sin importar lo que el usuario introduzca en el campo username —incluido ' OR '1'='1—, se trata como un valor de cadena literal, no como SQL. La inyección es imposible.

Defensa 2: ORM y constructores de consultas

Los mapeadores objeto-relacional (ORM) como SQLAlchemy, Hibernate, ActiveRecord y Django ORM usan consultas parametrizadas internamente. Usar un ORM correctamente previene la inyección SQL en casi todos los casos:

# Django ORM — seguro
User.objects.filter(username=username, password=password)

Precaución: la mayoría de los ORM tienen vías de escape para SQL sin procesar (raw(), execute()) que reintroducen el riesgo de inyección si se concatena la entrada del usuario. Trata los métodos de SQL sin procesar con el mismo cuidado que la construcción manual de consultas.

Defensa 3: procedimientos almacenados

Los procedimientos almacenados pueden ser seguros si se implementan correctamente: deben usar entradas parametrizadas internamente. Un procedimiento almacenado que concatena cadenas internamente sigue siendo vulnerable.

Defensa 4: principio de privilegio mínimo

La cuenta de base de datos que usa la aplicación web debería tener solo los permisos que necesita:

  • Una aplicación con muchas lecturas solo necesita SELECT
  • Ninguna aplicación debería ejecutarse como root, sa o DBA
  • Distintos componentes de la aplicación pueden usar distintas cuentas de base de datos con distintos permisos

Esto limita el impacto de una inyección exitosa: un atacante que solo puede hacer SELECT no puede eliminar tablas ni escribir archivos.

Defensa 5: validación de entrada

Valida que las entradas coincidan con su formato esperado:

  • Un ID de usuario debería ser un entero positivo: rechaza cualquier otra cosa antes de que llegue a la consulta
  • El nombre de un producto no debería contener palabras clave de SQL: usa una lista de permitidos con los caracteres esperados

La validación de entrada es una medida de defensa en profundidad, no un control principal. Reduce la superficie de ataque, pero no debería ser la única protección.

Defensa 6: WAF (cortafuegos de aplicaciones web)

Un WAF puede detectar y bloquear los patrones comunes de inyección SQL. Es una capa adicional, no un sustituto de las consultas parametrizadas. Los WAF pueden eludirse con trucos de ofuscación y codificación. No confíes en ellos como tu única defensa.

Pruebas de inyección SQL

Nociones básicas de pruebas manuales:

  1. Introduce una comilla simple (') en cada campo de entrada: los mensajes de error de la base de datos a menudo revelan los puntos de inyección
  2. Prueba 1=1 y 1=2 en los parámetros numéricos y compara las respuestas
  3. Prueba '; SELECT SLEEP(5);--: si la respuesta se retrasa, hay una inyección a ciegas

Herramientas automatizadas:

  • sqlmap: la herramienta estándar para la detección y explotación (solo contra sistemas que estés autorizado a probar)
  • Burp Suite: intercepta y manipula solicitudes; tiene un escáner de inyección SQL en la edición Pro
  • OWASP ZAP: escáner gratuito con detección de inyección SQL

Lista de verificación de remediación

  • Reemplaza toda la concatenación de cadenas en las consultas de base de datos por consultas parametrizadas
  • Audita todas las llamadas de SQL sin procesar en el código ORM
  • Aplica cuentas de base de datos con privilegio mínimo
  • Activa la supresión de errores de la base de datos en producción (los errores exponen información del esquema)
  • Revisa y prueba los procedimientos almacenados
  • Añade reglas de WAF como capa adicional
  • Ejecuta sqlmap o su equivalente contra el entorno de pruebas antes de cada lanzamiento

La inyección SQL tiene una solución completa y bien comprendida. No hay razón para que aparezca en código nuevo. La única barrera es la concienciación y la disciplina durante el desarrollo.

#SQL injection#web security#OWASP#secure coding#databases