La inyección SQL (SQL injection) es una vulnerabilidad de seguridad web que permite a un atacante interferir en las consultas que una aplicación hace a su base de datos, insertando código SQL malicioso en campos de entrada que no se validaron correctamente. Es uno de los fallos más antiguos y más explotados de la historia del hacking web, y sigue ocupando un lugar destacado en el OWASP Top 10 año tras año.
Qué es la inyección SQL y por qué ocurre
La raíz del problema es siempre la misma: la aplicación mezcla datos controlados por el usuario con el código SQL que ejecuta en la base de datos, sin separarlos bien. Cuando un usuario introduce texto en un formulario de login, un buscador o cualquier campo de entrada, esa cadena de texto acaba formando parte de una consulta SQL. Si la aplicación no la trata como dato puro sino como parte ejecutable de la consulta, el atacante puede alterar la lógica de esa consulta a su antojo.
Las causas concretas más frecuentes son:
- Concatenación directa del input del usuario en la cadena SQL.
- Ausencia de consultas parametrizadas o prepared statements.
- Confianza implícita en los datos que llegan del cliente (formularios, cookies, cabeceras HTTP, parámetros GET/POST).
- Exceso de privilegios de la cuenta de base de datos que usa la aplicación.
Cómo funciona: el código vulnerable
El ejemplo clásico es un formulario de login en PHP que construye la consulta así:
// CÓDIGO VULNERABLE — no usar en producción
$usuario = $_POST['usuario'];
$password = $_POST['password'];
$query = "SELECT * FROM usuarios
WHERE usuario = '" . $usuario . "'
AND password = '" . $password . "'";
$resultado = mysqli_query($conexion, $query);
if (mysqli_num_rows($resultado) > 0) {
// sesión iniciada
}
Si un atacante introduce ' OR '1'='1 en el campo de usuario (y cualquier cosa en la contraseña), la consulta que llega a la base de datos se convierte en:
SELECT * FROM usuarios
WHERE usuario = '' OR '1'='1'
AND password = 'lo_que_sea'
La condición '1'='1' es siempre verdadera, así que la consulta devuelve todas las filas de la tabla y el atacante entra sin credenciales válidas. Con variantes más elaboradas puede extraer el esquema completo de la base de datos, leer datos de otras tablas, modificar registros o, en configuraciones extremas, ejecutar comandos en el sistema operativo.
Tipos de inyección SQL
| Tipo | Subtipo | Cómo se detecta | Cómo se explota |
|---|---|---|---|
| In-band | UNION-based | La respuesta muestra datos de la BD directamente en la página | UNION SELECT para añadir columnas con datos de otras tablas |
| Error-based | Los mensajes de error de la BD aparecen en la respuesta HTTP | Funciones como EXTRACTVALUE() o UPDATEXML() fuerzan errores con datos incrustados |
|
| Blind (ciega) | Boolean-based | La respuesta cambia (diferente contenido, redirección) según la condición sea true/false | Preguntas binarias para extraer datos carácter a carácter: AND SUBSTRING(password,1,1)='a' |
| Time-based | No hay diferencia visual, pero el tiempo de respuesta varía | AND IF(condición, SLEEP(5), 0) — si tarda 5 segundos, la condición es verdadera |
|
| Out-of-band | DNS/HTTP exfiltration | No aparece nada en la respuesta normal; requiere canal externo | Funciones como LOAD_FILE() o xp_cmdshell (SQL Server) que generan peticiones DNS/HTTP a un servidor controlado por el atacante |
In-band SQLi
Es el tipo más común y más fácil de explotar porque el resultado llega en el mismo canal de la petición HTTP. En las inyecciones UNION-based el atacante añade una cláusula UNION SELECT para agregar filas de otra tabla a los resultados visibles. Las inyecciones error-based explotan que algunos motores de bases de datos incluyen el valor que causó el error en el mensaje de error, lo que permite extraer datos sin necesidad de UNION.
Blind SQLi
Cuando la aplicación no muestra errores ni datos de la base de datos en la respuesta, el atacante trabaja a ciegas. La variante boolean-based infiere información observando si la respuesta cambia según una condición true/false. La variante time-based usa funciones de retardo (SLEEP, WAITFOR DELAY) para inferir lo mismo a través del tiempo de respuesta. Ambas son más lentas pero igual de peligrosas; herramientas como SQLMap automatizan este proceso.
Out-of-band SQLi
El caso menos frecuente: el atacante no recibe los datos por el canal HTTP normal, sino que los exfiltra mediante peticiones DNS o HTTP a un servidor externo. Requiere que la base de datos tenga permisos especiales (como FILE en MySQL o xp_cmdshell en SQL Server) y que el servidor pueda hacer conexiones salientes.
Ejemplo práctico en laboratorio
Importante: practica SQLi únicamente en entornos controlados y pensados para ello. Intentar estas técnicas contra sistemas sin autorización explícita es un delito en España (art. 197 bis del Código Penal) y en la mayoría de jurisdicciones.
Las tres plataformas recomendadas para practicar son:
- DVWA (Damn Vulnerable Web Application): aplicación PHP/MySQL deliberadamente vulnerable, instalable en local con Docker o XAMPP. Tiene niveles de dificultad (low/medium/high/impossible) y módulo específico de SQL injection.
- OWASP Juice Shop: tienda web moderna vulnerable en Node.js. Cubre SQLi entre decenas de otros retos con sistema de puntuación.
- PortSwigger Web Security Academy: laboratorios en la nube, sin instalación. Cubren desde SQLi básico hasta second-order injection y bypass de WAF. Totalmente gratuitos.
Un ejercicio típico en DVWA con nivel «Low»: en el campo de búsqueda de usuarios introduces 1' y la aplicación lanza un error. Cambias a 1' ORDER BY 1--, 1' ORDER BY 2--… hasta encontrar el número de columnas. Después usas 1' UNION SELECT null, version()-- para ver la versión del motor. Todo esto con Burp Suite o OWASP ZAP interceptando las peticiones para verlas con claridad.
Si quieres profundizar en hacking web más allá de SQLi, consulta nuestra guía completa de hacking web o el curso de hacking web.
Cómo prevenir la inyección SQL
La prevención pide varias capas, pero hay una defensa primaria que, sola, elimina el problema de raíz:
1. Consultas parametrizadas (prepared statements): defensa primaria
La forma correcta de reescribir el ejemplo vulnerable anterior en PHP con PDO:
// CÓDIGO SEGURO — consulta parametrizada con PDO
$stmt = $pdo->prepare(
"SELECT * FROM usuarios WHERE usuario = ? AND password = ?"
);
$stmt->execute([$usuario, $password]);
$resultado = $stmt->fetchAll();
La diferencia de fondo es que la estructura SQL se envía al motor de base de datos primero, del todo separada de los datos. El motor sabe de antemano qué es código y qué son datos, así que ningún carácter especial introducido por el usuario puede alterar la lógica de la consulta. Lo mismo aplica en cualquier lenguaje: PreparedStatement en Java, parameterized queries en Python con psycopg2, $wpdb->prepare() en WordPress, etc.
«The use of prepared statements with variable binding (aka parameterized queries) is how all developers should first be taught how to write database queries.»
2. ORM (Object-Relational Mapping)
Frameworks como Eloquent (Laravel), SQLAlchemy (Python), Hibernate (Java) o ActiveRecord (Rails) generan consultas parametrizadas por defecto. Usar un ORM bien configurado elimina casi toda la superficie de ataque de SQLi, siempre que no se usen métodos de consulta cruda sin parametrización.
3. Mínimo privilegio en la base de datos
La cuenta de base de datos que usa la aplicación web debe tener solo los permisos imprescindibles: SELECT, INSERT, UPDATE sobre las tablas que necesita, y nada más. Sin permisos de DROP, CREATE, acceso a otras bases de datos o ejecución de funciones del sistema. Si hay un SQLi, el daño queda contenido.
4. Validación por lista de permitidos (allow-list)
Para valores que sí deben influir en la estructura de la consulta (nombres de columnas para ordenar, dirección ASC/DESC) y que no se pueden parametrizar, usa una lista blanca explícita en el código:
$columnas_permitidas = ['nombre', 'precio', 'fecha'];
if (!in_array($orden, $columnas_permitidas)) {
$orden = 'nombre'; // valor seguro por defecto
}
$query = "SELECT * FROM productos ORDER BY $orden";
5. WAF (Web Application Firewall) como capa extra, no como sustituto
Un WAF puede detectar y bloquear patrones conocidos de SQLi y añade una capa de defensa adicional. Pero no sustituye a las consultas parametrizadas: los WAF pueden eludirse con ofuscación, codificaciones alternativas o técnicas de bypass. Úsalos como complemento, nunca como solución principal.
Errores comunes que dejan la puerta abierta
- Escapar caracteres en lugar de parametrizar. Funciones como
mysql_real_escape_string()oaddslashes()son frágiles: dependen del charset, tienen casos límite conocidos y se olvidan con facilidad. Las consultas parametrizadas son la solución correcta. - Validar solo en el cliente (JavaScript). Cualquier validación de formulario en el navegador puede saltarse desactivando JS o enviando peticiones directas con Burp. La validación del servidor es obligatoria.
- Confiar en que un WAF protege todo. Ver el punto anterior.
- Exponer mensajes de error detallados. Un error de tipo
You have an error in your SQL syntax near '1''confirma al atacante que hay una inyección y revela el motor. Los errores detallados solo deben aparecer en logs internos, nunca en la respuesta HTTP. - Olvidar los vectores indirectos. SQLi no ocurre solo en formularios de login. Cabeceras HTTP (
User-Agent,X-Forwarded-For), cookies, parámetros de ordenación, campos de búsqueda y hasta importaciones de ficheros pueden ser vectores de entrada. - Second-order (stored) SQLi. El payload se guarda en la BD con escape correcto, pero al recuperarse más adelante y usarse en otra consulta sin parametrizar, se ejecuta. Es el caso más difícil de detectar.
Vídeo recomendado
Para reforzar los conceptos con una demo práctica, este vídeo de S4viSinFiltro (referente en la comunidad de hacking en español) explica SQL injection desde cero con ejemplos en laboratorio:
También puedes practicar en las mejores plataformas para practicar hacking o, si quieres participar en programas reales una vez tengas base, consulta nuestra guía de bug bounty.
📚 ¿Quieres practicarlo en un laboratorio legal, paso a paso? Lo trabajamos en el Módulo 4: Inyección SQL (SQLi) de nuestro Curso de Hacking Web.
Preguntas frecuentes
¿SQL injection sigue siendo relevante en 2025?
Sí. A pesar de llevar décadas documentada, SQLi sigue apareciendo en el OWASP Top 10 (bajo la categoría A03:2021 Injection) y en informes de programas de bug bounty. La causa principal es que sigue habiendo aplicaciones legacy con código antiguo sin actualizar y proyectos nuevos donde los desarrolladores no conocen las prácticas seguras.
¿SQLMap es legal?
SQLMap es una herramienta legítima de auditoría de seguridad. Su uso es perfectamente legal en sistemas propios, en entornos de laboratorio (DVWA, PortSwigger) o en sistemas ajenos con autorización escrita explícita. Usarla sin autorización contra sistemas de terceros es un delito en España (art. 197 bis CP) y en prácticamente todas las jurisdicciones.
¿Qué diferencia hay entre SQLi y NoSQLi?
La inyección NoSQL (NoSQLi) aplica el mismo principio, mezclar datos con código de consulta, pero sobre bases de datos no relacionales como MongoDB, CouchDB o Redis. Los payloads son diferentes (JSON con operadores como $where o $gt en MongoDB) pero el origen del fallo es idéntico: falta de separación entre datos y lógica de consulta.
¿Los ORM protegen al 100% contra SQLi?
En la práctica, sí en la mayoría de casos, siempre que no uses métodos de consulta cruda (raw(), whereRaw(), execute() con concatenación) sin parametrizar. Si un ORM genera consultas parametrizadas por defecto y no metes strings del usuario en métodos de consulta directa, la superficie de ataque de SQLi queda eliminada.
¿Cómo detecto si una aplicación es vulnerable a SQLi?
Los indicadores básicos son: introducir una comilla simple ' y ver si la aplicación devuelve un error SQL, cambia de comportamiento o lanza una excepción no controlada. Herramientas como Burp Suite o SQLMap automatizan esta detección. En el contexto profesional, las revisiones de código (buscar concatenaciones de strings en queries) son el método más fiable.
Aviso ético y legal: las técnicas descritas en este artículo hay que practicarlas únicamente en entornos de laboratorio propios (DVWA, Juice Shop, PortSwigger Academy) o en sistemas para los que dispongas de autorización escrita explícita. En España, el acceso no autorizado a sistemas informáticos está tipificado en el artículo 197 bis del Código Penal y puede conllevar penas de prisión. El conocimiento ofensivo tiene valor solo cuando se usa para defender.
