Tema 11

11. Inyecciones en APIs: SQL, NoSQL, comandos, plantillas y serialización insegura

Una API no existe aislada: consulta bases de datos, llama a servicios internos, procesa plantillas, manipula archivos y deserializa datos. Cuando las entradas controladas por el cliente alcanzan esas capas sin las defensas adecuadas, aparecen las inyecciones. Su peligro no está solo en el dato malicioso, sino en que la API lo interpreta como instrucciones en lugar de tratarlo como simple información.

Objetivo Entender cómo las entradas terminan ejecutándose en capas internas
Enfoque Patrones de inyección, impacto y prevención real
Resultado Reducir interpretación peligrosa de datos controlados por el cliente

11.1 Introducción

Las inyecciones siguen siendo una familia crítica de vulnerabilidades porque aprovechan una situación muy común: la aplicación construye una instrucción para otra capa usando datos que provienen, directa o indirectamente, del cliente. Si esos datos no se separan bien de la lógica o del comando, el atacante puede modificar el significado de la operación.

En APIs REST, estas fallas pueden aparecer en búsquedas, filtros, generación de reportes, consultas dinámicas, llamadas al sistema operativo, rendering de plantillas, deserialización de objetos o procesamiento de documentos. El hecho de que la API reciba JSON en lugar de formularios tradicionales no elimina este riesgo. Solo cambia la forma en que el input llega al backend.

Este tema estudia las variantes más relevantes para APIs modernas: inyección SQL, NoSQL, comandos, plantillas y serialización insegura.

11.2 Qué es una inyección

Una inyección ocurre cuando datos controlados por el atacante son interpretados como parte de una instrucción, consulta o estructura ejecutable en una capa posterior del sistema. El problema central no es el texto raro o el carácter especial en sí, sino la pérdida de separación entre datos y lógica.

En términos generales, hay una inyección cuando:

  • La API recibe datos del cliente.
  • Construye una instrucción usando concatenación, interpolación o parsing inseguro.
  • La capa destino interpreta parte del input como comando, consulta o expresión.
Una buena regla mental es esta: si el backend “arma” una instrucción con texto dinámico a partir de entrada externa, hay que asumir riesgo de inyección hasta demostrar lo contrario.

11.3 Por qué las APIs siguen siendo vulnerables

Existe el mito de que las APIs modernas, al usar frameworks, ORMs y JSON, ya no sufren inyecciones. En realidad, las inyecciones persisten porque:

  • Se construyen consultas dinámicas para filtros, ordenamientos o búsquedas avanzadas.
  • Se permiten operadores complejos en query parameters o cuerpos JSON.
  • Se llaman herramientas del sistema con argumentos derivados del cliente.
  • Se usan motores de plantillas o serialización en forma insegura.
  • Se mezclan datos externos con configuraciones, scripts o pipelines internos.

11.4 Inyección SQL

La inyección SQL ocurre cuando datos controlados por el cliente alteran la consulta que la aplicación envía a una base relacional. Aunque hoy existen ORMs y consultas preparadas, el riesgo sigue presente cuando el código arma condiciones dinámicas, ordenamientos o fragmentos SQL a partir de entradas no controladas.

Escenarios frecuentes en APIs:

  • Endpoints de búsqueda con filtros libres.
  • Ordenamientos definidos por parámetro de query.
  • Reportes o exportaciones construidos dinámicamente.
  • Combinación de múltiples filtros opcionales sin parametrización correcta.

11.5 Impacto de la inyección SQL

Una SQL Injection puede permitir mucho más que leer datos. Según privilegios y contexto, también puede modificar, borrar, insertar o incluso pivotear hacia otras capacidades del entorno.

Capacidad obtenida Consecuencia posible
Lectura arbitraria Exfiltración masiva de datos sensibles
Modificación de registros Fraude, corrupción de estados o pérdida de integridad
Borrado de datos Daño operativo o sabotaje
Bypass de filtros lógicos Acceso indebido a recursos o resultados

11.6 Cómo prevenir SQL Injection

La defensa principal es separar completamente datos e instrucciones mediante consultas parametrizadas o mecanismos equivalentes del framework o driver. Pero eso no siempre alcanza si se interpolan partes estructurales como nombres de columnas, operadores o fragmentos enteros.

