Guía de tecnologías

Protección contra inyección SQL: guía práctica

7 min read Seguridad Actualizado 27 Sep 2025
Protección contra inyección SQL
Protección contra inyección SQL

Servidor con base de datos y candado que simboliza seguridad de bases de datos

¿Qué es la inyección SQL?

SQL (Structured Query Language) es el lenguaje estándar para gestionar datos en bases de datos relacionales. Una inyección SQL sucede cuando un atacante inserta fragmentos de código SQL malicioso dentro de entradas que la aplicación incorpora, provocando que la base de datos ejecute instrucciones no previstas.

Definición rápida: inyección SQL — inserción de código SQL malicioso en campos de entrada que no están correctamente validados.

Tipos frecuentes:

  • Error-based (basada en errores): el atacante provoca mensajes de error para extraer información.
  • Boolean-based / Blind SQLi: se deducen datos mediante respuestas booleanas.
  • Time-based: se usan retardos (SLEEP) para inferir datos.
  • Union-based: se combinan resultados con UNION SELECT.

¿Cómo ocurre una inyección SQL? — ejemplo práctico

Una forma común es construir cadenas SQL concatenando valores provenientes de formularios. Ejemplo vulnerable (PHP):

Si un usuario legítimo introduce:

  • username: computer
  • password: comp123

La consulta resultante será:

SELECT * FROM users WHERE username='computer' AND user_password='comp123';

Pero si un atacante en el campo de contraseña introduce la cadena:

‘ OR ‘a’=’a

La consulta se convierte en:

SELECT * FROM users WHERE username='computer' AND user_password='' OR 'a'='a';

Dado que ‘a’=’a’ siempre es verdadero, la condición puede evaluarse como verdadera para filas existentes y el atacante obtiene acceso sin credenciales válidas.

Importante: concatenar entradas de usuarios dentro de consultas SQL sin control es la raíz de la mayoría de ataques por inyección.

Principios básicos de defensa

  1. Validación y saneamiento de entradas.
  2. Uso de consultas parametrizadas (prepared statements).
  3. Principio de privilegios mínimos (mínima exposición de cuentas de BD).
  4. Manejo seguro de errores (no mostrar mensajes de BD al usuario).
  5. Registro y detección de anomalías.

Saneamiento de entradas: buenas prácticas

  • Preferir listas blancas (allow-lists) por tipo y formato: por ejemplo, validar que un campo numérico sólo contenga dígitos.
  • Eliminar espacios en blanco extremos y caracteres de control.
  • Para emails, validar contra una expresión regular que limite los caracteres permitidos.
  • Nunca confiar en validación solo en el cliente; siempre validar en el servidor.

Ejemplo de escape (no recomendado como única defensa):

mysqli_real_escape_string añade barras invertidas antes de comillas y otros caracteres, pero no sustituye a las consultas parametrizadas ni a una validación adecuada.

Consultas parametrizadas (recomendado)

Separar código SQL de datos es la defensa más eficaz. Ejemplos: mysqli con prepared statements y PDO.

Ejemplo con mysqli (procedural):

Ejemplo con PDO:

prepare('SELECT * FROM users WHERE username = :username AND user_password = :password');
$stmt->execute(['username' => $_POST['username'], 'password' => $_POST['password']]);
$row = $stmt->fetch();
?>

Las consultas preparadas tratan los valores como datos, no como código, evitando la ejecución de fragmentos maliciosos.

Principio de privilegios mínimos

No uses una cuenta con privilegios administrativos para operaciones cotidianas de la aplicación. Limita permisos a lo estrictamente necesario (SELECT, INSERT, UPDATE en tablas concretas).

Ejemplo de restricciones para Microsoft SQL Server (ejemplo de comandos):

DENY SELECT ON sys.tables TO sqldatabasepermit;
DENY SELECT ON sys.packages TO sqldatabasepermit;
DENY SELECT ON sys.sysobjects TO sqldatabasepermit;

Explicación: negando SELECT en vistas de sistema se reduce la posibilidad de que el atacante obtenga información interna.

Manejo seguro de errores y mensajes

No devuelvas mensajes de error de la base de datos al usuario final. Registra mensajes completos en logs internos con acceso restringido y muestra al usuario mensajes genéricos.

Ejemplo:

  • Log interno: “DB error: syntax error near ‘…’; query: …”
  • Mensaje al usuario: “Ocurrió un error. Intente de nuevo más tarde.”

Detección y registro

  • Registra consultas fallidas y patrones inusuales (múltiples intentos, consultas largas, presencia de palabras clave SQL dentro de campos).
  • Implementa alertas para picos de errores o consultas con tiempo de ejecución elevado.

Pruebas y criterios de aceptación

Criterios de aceptación para una entrada protegida:

  • Validación de formato aplicada (allow-list) en servidor.
  • Consultas parametrizadas implementadas en endpoints críticos.
  • La cuenta de BD usada por la app no tiene permisos administrativos.
  • Mensajes de error de BD no se muestran al usuario.

Casos de prueba básicos:

  1. Intento de inyección clásica: enviar “‘ OR ‘1’=’1” en campos y verificar que la autenticación falla.
  2. Campo numérico: enviar texto con símbolos y verificar rechazo.
  3. Endpoint crítico: revisar logs para ver consultas preparadas vs. concatenadas.

