@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.
607 lines (606 loc) • 12.8 kB
JavaScript
/* eslint-disable object-property-newline */
"use strict";
const decodeText = require("./decodeText");
const RE_ENCODED = /%[a-fA-F0-9][a-fA-F0-9]/g;
const EncodedLookup = {
"%00": "\x00",
"%01": "\x01",
"%02": "\x02",
"%03": "\x03",
"%04": "\x04",
"%05": "\x05",
"%06": "\x06",
"%07": "\x07",
"%08": "\x08",
"%09": "\x09",
"%0a": "\x0a",
"%0A": "\x0a",
"%0b": "\x0b",
"%0B": "\x0b",
"%0c": "\x0c",
"%0C": "\x0c",
"%0d": "\x0d",
"%0D": "\x0d",
"%0e": "\x0e",
"%0E": "\x0e",
"%0f": "\x0f",
"%0F": "\x0f",
"%10": "\x10",
"%11": "\x11",
"%12": "\x12",
"%13": "\x13",
"%14": "\x14",
"%15": "\x15",
"%16": "\x16",
"%17": "\x17",
"%18": "\x18",
"%19": "\x19",
"%1a": "\x1a",
"%1A": "\x1a",
"%1b": "\x1b",
"%1B": "\x1b",
"%1c": "\x1c",
"%1C": "\x1c",
"%1d": "\x1d",
"%1D": "\x1d",
"%1e": "\x1e",
"%1E": "\x1e",
"%1f": "\x1f",
"%1F": "\x1f",
"%20": "\x20",
"%21": "\x21",
"%22": "\x22",
"%23": "\x23",
"%24": "\x24",
"%25": "\x25",
"%26": "\x26",
"%27": "\x27",
"%28": "\x28",
"%29": "\x29",
"%2a": "\x2a",
"%2A": "\x2a",
"%2b": "\x2b",
"%2B": "\x2b",
"%2c": "\x2c",
"%2C": "\x2c",
"%2d": "\x2d",
"%2D": "\x2d",
"%2e": "\x2e",
"%2E": "\x2e",
"%2f": "\x2f",
"%2F": "\x2f",
"%30": "\x30",
"%31": "\x31",
"%32": "\x32",
"%33": "\x33",
"%34": "\x34",
"%35": "\x35",
"%36": "\x36",
"%37": "\x37",
"%38": "\x38",
"%39": "\x39",
"%3a": "\x3a",
"%3A": "\x3a",
"%3b": "\x3b",
"%3B": "\x3b",
"%3c": "\x3c",
"%3C": "\x3c",
"%3d": "\x3d",
"%3D": "\x3d",
"%3e": "\x3e",
"%3E": "\x3e",
"%3f": "\x3f",
"%3F": "\x3f",
"%40": "\x40",
"%41": "\x41",
"%42": "\x42",
"%43": "\x43",
"%44": "\x44",
"%45": "\x45",
"%46": "\x46",
"%47": "\x47",
"%48": "\x48",
"%49": "\x49",
"%4a": "\x4a",
"%4A": "\x4a",
"%4b": "\x4b",
"%4B": "\x4b",
"%4c": "\x4c",
"%4C": "\x4c",
"%4d": "\x4d",
"%4D": "\x4d",
"%4e": "\x4e",
"%4E": "\x4e",
"%4f": "\x4f",
"%4F": "\x4f",
"%50": "\x50",
"%51": "\x51",
"%52": "\x52",
"%53": "\x53",
"%54": "\x54",
"%55": "\x55",
"%56": "\x56",
"%57": "\x57",
"%58": "\x58",
"%59": "\x59",
"%5a": "\x5a",
"%5A": "\x5a",
"%5b": "\x5b",
"%5B": "\x5b",
"%5c": "\x5c",
"%5C": "\x5c",
"%5d": "\x5d",
"%5D": "\x5d",
"%5e": "\x5e",
"%5E": "\x5e",
"%5f": "\x5f",
"%5F": "\x5f",
"%60": "\x60",
"%61": "\x61",
"%62": "\x62",
"%63": "\x63",
"%64": "\x64",
"%65": "\x65",
"%66": "\x66",
"%67": "\x67",
"%68": "\x68",
"%69": "\x69",
"%6a": "\x6a",
"%6A": "\x6a",
"%6b": "\x6b",
"%6B": "\x6b",
"%6c": "\x6c",
"%6C": "\x6c",
"%6d": "\x6d",
"%6D": "\x6d",
"%6e": "\x6e",
"%6E": "\x6e",
"%6f": "\x6f",
"%6F": "\x6f",
"%70": "\x70",
"%71": "\x71",
"%72": "\x72",
"%73": "\x73",
"%74": "\x74",
"%75": "\x75",
"%76": "\x76",
"%77": "\x77",
"%78": "\x78",
"%79": "\x79",
"%7a": "\x7a",
"%7A": "\x7a",
"%7b": "\x7b",
"%7B": "\x7b",
"%7c": "\x7c",
"%7C": "\x7c",
"%7d": "\x7d",
"%7D": "\x7d",
"%7e": "\x7e",
"%7E": "\x7e",
"%7f": "\x7f",
"%7F": "\x7f",
"%80": "\x80",
"%81": "\x81",
"%82": "\x82",
"%83": "\x83",
"%84": "\x84",
"%85": "\x85",
"%86": "\x86",
"%87": "\x87",
"%88": "\x88",
"%89": "\x89",
"%8a": "\x8a",
"%8A": "\x8a",
"%8b": "\x8b",
"%8B": "\x8b",
"%8c": "\x8c",
"%8C": "\x8c",
"%8d": "\x8d",
"%8D": "\x8d",
"%8e": "\x8e",
"%8E": "\x8e",
"%8f": "\x8f",
"%8F": "\x8f",
"%90": "\x90",
"%91": "\x91",
"%92": "\x92",
"%93": "\x93",
"%94": "\x94",
"%95": "\x95",
"%96": "\x96",
"%97": "\x97",
"%98": "\x98",
"%99": "\x99",
"%9a": "\x9a",
"%9A": "\x9a",
"%9b": "\x9b",
"%9B": "\x9b",
"%9c": "\x9c",
"%9C": "\x9c",
"%9d": "\x9d",
"%9D": "\x9d",
"%9e": "\x9e",
"%9E": "\x9e",
"%9f": "\x9f",
"%9F": "\x9f",
"%a0": "\xa0",
"%A0": "\xa0",
"%a1": "\xa1",
"%A1": "\xa1",
"%a2": "\xa2",
"%A2": "\xa2",
"%a3": "\xa3",
"%A3": "\xa3",
"%a4": "\xa4",
"%A4": "\xa4",
"%a5": "\xa5",
"%A5": "\xa5",
"%a6": "\xa6",
"%A6": "\xa6",
"%a7": "\xa7",
"%A7": "\xa7",
"%a8": "\xa8",
"%A8": "\xa8",
"%a9": "\xa9",
"%A9": "\xa9",
"%aa": "\xaa",
"%Aa": "\xaa",
"%aA": "\xaa",
"%AA": "\xaa",
"%ab": "\xab",
"%Ab": "\xab",
"%aB": "\xab",
"%AB": "\xab",
"%ac": "\xac",
"%Ac": "\xac",
"%aC": "\xac",
"%AC": "\xac",
"%ad": "\xad",
"%Ad": "\xad",
"%aD": "\xad",
"%AD": "\xad",
"%ae": "\xae",
"%Ae": "\xae",
"%aE": "\xae",
"%AE": "\xae",
"%af": "\xaf",
"%Af": "\xaf",
"%aF": "\xaf",
"%AF": "\xaf",
"%b0": "\xb0",
"%B0": "\xb0",
"%b1": "\xb1",
"%B1": "\xb1",
"%b2": "\xb2",
"%B2": "\xb2",
"%b3": "\xb3",
"%B3": "\xb3",
"%b4": "\xb4",
"%B4": "\xb4",
"%b5": "\xb5",
"%B5": "\xb5",
"%b6": "\xb6",
"%B6": "\xb6",
"%b7": "\xb7",
"%B7": "\xb7",
"%b8": "\xb8",
"%B8": "\xb8",
"%b9": "\xb9",
"%B9": "\xb9",
"%ba": "\xba",
"%Ba": "\xba",
"%bA": "\xba",
"%BA": "\xba",
"%bb": "\xbb",
"%Bb": "\xbb",
"%bB": "\xbb",
"%BB": "\xbb",
"%bc": "\xbc",
"%Bc": "\xbc",
"%bC": "\xbc",
"%BC": "\xbc",
"%bd": "\xbd",
"%Bd": "\xbd",
"%bD": "\xbd",
"%BD": "\xbd",
"%be": "\xbe",
"%Be": "\xbe",
"%bE": "\xbe",
"%BE": "\xbe",
"%bf": "\xbf",
"%Bf": "\xbf",
"%bF": "\xbf",
"%BF": "\xbf",
"%c0": "\xc0",
"%C0": "\xc0",
"%c1": "\xc1",
"%C1": "\xc1",
"%c2": "\xc2",
"%C2": "\xc2",
"%c3": "\xc3",
"%C3": "\xc3",
"%c4": "\xc4",
"%C4": "\xc4",
"%c5": "\xc5",
"%C5": "\xc5",
"%c6": "\xc6",
"%C6": "\xc6",
"%c7": "\xc7",
"%C7": "\xc7",
"%c8": "\xc8",
"%C8": "\xc8",
"%c9": "\xc9",
"%C9": "\xc9",
"%ca": "\xca",
"%Ca": "\xca",
"%cA": "\xca",
"%CA": "\xca",
"%cb": "\xcb",
"%Cb": "\xcb",
"%cB": "\xcb",
"%CB": "\xcb",
"%cc": "\xcc",
"%Cc": "\xcc",
"%cC": "\xcc",
"%CC": "\xcc",
"%cd": "\xcd",
"%Cd": "\xcd",
"%cD": "\xcd",
"%CD": "\xcd",
"%ce": "\xce",
"%Ce": "\xce",
"%cE": "\xce",
"%CE": "\xce",
"%cf": "\xcf",
"%Cf": "\xcf",
"%cF": "\xcf",
"%CF": "\xcf",
"%d0": "\xd0",
"%D0": "\xd0",
"%d1": "\xd1",
"%D1": "\xd1",
"%d2": "\xd2",
"%D2": "\xd2",
"%d3": "\xd3",
"%D3": "\xd3",
"%d4": "\xd4",
"%D4": "\xd4",
"%d5": "\xd5",
"%D5": "\xd5",
"%d6": "\xd6",
"%D6": "\xd6",
"%d7": "\xd7",
"%D7": "\xd7",
"%d8": "\xd8",
"%D8": "\xd8",
"%d9": "\xd9",
"%D9": "\xd9",
"%da": "\xda",
"%Da": "\xda",
"%dA": "\xda",
"%DA": "\xda",
"%db": "\xdb",
"%Db": "\xdb",
"%dB": "\xdb",
"%DB": "\xdb",
"%dc": "\xdc",
"%Dc": "\xdc",
"%dC": "\xdc",
"%DC": "\xdc",
"%dd": "\xdd",
"%Dd": "\xdd",
"%dD": "\xdd",
"%DD": "\xdd",
"%de": "\xde",
"%De": "\xde",
"%dE": "\xde",
"%DE": "\xde",
"%df": "\xdf",
"%Df": "\xdf",
"%dF": "\xdf",
"%DF": "\xdf",
"%e0": "\xe0",
"%E0": "\xe0",
"%e1": "\xe1",
"%E1": "\xe1",
"%e2": "\xe2",
"%E2": "\xe2",
"%e3": "\xe3",
"%E3": "\xe3",
"%e4": "\xe4",
"%E4": "\xe4",
"%e5": "\xe5",
"%E5": "\xe5",
"%e6": "\xe6",
"%E6": "\xe6",
"%e7": "\xe7",
"%E7": "\xe7",
"%e8": "\xe8",
"%E8": "\xe8",
"%e9": "\xe9",
"%E9": "\xe9",
"%ea": "\xea",
"%Ea": "\xea",
"%eA": "\xea",
"%EA": "\xea",
"%eb": "\xeb",
"%Eb": "\xeb",
"%eB": "\xeb",
"%EB": "\xeb",
"%ec": "\xec",
"%Ec": "\xec",
"%eC": "\xec",
"%EC": "\xec",
"%ed": "\xed",
"%Ed": "\xed",
"%eD": "\xed",
"%ED": "\xed",
"%ee": "\xee",
"%Ee": "\xee",
"%eE": "\xee",
"%EE": "\xee",
"%ef": "\xef",
"%Ef": "\xef",
"%eF": "\xef",
"%EF": "\xef",
"%f0": "\xf0",
"%F0": "\xf0",
"%f1": "\xf1",
"%F1": "\xf1",
"%f2": "\xf2",
"%F2": "\xf2",
"%f3": "\xf3",
"%F3": "\xf3",
"%f4": "\xf4",
"%F4": "\xf4",
"%f5": "\xf5",
"%F5": "\xf5",
"%f6": "\xf6",
"%F6": "\xf6",
"%f7": "\xf7",
"%F7": "\xf7",
"%f8": "\xf8",
"%F8": "\xf8",
"%f9": "\xf9",
"%F9": "\xf9",
"%fa": "\xfa",
"%Fa": "\xfa",
"%fA": "\xfa",
"%FA": "\xfa",
"%fb": "\xfb",
"%Fb": "\xfb",
"%fB": "\xfb",
"%FB": "\xfb",
"%fc": "\xfc",
"%Fc": "\xfc",
"%fC": "\xfc",
"%FC": "\xfc",
"%fd": "\xfd",
"%Fd": "\xfd",
"%fD": "\xfd",
"%FD": "\xfd",
"%fe": "\xfe",
"%Fe": "\xfe",
"%fE": "\xfe",
"%FE": "\xfe",
"%ff": "\xff",
"%Ff": "\xff",
"%fF": "\xff",
"%FF": "\xff",
};
function encodedReplacer(match) {
return EncodedLookup[match];
}
const STATE_KEY = 0;
const STATE_VALUE = 1;
const STATE_CHARSET = 2;
const STATE_LANG = 3;
function parseParams(str) {
const res = [];
let state = STATE_KEY;
let charset = "";
let inquote = false;
let escaping = false;
let p = 0;
let tmp = "";
const len = str.length;
for (var i = 0; i < len; ++i) {
// eslint-disable-line no-var
const char = str[i];
if (char === "\\" && inquote) {
if (escaping) {
escaping = false;
}
else {
escaping = true;
continue;
}
}
else if (char === '"') {
if (!escaping) {
if (inquote) {
inquote = false;
state = STATE_KEY;
// Skip any remaining characters until we hit a semicolon or end of string
// This ensures we don't include characters after the closing quote
while (i + 1 < len && str[i + 1] !== ";") {
++i;
}
}
else {
inquote = true;
}
continue;
}
else {
escaping = false;
}
}
else {
if (escaping && inquote) {
tmp += "\\";
}
escaping = false;
if ((state === STATE_CHARSET || state === STATE_LANG) && char === "'") {
if (state === STATE_CHARSET) {
state = STATE_LANG;
charset = tmp.substring(1);
}
else {
state = STATE_VALUE;
}
tmp = "";
continue;
}
else if (state === STATE_KEY &&
(char === "*" || char === "=") &&
res.length) {
state = char === "*" ? STATE_CHARSET : STATE_VALUE;
res[p] = [tmp, undefined];
tmp = "";
continue;
}
else if (!inquote && char === ";") {
state = STATE_KEY;
if (charset) {
if (tmp.length) {
tmp = decodeText(tmp.replace(RE_ENCODED, encodedReplacer), "binary", charset);
}
charset = "";
}
else if (tmp.length) {
tmp = decodeText(tmp, "binary", "utf8");
}
if (res[p] === undefined) {
res[p] = tmp;
}
else {
res[p][1] = tmp;
}
tmp = "";
++p;
continue;
}
else if (!inquote && (char === " " || char === "\t")) {
continue;
}
}
tmp += char;
}
if (charset && tmp.length) {
tmp = decodeText(tmp.replace(RE_ENCODED, encodedReplacer), "binary", charset);
}
else if (tmp) {
tmp = decodeText(tmp, "binary", "utf8");
}
if (res[p] === undefined) {
if (tmp) {
res[p] = tmp;
}
}
else {
res[p][1] = tmp;
}
return res;
}
module.exports = parseParams;