Artículos sobre: Solución de problemas
Este artículo también está disponible en:

Inyección SQL: ¿Qué es y cómo puedes protegerte?

¿Qué es la Inyección SQL?


La Inyección SQL (SQLi) continúa en la cima de las vulnerabilidades más peligrosas de la web por una razón simple: es fácil de explotar y devastadora para el negocio. El ataque ocurre cuando la aplicación acepta datos del usuario y, en lugar de tratarlos solo como información, termina concatenando todo directamente en la cadena de la consulta SQL. Con esto, la base de datos interpreta el texto malicioso como si fuera una orden del propio sistema.


Si tu sistema junta variables de formularios o URLs directamente en la query, básicamente has abierto la puerta para que cualquiera acceda, modifique o elimine tus datos sensibles.


El ataque en la vida real


Pensando en un sistema de autenticación común, la aplicación recibe el correo electrónico ingresado y arma la búsqueda. Si un atacante completa el campo de correo con el siguiente valor:


'admin@ejemplo.com' OR '1'='1'


La query procesada por el servidor quedará así:


SELECT * FROM usuarios WHERE email = 'admin@ejemplo.com' OR '1'='1' AND senha = '...';


Como la condición '1'='1' siempre es verdadera, la base de datos ignora el resto de la validación. El atacante logra burlar la verificación de la contraseña y gana acceso directo a la cuenta del administrador.


Cómo proteger tu código paso a paso


La regla de oro del desarrollo seguro es universal: nunca confíes en lo que viene del usuario. A continuación, mira cómo aplicar las principales defensas usando Node.js y Python.


Consultas Parametrizadas (Prepared Statements)


Esta es la línea de defensa más importante. En lugar de armar cadenas dinámicas, defines la estructura de la query primero y pasas los datos del usuario como argumentos aislados. El driver de la base de datos garantiza que estos parámetros sean tratados estrictamente como valores de texto, neutralizando cualquier comando oculto.


Ejemplo en JavaScript (Node.js + paquete pg)


// DE LA FORMA INCORRECTA: Concatenación peligrosa
const query = `SELECT * FROM usuarios WHERE email = '${req.body.email}'`;
const result = await pool.query(query);

// DE LA FORMA CORRECTA: El driver aísla el contenido de $1
const query = 'SELECT * FROM usuarios WHERE email = $1';
const values = [req.body.email];
const result = await pool.query(query, values);


Ejemplo en Python (driver psycopg2)


# DE LA FORMA INCORRECTA: La formatación de cadena genera la query antes del envío
query = f"SELECT * FROM usuarios WHERE email = '{user_input}'"
cursor.execute(query)

# DE LA FORMA CORRECTA: Los datos van separados de la estructura de la query
query = "SELECT * FROM usuarios WHERE email = %s"
cursor.execute(query, (user_input,))


Nota: Aunque Python use %s o ? en el texto de la query, esto no es una interpolación común de cadenas. El driver envía el comando y los parámetros en canales separados a la base de datos.


Validación y Sanitización de la Entrada


Frenar el problema antes de que se acerque a la base de datos ahorra procesamiento y aumenta la seguridad. Asegúrate de que el dato recibido siga el formato esperado por la aplicación.


Validación en Node.js

// Forzando la conversión para garantizar un número entero en la ruta
const userId = parseInt(req.params.id, 10);

if (isNaN(userId)) {
return res.status(400).json({ error: "ID inválido." });
}


Validación en Python

import re

# Verificando el formato del correo con una expresión regular antes de usarlo en la búsqueda
email_pattern = r"^[\w\.-]+@[\w\.-]+\.\w+$"

if not re.match(email_pattern, user_input):
raise ValueError("Formato de correo electrónico inválido.")


Ecosistema de ORMs Actualizados


Las herramientas de ORM modernas manejan la parametrización de forma nativa por debajo de la mesa en la mayor parte de las llamadas.


  • En el ecosistema JS (Sequelize, Prisma): Las consultas estructuradas a través de User.findOne({ where: { email } }) ya nacen protegidas.
  • En el ecosistema Python (SQLAlchemy, Django ORM): Métodos como User.objects.filter(email=user_input) frenan el SQLi automáticamente.


Presta atención si necesitas escribir queries puras (raw SQL) dentro de estos frameworks. Funciones como db.execute("SELECT...") pierden la protección automática y exigen parametrización manual idéntica a los ejemplos anteriores.


Sustituir la concatenación de cadenas por consultas parametrizadas resuelve la inmensa mayoría de los riesgos de SQL Injection. Unir esta práctica con la validación rigurosa de los payloads recibidos blinda el ecosistema y garantiza la integridad de los datos de la aplicación.

Actualizado el: 30/06/2026

¿Este artículo te resultó útil?

Comparte tu opinión

Cancelar

¡Gracias!