El operador $where
en MongoDB es una característica que es mejor evitar. Su rendimiento es abismal, y no solo porque no se beneficia de los índices. Casi todos los casos de uso comunes se pueden resolver de manera mucho más eficiente con una consulta o agregación de búsqueda común, especialmente una tan trivial como esta. Pero esto es un intercambio de seguridad de pila, no un flujo de pila, así que concentrémonos en las implicaciones de seguridad.
La declaración $where
pasa un fragmento de código javascript a la base de datos que la base de datos ejecutará una vez para cada documento de la colección. Afortunadamente, este script no tiene acceso al objeto db
ni a otras funciones de shell peligrosas y funciona en copias de los documentos, por lo que el atacante al menos no puede cambiar el contenido de la base de datos como ocurre con muchas inyecciones de SQL. Pero, por ejemplo, es vulnerable a los ataques donde el atacante quiere devolver otros resultados de los previstos.
Vamos a hacer un ejemplo. Digamos que tenemos un blog. Nuestro blog tiene muchos artículos que se pueden leer en público, pero también tenemos algunos artículos privados que son para nuestro uso interno y que no deben publicarse. Así que tenemos un campo hidden
en nuestros documentos que puede ser true
o false
dependiendo de si nuestros visitantes deben ver el artículo o no. Nuestra consulta de MongoDB para obtener una lista de todos los artículos en una categoría determinada para mostrarla al visitante del sitio web es así:
db.articles.find({"$where": "this.hidden == false && this.category == '"+category+"'" });
Eso debería asegurarnos de que nadie vea nuestros artículos ocultos. O lo hace? Cuando el usuario controla la variable category
, puede establecerla en esta cadena:
'; return '' == '
El fragmento de código Javascript resultante que se envía a la base de datos es el siguiente:
this.hidden == false && this.category == ''; return '' == ''
Cuando tiene un fragmento de código javascript con varios comandos separados por ;
, se ejecutarán como una función y se necesita una declaración return
para determinar qué valor se devolverá al llamante. Esta función siempre devolverá verdadero. Eso significa que el usuario también verá todos los artículos de nuestra colección, incluidos aquellos que se supone que están ocultos.