¿Qué es una Inyección NoSQL?
Es un tipo de ataque en el que un atacante inyecta código malicioso en consultas a bases de datos NoSQL (como MongoDB, CouchDB, etc.). Esto puede permitir al atacante bypassear autenticaciones, robar datos o manipular la base de datos.
¿Cómo funciona?
-
Consulta NoSQL:
Las bases de datos NoSQL usan consultas basadas en objetos JSON o similares, en lugar de SQL. Por ejemplo:db.users.find({ username: "admin", password: "1234" }) -
Inyección:
Si la aplicación no valida correctamente las entradas del usuario, un atacante puede manipular la consulta. Por ejemplo:db.users.find({ username: "admin", password: { "$ne": "" } })- Aquí,
"$ne": ""significa “no igual a vacío”, lo que podría devolver todos los usuarios.
- Aquí,
Operadores Comunes en Inyecciones NoSQL
-
$ne(Not Equal):
Busca valores que no sean iguales a un valor específico.- Ejemplo:
{ password: { "$ne": "" } }devuelve todos los usuarios con contraseña no vacía.
- Ejemplo:
-
$regex:
Permite usar expresiones regulares en las consultas.- Ejemplo:
{ username: { "$regex": ".*admin.*" } }devuelve usuarios cuyo nombre contenga “admin”.
- Ejemplo:
-
.{longitud}:
En expresiones regulares,.coincide con cualquier carácter y{n}especifica la longitud exacta.- Ejemplo:
{ password: { "$regex": ".{8}" } }devuelve usuarios con contraseñas de 8 caracteres.
- Ejemplo:
-
' || 1==1:
En bases de datos NoSQL que permiten ejecutar código JavaScript (como MongoDB con$where), este tipo de inyección puede forzar una condición siempre verdadera.- Ejemplo:
Esto devuelve todos los usuarios porquedb.users.find({ $where: "this.username == 'admin' || 1==1" })1==1siempre es verdadero.
- Ejemplo:
Ejemplo Práctico
-
Escenario: Un formulario de login que usa MongoDB.
-
Código vulnerable:
const user = db.users.findOne({ username: req.body.username, password: req.body.password }); -
Ataque con
$regex:
El atacante envía el siguiente JSON en el campousername:{ "$regex": ".*" }- La consulta resultante sería:
db.users.findOne({ username: { "$regex": ".*" }, password: "1234" }) - Esto devuelve el primer usuario que coincida con cualquier nombre.
- La consulta resultante sería:
-
Ataque con
' || 1==1:
Si la aplicación permite ejecutar código JavaScript:db.users.find({ $where: "this.username == 'admin' || 1==1" })- Esto devuelve todos los usuarios porque
1==1siempre es verdadero.
- Esto devuelve todos los usuarios porque
¿Por qué es peligroso?
- Bypass de autenticación: El atacante puede iniciar sesión sin credenciales válidas.
- Exfiltración de datos: Puede acceder a información sensible de la base de datos.
- Manipulación de datos: Puede modificar o eliminar registros.
¿Cómo prevenir Inyecciones NoSQL?
-
Validar Entradas:
Asegúrate de que las entradas del usuario sean válidas y estén sanitizadas. -
Usar Consultas Parametrizadas:
Utiliza métodos seguros para construir consultas, comofindOnecon parámetros explícitos. -
Escape de Caracteres Especiales:
Escapa caracteres como$,.,[]y||que tienen significado especial en NoSQL. -
Limitar Permisos:
Asegúrate de que la aplicación use una cuenta de base de datos con permisos mínimos necesarios. -
Deshabilitar Ejecución de Código:
Evita el uso de funciones como$whereque permiten ejecutar código JavaScript.
Resumen
- Inyección NoSQL: Ataque donde el atacante manipula consultas NoSQL para bypassear autenticaciones o robar datos.
- Operadores comunes:
$ne,$regex,.{longitud},' || 1==1. - Prevención: Valida entradas, usa consultas parametrizadas y escapa caracteres especiales.
Diagrama de Inyección NoSQL
sequenceDiagram participant Atacante participant Aplicación participant BaseDeDatos Atacante->>Aplicación: Envía datos maliciosos Aplicación->>BaseDeDatos: Consulta NoSQL manipulada BaseDeDatos->>Aplicación: Devuelve datos no autorizados Aplicación->>Atacante: Acceso concedido
Consejo Final
Nunca confíes en las entradas del usuario. Siempre valida y sanitiza los datos antes de usarlos en consultas a la base de datos.