Description
Prerequisites
- I have written a descriptive issue title
- I have searched existing issues to ensure the feature has not already been requested
🚀 Feature Proposal
The problem is that every time you work with the express framework or any other for rest services you need two types of redundant input validations, the one that belongs to the controller and the one that belongs to the data layer.
For example, I have a collection called users
which has a field called name
, in mongoose I can define the data type as String and a regular expression to validate its content, but from the controller, every time a user wants to search for a list of users through their name I must use a second validation (for example with jsonschema) which validates that the name
property is of type string since if it is passed directly to the findOne
function of mongoose it could cause a vulnerability of type NoSQL injection and bring unexpected information.
The same thing happens in other types of selections such as accessing the user account or searching for a document through its id, the end user could send a conditional object instead of plain text with the bsonId
string, especially when these Data travels through the body of the post or patch request.
In summary, for each project, redundant validations must be created for almost each mongoose function to avoid unexpected executions in the functions to be executed in mongodb and this significantly increases the amount of code and complicates the development architecture, forcing the creation of additional layers of validation or custom methods that duplicate the native functions for each model to be created.
To avoid this problem, i propose something very simple, create an option to temporarily disable the use of filters in the objects that are sent as arguments in the mongoose functions, this would allow the user's input to be used in the development of the application. direct and unfiltered in a completely safe way when performing simple searches.
If the schema says that a field is of type String, then it will automatically reject any data type other than String if filters are disabled.
References:
- https://portswigger.net/web-security/nosql-injection
- https://book.hacktricks.xyz/pentesting-web/nosql-injection
- https://owasp.org/www-project-web-security-testing-guide/v42/4-Web_Application_Security_Testing/07-Input_Validation_Testing/05.6-Testing_for_NoSQL_Injection.html
Motivation
Improve security and save redundant code.
Example
const schema = new mongoose.Schema({
name: {
type: String,
required: true,
validate: val => !!val.match(/^[a-zA-ZáéíóúñÁÉÍÓÚÑ\s,'"`]{1,32}$/) // Why not pattern attribute?
}
});
const model = mongoose.model('users');
const router = express.Router();
router.get(`/users`, async (req, res, next) => {
const documents = await model
.find({ name: $regex: req.query.search })
.sort({ name: 'asc' })
.options({ filters: false }) // <- Proposal here!
.exec();
res.status(200).json(documents);
next();
});
This would help improve the security of everything that is sent to mongoose and reduce the number of vulnerable projects, it would also save a lot of code and work time by avoiding having to create additional validations, especially when there is more than one attribute to control where not all They are of type String.