Skip to content

Commit d19dbee

Browse files
committed
Merge branch 'main' of github.com:AikidoSec/node-RASP into drop-compressed-timings
* 'main' of github.com:AikidoSec/node-RASP: (85 commits) Rename variable to make it more clear Remove redundant methods Improve comment Remove `isMonitoredIPAddress` Use userAgent variable Iterate through monitored IP lists only once Add comment about empty string and regexp Refactor safeCreateRegExp to its own file Fix end2end test Fix missing imports Format file Add end2end test to ensure monitored IPs and user agents are never blocked Fix tests Adapt to new firewall/lists API Revert "Revert "Merge pull request #505 from AikidoSec/request-stats"" Revert "Merge pull request #505 from AikidoSec/request-stats" Always include items key for arrays in data schema Fix test Set symbol to true and add comment Prevent double counting monitored lists ...
2 parents f5ab2a9 + 192443f commit d19dbee

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+1560
-143
lines changed

end2end/server/src/handlers/lists.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ const {
22
getBlockedIPAddresses,
33
getBlockedUserAgents,
44
getAllowedIPAddresses,
5+
getMonitoredUserAgents,
6+
getMonitoredIPAddresses,
7+
getUserAgentDetails,
58
} = require("../zen/config");
69

710
module.exports = function lists(req, res) {
@@ -12,6 +15,9 @@ module.exports = function lists(req, res) {
1215
const blockedIps = getBlockedIPAddresses(req.app);
1316
const blockedUserAgents = getBlockedUserAgents(req.app);
1417
const allowedIps = getAllowedIPAddresses(req.app);
18+
const monitoredUserAgents = getMonitoredUserAgents(req.app);
19+
const monitoredIps = getMonitoredIPAddresses(req.app);
20+
const userAgentDetails = getUserAgentDetails(req.app);
1521

1622
res.json({
1723
success: true,
@@ -20,22 +26,37 @@ module.exports = function lists(req, res) {
2026
blockedIps.length > 0
2127
? [
2228
{
29+
key: "geoip/Belgium;BE",
2330
source: "geoip",
2431
description: "geo restrictions",
2532
ips: blockedIps,
2633
},
2734
]
2835
: [],
2936
blockedUserAgents: blockedUserAgents,
37+
monitoredUserAgents: monitoredUserAgents,
38+
userAgentDetails: userAgentDetails,
3039
allowedIPAddresses:
3140
allowedIps.length > 0
3241
? [
3342
{
43+
key: "geoip/Belgium;BE",
3444
source: "geoip",
3545
description: "geo restrictions",
3646
ips: allowedIps,
3747
},
3848
]
3949
: [],
50+
monitoredIPAddresses:
51+
monitoredIps.length > 0
52+
? monitoredIps
53+
: [
54+
{
55+
key: "geoip/Belgium;BE",
56+
source: "geoip",
57+
description: "geo restrictions",
58+
ips: monitoredIps,
59+
},
60+
],
4061
});
4162
};

end2end/server/src/handlers/updateLists.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ const {
22
updateBlockedIPAddresses,
33
updateBlockedUserAgents,
44
updateAllowedIPAddresses,
5+
updateMonitoredUserAgents,
6+
updateMonitoredIPAddresses,
7+
updateUserAgentDetails,
58
} = require("../zen/config");
69

710
module.exports = function updateIPLists(req, res) {
@@ -46,5 +49,26 @@ module.exports = function updateIPLists(req, res) {
4649
updateAllowedIPAddresses(req.app, req.body.allowedIPAddresses);
4750
}
4851

52+
if (
53+
req.body.monitoredUserAgents &&
54+
typeof req.body.monitoredUserAgents === "string"
55+
) {
56+
updateMonitoredUserAgents(req.app, req.body.monitoredUserAgents);
57+
}
58+
59+
if (
60+
req.body.monitoredIPAddresses &&
61+
Array.isArray(req.body.monitoredIPAddresses)
62+
) {
63+
updateMonitoredIPAddresses(req.app, req.body.monitoredIPAddresses);
64+
}
65+
66+
if (
67+
req.body.userAgentDetails &&
68+
Array.isArray(req.body.userAgentDetails)
69+
) {
70+
updateUserAgentDetails(req.app, req.body.userAgentDetails);
71+
}
72+
4973
res.json({ success: true });
5074
};

end2end/server/src/zen/config.js

Lines changed: 83 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ function updateAppConfig(app, newConfig) {
4040
const blockedIPAddresses = [];
4141
const blockedUserAgents = [];
4242
const allowedIPAddresses = [];
43+
const monitoredUserAgents = [];
44+
const monitoredIPAddresses = [];
45+
const userAgentDetails = [];
4346

4447
function updateBlockedIPAddresses(app, ips) {
4548
let entry = blockedIPAddresses.find((ip) => ip.serviceId === app.serviceId);
@@ -90,7 +93,7 @@ function getAllowedIPAddresses(app) {
9093
}
9194

9295
function updateBlockedUserAgents(app, uas) {
93-
let entry = blockedUserAgents.find((e) => e.serviceId === e.serviceId);
96+
let entry = blockedUserAgents.find((e) => e.serviceId === app.serviceId);
9497

9598
if (entry) {
9699
entry.userAgents = uas;
@@ -104,7 +107,7 @@ function updateBlockedUserAgents(app, uas) {
104107
}
105108

106109
function getBlockedUserAgents(app) {
107-
const entry = blockedUserAgents.find((e) => e.serviceId === e.serviceId);
110+
const entry = blockedUserAgents.find((e) => e.serviceId === app.serviceId);
108111

109112
if (entry) {
110113
return entry.userAgents;
@@ -113,6 +116,78 @@ function getBlockedUserAgents(app) {
113116
return "";
114117
}
115118

119+
function updateMonitoredUserAgents(app, uas) {
120+
let entry = monitoredUserAgents.find((e) => e.serviceId === app.serviceId);
121+
122+
if (entry) {
123+
entry.userAgents = uas;
124+
} else {
125+
entry = { serviceId: app.serviceId, userAgents: uas };
126+
monitoredUserAgents.push(entry);
127+
}
128+
129+
// Bump lastUpdatedAt
130+
updateAppConfig(app, {});
131+
}
132+
133+
function getMonitoredUserAgents(app) {
134+
const entry = monitoredUserAgents.find((e) => e.serviceId === app.serviceId);
135+
136+
if (entry) {
137+
return entry.userAgents;
138+
}
139+
140+
return "";
141+
}
142+
143+
function updateMonitoredIPAddresses(app, ips) {
144+
let entry = monitoredIPAddresses.find((e) => e.serviceId === app.serviceId);
145+
146+
if (entry) {
147+
entry.ipAddresses = ips;
148+
} else {
149+
entry = { serviceId: app.serviceId, ipAddresses: ips };
150+
monitoredIPAddresses.push(entry);
151+
}
152+
153+
// Bump lastUpdatedAt
154+
updateAppConfig(app, {});
155+
}
156+
157+
function getMonitoredIPAddresses(app) {
158+
const entry = monitoredIPAddresses.find((e) => e.serviceId === app.serviceId);
159+
160+
if (entry) {
161+
return entry.ipAddresses;
162+
}
163+
164+
return [];
165+
}
166+
167+
function updateUserAgentDetails(app, uas) {
168+
let entry = userAgentDetails.find((e) => e.serviceId === app.serviceId);
169+
170+
if (entry) {
171+
entry.userAgents = uas;
172+
} else {
173+
entry = { serviceId: app.serviceId, userAgents: uas };
174+
userAgentDetails.push(entry);
175+
}
176+
177+
// Bump lastUpdatedAt
178+
updateAppConfig(app, {});
179+
}
180+
181+
function getUserAgentDetails(app) {
182+
const entry = userAgentDetails.find((e) => e.serviceId === app.serviceId);
183+
184+
if (entry) {
185+
return entry.userAgents;
186+
}
187+
188+
return [];
189+
}
190+
116191
module.exports = {
117192
getAppConfig,
118193
updateAppConfig,
@@ -122,4 +197,10 @@ module.exports = {
122197
getBlockedUserAgents,
123198
getAllowedIPAddresses,
124199
updateAllowedIPAddresses,
200+
updateMonitoredUserAgents,
201+
getMonitoredUserAgents,
202+
updateMonitoredIPAddresses,
203+
getMonitoredIPAddresses,
204+
updateUserAgentDetails,
205+
getUserAgentDetails,
125206
};
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
const t = require("tap");
2+
const { spawn } = require("child_process");
3+
const { resolve } = require("path");
4+
const timeout = require("../timeout");
5+
6+
const pathToApp = resolve(__dirname, "../../sample-apps/hono-xml", "app.js");
7+
const testServerUrl = "http://localhost:5874";
8+
9+
let token;
10+
t.beforeEach(async () => {
11+
const response = await fetch(`${testServerUrl}/api/runtime/apps`, {
12+
method: "POST",
13+
});
14+
const body = await response.json();
15+
token = body.token;
16+
17+
const lists = await fetch(`${testServerUrl}/api/runtime/firewall/lists`, {
18+
method: "POST",
19+
headers: {
20+
"Content-Type": "application/json",
21+
Authorization: token,
22+
},
23+
body: JSON.stringify({
24+
blockedIPAddresses: [],
25+
monitoredIPAddresses: ["1.3.2.0/24", "e98c:a7ba:2329:8c69::/64"],
26+
monitoredUserAgents: "monitored-bot",
27+
userAgentDetails: [
28+
{
29+
key: "monitored-bot",
30+
pattern: "monitored-bot",
31+
},
32+
],
33+
}),
34+
});
35+
t.same(lists.status, 200);
36+
});
37+
38+
t.test("it does not block monitored IPs", (t) => {
39+
const server = spawn(`node`, [pathToApp, "4005"], {
40+
env: {
41+
...process.env,
42+
AIKIDO_DEBUG: "true",
43+
AIKIDO_BLOCKING: "true",
44+
AIKIDO_TOKEN: token,
45+
AIKIDO_ENDPOINT: testServerUrl,
46+
},
47+
});
48+
49+
server.on("close", () => {
50+
t.end();
51+
});
52+
53+
server.on("error", (err) => {
54+
t.fail(err);
55+
});
56+
57+
let stdout = "";
58+
server.stdout.on("data", (data) => {
59+
stdout += data.toString();
60+
});
61+
62+
let stderr = "";
63+
server.stderr.on("data", (data) => {
64+
stderr += data.toString();
65+
});
66+
67+
// Wait for the server to start
68+
timeout(2000)
69+
.then(async () => {
70+
// Test IPv4 monitoring
71+
const resp1 = await fetch("http://127.0.0.1:4005/add", {
72+
method: "POST",
73+
body: "<cat><name>Njuska</name></cat>",
74+
headers: {
75+
"Content-Type": "application/xml",
76+
"X-Forwarded-For": "1.3.2.4",
77+
},
78+
signal: AbortSignal.timeout(5000),
79+
});
80+
t.same(resp1.status, 200);
81+
t.same(await resp1.text(), JSON.stringify({ success: true }));
82+
83+
// Test IPv6 monitoring
84+
const resp2 = await fetch("http://127.0.0.1:4005/add", {
85+
method: "POST",
86+
body: "<cat><name>Harry</name></cat>",
87+
headers: {
88+
"Content-Type": "application/xml",
89+
"X-Forwarded-For": "e98c:a7ba:2329:8c69:a13a:8aff:a932:13f2",
90+
},
91+
signal: AbortSignal.timeout(5000),
92+
});
93+
t.same(resp2.status, 200);
94+
t.same(await resp2.text(), JSON.stringify({ success: true }));
95+
})
96+
.catch((error) => {
97+
t.fail(error);
98+
})
99+
.finally(() => {
100+
server.kill();
101+
});
102+
});
103+
104+
t.test("it does not block monitored user agents", (t) => {
105+
const server = spawn(`node`, [pathToApp, "4006"], {
106+
env: {
107+
...process.env,
108+
AIKIDO_DEBUG: "true",
109+
AIKIDO_BLOCKING: "true",
110+
AIKIDO_TOKEN: token,
111+
AIKIDO_ENDPOINT: testServerUrl,
112+
},
113+
});
114+
115+
server.on("close", () => {
116+
t.end();
117+
});
118+
119+
server.on("error", (err) => {
120+
t.fail(err);
121+
});
122+
123+
let stdout = "";
124+
server.stdout.on("data", (data) => {
125+
stdout += data.toString();
126+
});
127+
128+
let stderr = "";
129+
server.stderr.on("data", (data) => {
130+
stderr += data.toString();
131+
});
132+
133+
// Wait for the server to start
134+
timeout(2000)
135+
.then(async () => {
136+
// Test monitored user agent
137+
const resp1 = await fetch("http://127.0.0.1:4006/", {
138+
headers: {
139+
"User-Agent": "monitored-bot",
140+
},
141+
signal: AbortSignal.timeout(5000),
142+
});
143+
t.same(resp1.status, 200);
144+
})
145+
.catch((error) => {
146+
t.fail(error);
147+
})
148+
.finally(() => {
149+
server.kill();
150+
});
151+
});

0 commit comments

Comments
 (0)