Checklist por rol

Desarrollador:

  • Usar queries parametrizadas en todas las entradas que acceden a la BD.
  • Aplicar validación en servidor (allow-lists).
  • Evitar concatenación dinámica de SQL.

DBA/Administrador de BD:

  • Crear cuentas con privilegios mínimos.
  • Revisar roles y permisos periódicamente.
  • Habilitar y proteger auditoría de consultas.

Equipo de Seguridad / SOC:

  • Monitorizar patrones de inyección y alertar sobre picos.
  • Mantener playbook de respuesta a incidentes.

Runbook de incidente (respuesta rápida)

  1. Detectar: alerta por intento de inyección o comportamiento anómalo.
  2. Contener: bloquear la cuenta/API key comprometida y aplicar reglas WAF temporales.
  3. Investigar: revisar logs, consultas y accesos, determinar alcance.
  4. Remediar: corregir código vulnerable, revocar credenciales comprometidas, aplicar parches.
  5. Recuperar: restaurar acceso controlado y monitorizar.
  6. Comunicar: informar a stakeholders y, si aplica, cumplir obligaciones legales/regulatorias.

Alternativas y medidas complementarias

  • Web Application Firewall (WAF): filtro adicional que bloquea patrones conocidos de inyección.
  • ORM seguro: frameworks y ORM (p. ej. Doctrine, Eloquent) que abstraen consultas y usan parámetros.
  • Escaneo dinámico y estático: usar SAST y DAST para detectar vulnerabilidades en código y en ejecución.

Mini-metodología para endurecer una aplicación (5 pasos)

  1. Inventario: localizar todos los puntos que ejecutan consultas SQL.
  2. Priorizar: endpoints de autenticación y modificación de datos primero.
  3. Remediar: introducir validación y prepared statements.
  4. Verificar: ejecutar pruebas de penetración centradas en SQLi.
  5. Monitorizar: activar alertas y auditoría continua.

Cuándo estas medidas no bastan (limitaciones)

  • Fallas en la lógica de la aplicación (por ejemplo, usar eval() u otras execuciones dinámicas) pueden permitir evasiones.
  • Vulnerabilidades en componentes de terceros que ejecutan SQL internamente.
  • Exposición por credenciales expuestas fuera del ciclo (por ejemplo, secretos en repositorios públicos).

Glosario (1 línea cada término)

  • Prepared statement: consulta SQL precompilada que separa código y datos.
  • Allow-list: conjunto de valores o patrones permitidos para un campo.
  • Privilegios mínimos: asignar solo los permisos necesarios a una cuenta.
  • WAF: firewall de aplicaciones web que filtra tráfico malicioso.

Plantilla rápida: fragmentos de código (cheat sheet)

  • PHP + mysqli (prepared): ya mostrado arriba.
  • PHP + PDO (prepared): ya mostrado.
  • Validación simple de email (PHP):
function validar_email($email) {
  return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}

Diagrama de decisión (flujo básico)

flowchart TD
  A[Inicio: petición entrante] --> B{¿Entrada valida?}
  B -- No --> C[Rechazar y registrar]
  B -- Sí --> D{¿Consulta a BD?}
  D -- No --> E[Procesar sin BD]
  D -- Sí --> F{¿Usa prepared statement?}
  F -- Sí --> G[Ejecutar y devolver resultado]
  F -- No --> H[Bloquear/Marcar para revisión]

Resumen final

La inyección SQL sigue siendo una de las amenazas más comunes para aplicaciones que usan bases de datos relacionales. La defensa eficaz combina validación y saneamiento de entradas, uso de consultas parametrizadas, cuentas con privilegios mínimos, manejo seguro de errores y monitorización. Implementa pruebas continuas y prepara un runbook de respuesta ante incidentes para minimizar impacto.

Notas finales

  • Aprender de expertos y de ejercicios prácticos (laboratorios controlados) mejora la capacidad para detectar y mitigar ataques.
  • Las medidas aquí descritas son esenciales, pero la seguridad es un proceso iterativo, no un estado fijo.

Criterios de aceptación

  • Todas las rutas que acceden a la base de datos usan consultas parametrizadas.
  • Validación de entrada implementada en servidor para campos críticos.
  • Cuenta de aplicación con permisos mínimos y auditoría habilitada.
Autor
Edición

Materiales similares

Instalar Asterisk: guía para tu primera PBX
Telefonía

Instalar Asterisk: guía para tu primera PBX

Cómo arreglar Microsoft Store que no funciona
Soporte técnico

Cómo arreglar Microsoft Store que no funciona

Cómo escanear y asegurar un sitio WordPress
Seguridad

Cómo escanear y asegurar un sitio WordPress

Hilos de foro a RSS con Blogger
Guías

Hilos de foro a RSS con Blogger

Instalar OCS Inventory NG 2 en CentOS 5.5
Linux

Instalar OCS Inventory NG 2 en CentOS 5.5

Función CHAR en Google Sheets: símbolos y saltos
Hojas de cálculo

Función CHAR en Google Sheets: símbolos y saltos