@aikidosec/firewall
Version:
Zen by Aikido is an embedded Application Firewall that autonomously protects Node.js apps against common and critical attacks, provides rate limiting, detects malicious traffic (including bots), and more.
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;
}
;