UNPKG

@aikidosec/firewall

Version:

Zen by Aikido is an embedded Web Application Firewall that autonomously protects Node.js apps against common and critical attacks

145 lines (144 loc) 5.48 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MongoDB = void 0; const detectNoSQLInjection_1 = require("../vulnerabilities/nosql-injection/detectNoSQLInjection"); const isPlainObject_1 = require("../helpers/isPlainObject"); const Context_1 = require("../agent/Context"); const wrapExport_1 = require("../agent/hooks/wrapExport"); const OPERATIONS_WITH_FILTER = [ "count", "countDocuments", "find", "findOne", "findOneAndUpdate", "findOneAndReplace", "findOneAndDelete", "deleteOne", "deleteMany", "updateOne", "updateMany", "replaceOne", ]; const BULK_WRITE_OPERATIONS_WITH_FILTER = [ "replaceOne", "updateOne", "updateMany", "deleteOne", "deleteMany", ]; class MongoDB { inspectFilter(db, collection, request, filter, operation) { const result = (0, detectNoSQLInjection_1.detectNoSQLInjection)(request, filter); if (result.injection) { return { operation: `MongoDB.Collection.${operation}`, kind: "nosql_injection", source: result.source, pathsToPayload: result.pathsToPayload, metadata: { db: db, collection: collection, operation: operation, filter: JSON.stringify(filter), }, payload: result.payload, }; } } inspectBulkWriteOperation(operation, collection, context) { for (const op of BULK_WRITE_OPERATIONS_WITH_FILTER) { const options = operation[op]; if (options && options.filter) { return this.inspectFilter(collection.dbName, collection.collectionName, context, options.filter, "bulkWrite"); } } return undefined; } inspectBulkWrite(args, collection) { const context = (0, Context_1.getContext)(); if (!context) { return undefined; } if (Array.isArray(args[0]) && args[0].length > 0) { const operations = args[0]; for (const operation of operations) { const result = this.inspectBulkWriteOperation(operation, collection, context); if (result) { return result; } } } return undefined; } inspectAggregate(args, collection) { const context = (0, Context_1.getContext)(); if (!context) { return undefined; } if (Array.isArray(args) && args.length > 0) { const pipeline = args[0]; return this.inspectFilter(collection.dbName, collection.collectionName, context, pipeline, "aggregate"); } return undefined; } inspectOperation(operation, args, collection) { const context = (0, Context_1.getContext)(); if (!context) { return undefined; } if (args.length > 0 && (0, isPlainObject_1.isPlainObject)(args[0])) { const filter = args[0]; return this.inspectFilter(collection.dbName, collection.collectionName, context, filter, operation); } return undefined; } inspectDistinct(args, collection) { const context = (0, Context_1.getContext)(); if (!context) { return undefined; } if (args.length > 1 && (0, isPlainObject_1.isPlainObject)(args[1])) { const filter = args[1]; return this.inspectFilter(collection.dbName, collection.collectionName, context, filter, "distinct"); } return undefined; } wrapCollection(exports, pkgInfo) { const collectionProto = exports.Collection.prototype; OPERATIONS_WITH_FILTER.forEach((operation) => { (0, wrapExport_1.wrapExport)(collectionProto, operation, pkgInfo, { kind: "nosql_op", inspectArgs: (args, agent, collection) => this.inspectOperation(operation, args, collection), }); }); (0, wrapExport_1.wrapExport)(collectionProto, "bulkWrite", pkgInfo, { kind: "nosql_op", inspectArgs: (args, agent, collection) => this.inspectBulkWrite(args, collection), }); (0, wrapExport_1.wrapExport)(collectionProto, "aggregate", pkgInfo, { kind: "nosql_op", inspectArgs: (args, agent, collection) => this.inspectAggregate(args, collection), }); (0, wrapExport_1.wrapExport)(collectionProto, "distinct", pkgInfo, { kind: "nosql_op", inspectArgs: (args, agent, collection) => this.inspectDistinct(args, collection), }); } wrap(hooks) { hooks .addPackage("mongodb") .withVersion("^4.0.0 || ^5.0.0 || ^6.0.0") .onRequire((exports, pkgInfo) => { // From mongodb v6.10.0, the Collection is undefined // It's defined like: // exports.Collection = void 0; // const collection_1 = require("./collection"); // Object.defineProperty(exports, "Collection", { enumerable: true, get: function () { return collection_1.Collection; } }); // So we need to wait for the next tick to wrap the Collection process.nextTick(() => { this.wrapCollection(exports, pkgInfo); }); }); } } exports.MongoDB = MongoDB;