Buenas prácticas clave:

  • Usar consultas preparadas y parámetros bind.
  • Evitar concatenación manual de SQL.
  • Restringir por allowlist columnas y operadores válidos.
  • Aplicar validación fuerte a filtros, ordenamientos y paginación.
  • Ejecutar con el mínimo privilegio posible en base de datos.

11.7 Inyección NoSQL

Las bases NoSQL y motores documentales no están exentos de inyección. El problema aparece cuando el backend construye consultas dinámicas con objetos o estructuras que incluyen operadores controlados por el cliente.

Ejemplos típicos:

  • Permitir que el cliente envíe operadores de consulta directamente.
  • Mapear filtros JSON sin normalización ni allowlist.
  • Construir expresiones de búsqueda o agregación con datos no validados.

Una entrada maliciosa puede cambiar el significado de la consulta, ampliar el conjunto de resultados o saltear restricciones lógicas previstas por la API.

11.8 Particularidades de la inyección NoSQL

La inyección NoSQL suele pasar desapercibida porque el código parece “tipado” o estructurado, y no usa cadenas SQL clásicas. Pero el riesgo sigue siendo el mismo: la API permite que el cliente influya en la estructura de la consulta, no solo en sus valores.

Se vuelve especialmente peligrosa cuando:

  • Se aceptan objetos arbitrarios en filtros.
  • Se habilitan operadores complejos sin control.
  • La query resultante depende casi por completo del payload del cliente.
  • La API usa deserialización genérica sobre filtros dinámicos.

11.9 Inyección de comandos del sistema

La command injection ocurre cuando la API construye y ejecuta comandos del sistema operativo usando entradas controladas por el cliente. Esto puede suceder en tareas como conversión de archivos, procesamiento multimedia, compresión, ping, diagnósticos, backups o scripts operativos.

Riesgos típicos:

  • Ejecución de comandos arbitrarios.
  • Lectura o modificación de archivos locales.
  • Pivoting hacia otros servicios del entorno.
  • Compromiso total del host o contenedor.
Invocar herramientas del sistema desde una API no es necesariamente inseguro. Lo inseguro es construir el comando mezclando entrada del cliente y semántica del shell sin separación estricta.

11.10 Prevención de command injection

La mejor defensa suele ser evitar el shell por completo. Cuando sea posible, conviene usar librerías nativas o invocaciones con argumentos estructurados sin interpretación por shell.

Recomendaciones:

  • No construir comandos con concatenación de cadenas.
  • Usar APIs del sistema que separen ejecutable y argumentos.
  • Aplicar allowlist estricta sobre parámetros permitidos.
  • Ejecutar procesos con privilegios mínimos y aislamiento.
  • Evitar pasar nombres de archivo, rutas o flags sin validación estricta.

11.11 Template Injection

La inyección en plantillas aparece cuando datos controlados por el usuario son interpretados por un motor de templates como expresiones, variables o instrucciones ejecutables. Aunque suele asociarse a interfaces HTML, también puede aparecer en generación de correos, documentos, reportes o mensajes dinámicos expuestos por APIs.

El riesgo es mayor cuando la aplicación permite personalización avanzada, renderizado dinámico o almacenamiento de contenido que luego pasa por una plantilla sin aislamiento adecuado.

11.12 Serialización y deserialización insegura

La serialización convierte objetos o estructuras en formatos transportables; la deserialización hace el camino inverso. El problema aparece cuando la API acepta datos serializados que luego reconstruyen estructuras internas complejas, activan comportamientos inesperados o permiten manipular tipos y propiedades críticas.

Riesgos frecuentes:

  • Reconstrucción de objetos con campos no esperados.
  • Ejecución de lógica asociada a tipos o metadatos serializados.
  • Mass assignment y sobreescritura de propiedades internas.
  • Fallas de validación al confiar en formatos complejos.

11.13 Deserialización insegura y APIs modernas

En APIs modernas este riesgo no siempre aparece como deserialización binaria clásica. A veces se manifiesta como mapeo automático excesivo desde JSON hacia modelos internos, eventos, expresiones o estructuras complejas que luego activan lógica no prevista.

