sql >> Base de Datos >  >> NoSQL >> MongoDB

Protección de MongoDB frente a ataques de inyección externa

La seguridad de MongoDB no está totalmente garantizada simplemente configurando certificados de autenticación o cifrando los datos. Algunos atacantes "harán un esfuerzo adicional" jugando con los parámetros recibidos en las solicitudes HTTP que se utilizan como parte del proceso de consulta de la base de datos.

Las bases de datos SQL son las más vulnerables a este tipo de ataque, pero la inyección externa también es posible en DBM NoSQL como MongoDB. En la mayoría de los casos, las inyecciones externas ocurren como resultado de una concatenación insegura de cadenas al crear consultas.

¿Qué es un ataque de inyección externa?

La inyección de código consiste básicamente en integrar datos no validados (vectores no mitigados) en un programa vulnerable que, cuando se ejecuta, conduce a un acceso desastroso a su base de datos; amenazando su seguridad.

Cuando se pasan variables sin desinfectar a una consulta de MongoDB, rompen la estructura de orientación de la consulta del documento y, a veces, se ejecutan como el propio código javascript. Este suele ser el caso cuando se pasan accesorios directamente desde el módulo analizador de cuerpo para el servidor Nodejs. Por lo tanto, un atacante puede insertar fácilmente un objeto Js donde esperaría una cadena o un número, obteniendo así resultados no deseados o manipulando sus datos.

Considere los siguientes datos en la colección de un estudiante.

{username:'John Doc', email:'[email protected]', age:20},

{username:'Rafael Silver', email:'[email protected]', age:30},

{username:'Kevin Smith', email:'[email protected]', age:22},

{username:'Pauline Wagu', email:'[email protected]', age:23}

Digamos que su programa tiene que buscar a todos los estudiantes cuya edad sea igual a 20, escribiría un código como este...

app.get(‘/:age’, function(req, res){

  db.collections(“students”).find({age: req.params.age});

})

Habrá enviado un objeto JSON en su solicitud http como 

{age: 20}

Esto devolverá todos los estudiantes cuya edad sea igual a 20 como el resultado esperado y en este caso solo {username:'John Doc', email:'[email protected]', age:20} .

Ahora, digamos que un atacante envía un objeto en lugar de un número, es decir, {‘$gt:0’};

La consulta resultante será:

db.colecciones(“estudiantes”).find({edad:{‘$gt:0’}); que es una consulta válida que, al ejecutarse, devolverá todos los estudiantes de esa colección. El atacante tiene la oportunidad de actuar sobre sus datos de acuerdo con sus intenciones maliciosas. En la mayoría de los casos, un atacante inyecta un objeto personalizado que contiene comandos MongoDB que les permiten acceder a sus documentos sin el procedimiento adecuado.

Algunos comandos de MongoDB ejecutan código Javascript dentro del motor de la base de datos, un riesgo potencial para sus datos. Algunos de estos comandos son '$where', '$group' y 'mapReduce'. Para versiones anteriores a MongoDB 2.4, el código Js tiene acceso al objeto db desde dentro de la consulta.

Protecciones Naitivas de MongoDB

MongoDB utiliza los datos BSON (Binary JSON) tanto para sus consultas como para sus documentos, pero en algunos casos puede aceptar expresiones JSON y Js no serializadas (como las mencionadas anteriormente). La mayoría de los datos que se pasan al servidor tienen el formato de una cadena y se pueden introducir directamente en una consulta de MongoDB. MongoDB no analiza sus datos, por lo que evita los riesgos potenciales que pueden derivarse de la integración de parámetros directos.

Si una API involucra la codificación de datos en un texto formateado y ese texto necesita ser analizado, tiene el potencial de crear un desacuerdo entre la persona que llama al servidor y el destinatario de la base de datos sobre cómo se analizará esa cadena. . Si los datos se malinterpretan accidentalmente como metadatos, el escenario puede representar amenazas de seguridad para sus datos.

Ejemplos de inyecciones externas de MongoDB y cómo manejarlas

 Consideremos los siguientes datos en una colección de estudiantes.

{username:'John Doc', password: ‘16djfhg’, email:'[email protected]', age:20},

{username:'Rafael Silver',password: ‘djh’, email:'[email protected]', age:30},

{username:'Kevin Smith', password: ‘16dj’, email:'[email protected]', age:22},

{username:'Pauline Wagu', password: ‘g6yj’, email:'[email protected]', age:23}

Inyección usando el operador $ne (no igual)

Si quiero devolver el documento con el nombre de usuario y la contraseña proporcionados en una solicitud, el código será:

app.post('/students, function (req, res) {

    var query = {

        username: req.body.username,

        password: req.body.password

    }

    db.collection(students).findOne(query, function (err, student) {

        res(student);

    });

});

