@aikidosec/firewall
Version:
Zen by Aikido is an embedded Web Application Firewall that autonomously protects Node.js apps against common and critical attacks
73 lines (72 loc) • 2.66 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.detectDbJsInjection = detectDbJsInjection;
const isPlainObject_1 = require("../../helpers/isPlainObject");
const detectJsInjection_1 = require("./detectJsInjection");
// Operators accepting server-side JS code
const serverSideJsFunctions = ["$where", "$accumulator", "$function"];
/**
* Checks if the user input is part of queries that execute JS code on the server.
* If the user input is part of the query and not safely encapsulated, it's considered an injection.
* Because strings are always encapsulated in quotes in JS, every non-encapsulated user input is an injection.
*/
function detectDbJsInjection(userInput, filterPart) {
for (const [key, value] of Object.entries(filterPart)) {
if (!serverSideJsFunctions.includes(key)) {
continue;
}
const jsCode = extractStringToCheck(key, value);
if (typeof jsCode !== "string" || jsCode.length < 1) {
continue;
}
return (0, detectJsInjection_1.detectJsInjection)(jsCode, userInput);
}
return false;
}
/**
* Gets the code string to check for injections from a $where, $function or $accumulator object
*/
function extractStringToCheck(key, value) {
if (typeof value === "string") {
return value;
}
if (!(0, isPlainObject_1.isPlainObject)(value) || !value) {
return undefined;
}
if (key !== "$function" && key !== "$accumulator") {
return undefined;
}
if (typeof value.lang === "string" && value.lang !== "js") {
return undefined;
}
// We can ignore args, because mongo is interpreting the body as JS code and passes the args to the function as string arguments.
// You can not break out of a JS string with quotes inside a JS string.
if (key === "$function") {
if (typeof value.body !== "string") {
return undefined;
}
return value.body;
}
else if (key === "$accumulator") {
return extractCodeFromAccumulator(value);
}
}
/**
* Gets all js code strings from the $accumulator object and concatenates them
*/
function extractCodeFromAccumulator(accumulator) {
let strToCheck = "";
if (typeof accumulator.init === "string") {
strToCheck = accumulator.init;
}
if (typeof accumulator.accumulate === "string") {
strToCheck += accumulator.accumulate;
}
if (typeof accumulator.merge === "string") {
strToCheck += accumulator.merge;
}
if (typeof accumulator.finalize === "string") {
strToCheck += accumulator.finalize;
}
return strToCheck;
}