La inyección SQL (SQL injection o SQLi) es una vulnerabilidad web en la que un atacante introduce fragmentos de código SQL dentro de los datos que envía a una aplicación, de forma que el gestor de base de datos los interpreta como parte de la consulta y no como simples valores. Cuando la aplicación construye sus consultas concatenando directamente la entrada del usuario, esos fragmentos alteran la lógica original: permiten leer tablas que no deberían ser accesibles, saltarse la autenticación, modificar registros o, en el peor de los casos, ejecutar comandos en el sistema operativo del servidor. Es una de las vulnerabilidades más antiguas y mejor documentadas de la seguridad web, y sigue apareciendo en aplicaciones reales en 2026.
Lo esencial. La inyección SQL nace de mezclar código y datos en la misma cadena. La defensa definitiva no consiste en filtrar caracteres peligrosos, sino en separar código y datos mediante consultas parametrizadas (prepared statements). El resto de capas (validación de entrada, mínimo privilegio en la base de datos, WAF) refuerzan esa separación, pero no la sustituyen.
Cómo funciona la inyección SQL: interpolación de consultas
El origen del problema es la construcción dinámica de consultas. Una aplicación toma un valor que envía el usuario (un nombre, un identificador, un término de búsqueda) y lo inserta dentro de una cadena SQL antes de enviarla al motor. Si esa inserción se hace por concatenación de texto, el motor no distingue entre lo que el programador escribió y lo que introdujo el usuario: todo llega como una única sentencia.
Imaginemos un formulario de login que construye la consulta así:
// Vulnerable: concatenación directa de la entrada del usuario
$user = $_GET['user'];
$sql = "SELECT id, email FROM usuarios WHERE nombre = '$user'";
$result = mysqli_query($conn, $sql);
Si el usuario envía admin, la consulta resultante es inofensiva. Pero si envía ' OR '1'='1' -- , la cadena final se convierte en:
SELECT id, email FROM usuarios WHERE nombre = '' OR '1'='1' -- '
La condición '1'='1' siempre es verdadera y el -- comenta el resto de la línea, así que la consulta devuelve todas las filas de la tabla. En un login mal diseñado, esto equivale a entrar sin credenciales. La misma técnica, con payloads más elaborados, permite extraer datos de otras tablas, encadenar subconsultas o forzar errores que revelan la estructura interna.
La solución correcta separa el código de los datos con parámetros. El motor recibe la plantilla de la consulta y los valores por canales distintos, de modo que el valor nunca puede cambiar la estructura de la sentencia:
// Seguro: consulta parametrizada con PDO
$stmt = $pdo->prepare('SELECT id, email FROM usuarios WHERE nombre = ?');
$stmt->execute([$_GET['user']]);
$rows = $stmt->fetchAll();
Aquí el ? es un marcador de posición. Aunque el usuario envíe ' OR '1'='1, el motor lo trata como un literal de texto y busca un usuario cuyo nombre sea exactamente esa cadena. La inyección deja de ser posible por diseño.
Tipos de inyección SQL
Las inyecciones se clasifican según cómo recupera el atacante la información. Esta taxonomía coincide con la que emplean OWASP y herramientas como sqlmap.
In-band: union-based y error-based
En la inyección in-band, el atacante recibe los resultados por el mismo canal que la petición, directamente en la respuesta de la aplicación.
La variante union-based aprovecha el operador UNION para añadir a la consulta original una segunda consulta cuyos resultados se muestran junto a los legítimos. Primero se determina el número de columnas (por ejemplo con ORDER BY 3-- - o probando UNION SELECT NULL,NULL,NULL) y después se extraen datos: ' UNION SELECT usuario, contrasena FROM users-- -.
La variante error-based fuerza al motor a producir un error cuyo mensaje contiene datos de la propia base. Funciones como EXTRACTVALUE() o UPDATEXML() en MySQL, o la conversión de tipos en SQL Server, hacen que el fragmento inyectado aparezca dentro del texto de error si la aplicación lo muestra al usuario.
Blind: boolean-based y time-based
En la inyección ciega (blind SQL injection) la aplicación no devuelve los datos ni los errores, pero su comportamiento cambia según la consulta. El atacante deduce la información pregunta a pregunta.
La variante boolean-based envía condiciones verdaderas o falsas y observa la diferencia en la respuesta (una página que carga o no, un texto que aparece o desaparece). Con muchas peticiones se reconstruye un dato carácter a carácter.
La variante time-based introduce un retardo condicional y mide el tiempo de respuesta. Cada motor tiene su función:
- MySQL:
' OR SLEEP(5)-- - - PostgreSQL:
'; SELECT pg_sleep(5)-- - - SQL Server:
'; WAITFOR DELAY '0:0:5'-- - - Oracle:
' AND 1=(SELECT COUNT(*) FROM all_users WHERE ROWNUM=1 AND dbms_pipe.receive_message(('a'),5)=1)-- -
Si la respuesta tarda cinco segundos, la condición era verdadera. Es lenta pero fiable, y funciona incluso cuando la aplicación no muestra ninguna diferencia visible.
Out-of-band
Cuando ni la respuesta ni el tiempo son útiles, la inyección out-of-band (OAST) exfiltra datos por un canal secundario, típicamente DNS o HTTP. El motor se fuerza a realizar una petición saliente hacia un dominio controlado por el auditor (xp_dirtree y UNC paths en SQL Server, UTL_HTTP o UTL_INADDR en Oracle, LOAD_FILE con rutas UNC en MySQL). Es la técnica preferida cuando la aplicación es totalmente muda pero el servidor tiene salida de red.
Inyección de segundo orden
En la inyección de segundo orden, el dato malicioso se almacena en un primer momento sin causar daño y se ejecuta después, cuando otra parte de la aplicación lo recupera y lo concatena en una consulta distinta. Es difícil de detectar con escáneres automáticos porque el punto de entrada y el punto de ejecución están separados en el tiempo y en el código.
Detección: sqlmap y payloads manuales
La herramienta de referencia para automatizar la explotación es sqlmap, de código abierto. Detecta el tipo de inyección, identifica el motor y automatiza la extracción:
# Enumerar bases de datos a partir de un parámetro GET
sqlmap -u "https://objetivo.tld/item?id=1" --batch --dbs
# Volcar una tabla concreta
sqlmap -u "https://objetivo.tld/item?id=1" -D appdb -T users --dump
sqlmap acepta peticiones capturadas con Burp (-r peticion.txt), maneja cookies de sesión y ajusta las técnicas por nivel y riesgo. Aun así, ninguna auditoría seria se limita a la herramienta: la confirmación manual con payloads como ', '', ' OR '1'='1, 1-1, 1 AND 1=2 o los retardos time-based sigue siendo imprescindible para entender el contexto, evitar falsos positivos y encontrar puntos que el automatizador no cubre, como cabeceras HTTP, campos JSON o inyecciones de segundo orden. En una auditoría web el flujo habitual combina el crawling y la interceptación con Burp Suite, la validación manual de cada parámetro y el uso puntual de sqlmap para acelerar la explotación una vez confirmado el punto vulnerable.
Prevención: consultas parametrizadas y defensa en profundidad
Consultas parametrizadas (prepared statements)
Es la única defensa que ataca la causa raíz. Al enviar la plantilla y los valores por separado, el valor nunca puede alterar la estructura de la sentencia. Está disponible en todos los lenguajes: PDO y mysqli en PHP, PreparedStatement en Java, cursor.execute(sql, params) en Python, consultas parametrizadas en .NET, pg y mysql2 en Node.js. La regla es simple: ningún dato del usuario debe concatenarse nunca dentro de una cadena SQL.
Una advertencia importante: los parámetros solo sirven para valores, no para identificadores (nombres de tabla o columna) ni para cláusulas dinámicas como ORDER BY. Cuando esos elementos dependen de la entrada del usuario, la protección correcta es una lista blanca (allowlist) que traduzca la entrada a un conjunto cerrado de valores permitidos.
ORM y sus límites
Los ORM (Hibernate, Entity Framework, Django ORM, Sequelize, Eloquent) parametrizan por defecto y eliminan la mayor parte del riesgo. Pero no son inmunes: en cuanto se usan consultas en crudo (raw, extra, HQL con concatenación, expresiones nativas), el ORM deja de proteger y el desarrollador vuelve a ser responsable de parametrizar. Un ORM mal usado es tan vulnerable como el mysqli_query del principio.
Validación de entrada y mínimo privilegio
La validación de entrada con listas blancas (tipos, longitudes, formatos esperados) reduce la superficie, pero es una capa complementaria, no una defensa por sí sola: siempre habrá payloads que pasen un filtro. Más eficaz es aplicar el principio de mínimo privilegio en la base de datos: la cuenta que usa la aplicación no debería poder ejecutar DROP, ni tener el privilegio FILE (que habilita LOAD_FILE e INTO OUTFILE), ni acceder a más esquemas de los necesarios. Así, aunque exista una inyección, el impacto queda acotado. Segmentar cuentas por función y revocar permisos sobre information_schema cuando no se necesitan limita mucho lo que un atacante puede extraer.
WAF como defensa en profundidad
Un WAF (Web Application Firewall) detecta y bloquea patrones de inyección conocidos y aporta una capa útil frente a escaneos automatizados y explotación masiva. Pero es una red de seguridad, no una solución: las técnicas de evasión (codificación, comentarios internos, uso de mayúsculas y minúsculas, sintaxis alternativa por motor) permiten sortear reglas mal ajustadas. El WAF compra tiempo y filtra ruido, pero el código sigue teniendo que estar parametrizado.
Casos reales y CVEs públicos
La inyección SQL no es un problema histórico. En 2023, la vulnerabilidad CVE-2023-34362 en MOVEit Transfer, una inyección SQL en la aplicación web de transferencia de ficheros, fue explotada de forma masiva por el grupo de ransomware Cl0p para robar datos de miles de organizaciones. Es uno de los incidentes de mayor impacto de la década y su vector inicial fue, precisamente, una SQLi. Años antes, la brecha de Heartland Payment Systems y varias de las intrusiones atribuidas a Albert Gonzalez partieron también de inyecciones SQL contra aplicaciones expuestas.
En el catálogo público, la inyección SQL corresponde a CWE-89. Búsquedas en el NVD por SQL injection devuelven entradas constantes en CMS, plugins, paneles de administración, dispositivos de red y software empresarial sin actualizar. El patrón se repite: un parámetro concatenado, una cuenta de base de datos con demasiados privilegios y ausencia de consultas parametrizadas.
Encaje con OWASP Top 10
La inyección SQL se clasifica dentro de A03:2021 Injection del OWASP Top 10, categoría que en la edición de 2021 fusionó la inyección clásica con el cross-site scripting. Su metodología de prueba está descrita en la OWASP Web Security Testing Guide (WSTG-INPV-05). Aunque la posición relativa de la categoría bajó respecto a ediciones anteriores gracias a la adopción de frameworks que parametrizan por defecto, sigue siendo una de las clases de vulnerabilidad más críticas por su impacto directo sobre la confidencialidad e integridad de los datos. Puedes ver el contexto completo en nuestro análisis del OWASP Top 10 2025 y en el repaso de las 5 vulnerabilidades web más comunes, donde la inyección convive con vectores relacionados como XSS y CSRF.
Preguntas frecuentes
¿La inyección SQL sigue siendo peligrosa en 2026?
Sí. A pesar de tener más de dos décadas, sigue apareciendo en auditorías y en incidentes reales. Casos como MOVEit (CVE-2023-34362) demuestran que un único punto de inyección puede provocar una brecha masiva. El riesgo persiste en código heredado, consultas en crudo dentro de ORM, plugins de terceros y endpoints añadidos sin revisar.
¿Un ORM me protege de la inyección SQL?
Parcialmente. Los ORM parametrizan por defecto y eliminan la mayoría del riesgo, pero dejan de protegerte en cuanto usas consultas en crudo o construyes fragmentos concatenando entrada del usuario. La responsabilidad de parametrizar vuelve al desarrollador en esos casos.
¿Qué diferencia hay entre inyección SQL clásica y ciega?
En la inyección clásica (in-band) los datos vuelven en la respuesta o en un mensaje de error. En la inyección ciega (blind) la aplicación no muestra datos ni errores, pero su comportamiento o su tiempo de respuesta cambian según la consulta, lo que permite deducir la información pregunta a pregunta con las variantes boolean-based y time-based.
¿Es suficiente un WAF para detener la inyección SQL?
No. Un WAF es defensa en profundidad: bloquea patrones conocidos y frena la explotación automatizada, pero existen técnicas de evasión que sortean reglas mal ajustadas. La corrección real es parametrizar las consultas en el código. El WAF complementa, no sustituye.
¿Cómo compruebo si mi aplicación es vulnerable?
Combina revisión de código (buscar concatenación de entrada en consultas) con pruebas dinámicas: payloads manuales por cada parámetro, cabecera y campo JSON, y automatización puntual con sqlmap. Lo más fiable es una auditoría de aplicación web profesional que cubra los puntos que los escáneres no detectan, como las inyecciones de segundo orden.
Recursos relacionados
- Pentesting de aplicaciones web
- OWASP Top 10 2025: vulnerabilidades para empresas
- Las 5 vulnerabilidades web más comunes
- Qué es XSS (cross-site scripting)
- Qué es CSRF (cross-site request forgery)
- Qué es SSRF (server-side request forgery)
- Qué es un WAF y para qué sirve
Auditar inyección SQL con Secra
Secra realiza auditorías de aplicaciones web alineadas con OWASP Top 10 y la OWASP Web Security Testing Guide. Probamos cada parámetro, cabecera y campo de la aplicación en busca de inyección SQL in-band, ciega y out-of-band, confirmamos manualmente los hallazgos, verificamos la parametrización de las consultas y revisamos los privilegios de las cuentas de base de datos para acotar el impacto.
Entregamos hallazgos priorizados, pruebas de concepto reproducibles y recomendaciones de hardening específicas para vuestra arquitectura, además de casos de regresión para integrar en CI y evitar que la vulnerabilidad reaparezca. Si necesitáis una revisión profesional, conoced nuestro servicio de auditoría web y móvil o escribidnos desde /es/contacto/ para planificar una auditoría adaptada al alcance de vuestra plataforma.
Sobre el autor
Equipo de Secra Solutions
Ethical hackers certificados OSCP, OSEP, OSWE, CRTO, CRTL y CARTE, con más de 7 años de experiencia en ciberseguridad ofensiva. Autores de los CVE-2025-40652 y CVE-2023-3512.