Si recibimos la solicitud a continuación

POST https://localhost/students HTTP/1.1

Content-Type: application/json

{

    "username": {"$ne": null},

    "password": {"$ne": null}

}

La consulta definitivamente devolverá el primer estudiante en este caso ya que su nombre de usuario y contraseña no se valoran como nulos. Esto no está de acuerdo con los resultados esperados.

Para resolver esto, puedes usar:

módulo mongo-sanitize que evita que cualquier clave que comience con '$' pase al motor de consulta de MongoDB.

Instale primero el módulo  

​npm install mongo-sanitize

var sanitize = require(‘mongo-sanitize’);

var query = {

username: req.body.username,

password: req.body.password

}

Uso de mongoose para validar sus campos de esquema de modo que si espera una cadena y recibe un objeto, la consulta generará un error. En nuestro caso anterior, el valor nulo se convertirá en una cadena "" que literalmente no tiene impacto.

Inyección usando el operador $where

Este es uno de los operadores más peligrosos. Permitirá evaluar una cadena dentro del propio servidor. Por ejemplo, para buscar estudiantes cuya edad sea superior a un valor Y, la consulta será 

var query = { 

   $where: “this.age > ”+req.body.age

}

 db.collection(students).findOne(query, function (err, student) {

        res(student);

    });

Usar el módulo sanitize no ayudará en este caso si tenemos un '0; return true' porque el resultado devolverá todos los estudiantes en lugar de aquellos cuya edad es mayor que algún valor dado. Otras cadenas posibles que puede recibir son '\'; return \ ‘\’ ==\’’ o  this.email ===‘’;return ‘’ ==‘’. Esta consulta devolverá todos los estudiantes en lugar de solo aquellos que coincidan con la cláusula.

La cláusula $where debe evitarse en gran medida. Además del contratiempo descrito, también reduce el rendimiento porque no está optimizado para usar índices.

También existe una gran posibilidad de pasar una función en la cláusula $where y no se podrá acceder a la variable en el ámbito de MongoDB, por lo que su aplicación puede fallar. Es decir

var query = {

   $where: function() {

       return this.age > setValue //setValue is not defined

   }

}

También puede usar los operadores $eq, $lt, $lte, $gt, $gte.

Protegerse de la inyección externa de MongoDB

Aquí hay tres cosas que puede hacer para mantenerse protegido...

  1. Validar datos de usuario. Mirando hacia atrás a cómo se puede usar la expresión $where para acceder a sus datos, es recomendable validar siempre lo que los usuarios envían a su servidor.
  2. Use el concepto de validación JSON para validar su esquema junto con el módulo mongoose.
  3. Diseñe sus consultas de modo que el código Js no tenga acceso completo al código de su base de datos.

Conclusión

La inyección externa también es posible con MongoDB. A menudo se asocia con datos de usuario no validados que ingresan a las consultas de MongoDB. Siempre es importante detectar y prevenir la inyección de NoSQL probando cualquier dato que pueda recibir su servidor. Si se descuida, esto puede amenazar la seguridad de los datos del usuario. El procedimiento más importante es validar sus datos en todas las capas involucradas.