Ejemplos prácticos:

  • Deserializar directamente sobre entidades del dominio.
  • Aceptar metadatos de tipo o referencia en payloads complejos.
  • Permitir objetos anidados con poca restricción de forma y propiedades.
  • Usar librerías con configuraciones permissivas o peligrosas por defecto.

11.14 Inyecciones indirectas a través de integraciones

No toda inyección se ejecuta en la primera capa del backend. A veces la API recibe una entrada, la almacena o la reenvía, y el efecto peligroso aparece más adelante cuando otro componente la interpreta. Esto puede suceder con colas, workers, motores de reportes, sistemas de búsqueda, ETL, plantillas o scripts de administración.

Ese carácter indirecto hace que la vulnerabilidad sea más difícil de detectar y a veces más dañina, porque cruza límites entre componentes que se suponen desacoplados.

11.15 Inyecciones y filtros de búsqueda

Las APIs que ofrecen búsqueda avanzada son especialmente sensibles. Permitir filtros complejos, operadores dinámicos, expresiones regulares, ordenamientos libres o criterios anidados puede acercar mucho la entrada del cliente a la sintaxis interna del motor de datos.

Cuanto más expresiva es la interfaz de búsqueda, más importante es:

  • Definir un lenguaje de consulta acotado.
  • Traducir ese lenguaje a operaciones internas seguras.
  • No reenviar directamente estructuras arbitrarias del cliente al motor subyacente.

11.16 Principios de mitigación transversales

Aunque cada tipo de inyección tenga particularidades, hay principios defensivos que se repiten:

  • Separar datos de instrucciones.
  • Validar entradas con allowlists y esquemas claros.
  • No concatenar estructuras ejecutables o consultables.
  • Usar APIs seguras del framework o del lenguaje.
  • Aplicar mínimo privilegio en bases, procesos y servicios.
  • Limitar qué partes de una operación pueden ser dinámicas.

11.17 Señales de alerta en el diseño

Hay ciertos olores de diseño que deberían encender alarmas tempranas:

  • Consultas armadas con strings dinámicos.
  • Campos de filtro o sort derivados directamente del cliente.
  • Uso de shell o scripts con parámetros externos.
  • Renderizado de plantillas con contenido editable por usuarios.
  • Deserialización directa a modelos internos ricos en comportamiento.
  • Exposición de lenguajes de consulta demasiado poderosos.

11.18 Errores comunes al mitigar

  • Confiar solo en sanitización superficial de caracteres.
  • Usar ORMs y asumir que todo riesgo desapareció.
  • Parametrizar valores, pero interpolar columnas, operadores o fragmentos completos.
  • Filtrar algunos símbolos y olvidar el contexto real de ejecución.
  • No revisar integraciones, workers o procesos secundarios.
  • Deserializar estructuras complejas sin restricciones fuertes.
La defensa correcta no es “limpiar caracteres peligrosos”. Es diseñar de modo que la entrada nunca pueda convertirse en instrucción.

11.19 Qué debes recordar de este tema

  • Las inyecciones ocurren cuando el sistema interpreta input del cliente como parte de una instrucción o estructura ejecutable.
  • En APIs REST siguen siendo relevantes SQL, NoSQL, comandos, plantillas y deserialización insegura.
  • El riesgo no está solo en el body JSON, sino en cualquier dato que influya sobre consultas, comandos o parsing interno.
  • La mitigación principal es separar datos de lógica, validar por allowlist y usar APIs seguras del framework.
  • Las capas indirectas e integraciones también pueden convertir input en ejecución peligrosa.

11.20 Conclusión

Las inyecciones siguen siendo una amenaza crítica en APIs porque explotan una debilidad estructural: permitir que datos no confiables alteren el significado de consultas, comandos o estructuras internas. El problema no se resuelve solo con frameworks o con JSON; se resuelve diseñando la API y sus capas internas para que la entrada del cliente nunca se mezcle de forma peligrosa con la lógica ejecutable.

En el próximo tema estudiaremos la protección de datos sensibles en requests, responses y logs, para reducir la exposición de información crítica tanto en tránsito como en observabilidad y operación.