Skip to content

Commit

Permalink
Merge pull request #506 from AikidoSec/never-block-bypass-ip
Browse files Browse the repository at this point in the history
Never block bypass IP
  • Loading branch information
willem-delbare authored Jan 27, 2025
2 parents 6d7aac1 + 0033b0f commit 689e46d
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 29 deletions.
125 changes: 105 additions & 20 deletions end2end/tests/hono-xml-blocklists.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,41 @@ t.beforeEach(async () => {
const body = await response.json();
token = body.token;

// Apply rate limiting
const updateConfigResponse = await fetch(
`${testServerUrl}/api/runtime/firewall/lists`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: token,
},
body: JSON.stringify({
blockedIPAddresses: ["1.3.2.0/24", "fe80::1234:5678:abcd:ef12/64"],
blockedUserAgents: "hacker|attacker|GPTBot",
}),
}
);
t.same(updateConfigResponse.status, 200);
const config = await fetch(`${testServerUrl}/api/runtime/config`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: token,
},
body: JSON.stringify({
allowedIPAddresses: ["1.3.2.1", "1.3.2.2"],
endpoints: [
{
route: "/admin",
method: "GET",
forceProtectionOff: false,
allowedIPAddresses: ["1.3.2.1"],
rateLimiting: {
enabled: false,
},
},
],
}),
});
t.same(config.status, 200);

const lists = await fetch(`${testServerUrl}/api/runtime/firewall/lists`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: token,
},
body: JSON.stringify({
blockedIPAddresses: ["1.3.2.0/24", "fe80::1234:5678:abcd:ef12/64"],
blockedUserAgents: "hacker|attacker|GPTBot",
}),
});
t.same(lists.status, 200);
});

t.test("it blocks geo restricted IPs", (t) => {
Expand All @@ -48,7 +67,7 @@ t.test("it blocks geo restricted IPs", (t) => {
});

server.on("error", (err) => {
t.fail(err.message);
t.fail(err);
});

let stdout = "";
Expand Down Expand Up @@ -107,7 +126,7 @@ t.test("it blocks geo restricted IPs", (t) => {
t.same(await resp3.text(), JSON.stringify({ success: true }));
})
.catch((error) => {
t.fail(error.message);
t.fail(error);
})
.finally(() => {
server.kill();
Expand All @@ -130,7 +149,7 @@ t.test("it blocks bots", (t) => {
});

server.on("error", (err) => {
t.fail(err.message);
t.fail(err);
});

let stdout = "";
Expand Down Expand Up @@ -190,7 +209,73 @@ t.test("it blocks bots", (t) => {
}
})
.catch((error) => {
t.fail(error.message);
t.fail(error);
})
.finally(() => {
server.kill();
});
});

t.test("it does not block bypass IP if in blocklist", (t) => {
const server = spawn(`node`, [pathToApp, "4004"], {
env: {
...process.env,
AIKIDO_DEBUG: "true",
AIKIDO_BLOCKING: "true",
AIKIDO_TOKEN: token,
AIKIDO_URL: testServerUrl,
},
});

server.on("close", () => {
t.end();
});

server.on("error", (err) => {
t.fail(err);
});

let stdout = "";
server.stdout.on("data", (data) => {
stdout += data.toString();
});

let stderr = "";
server.stderr.on("data", (data) => {
stderr += data.toString();
});

// Wait for the server to start
timeout(2000)
.then(async () => {
const resp1 = await fetch("http://127.0.0.1:4004/", {
headers: {
"X-Forwarded-For": "1.3.2.1",
},
signal: AbortSignal.timeout(5000),
});
t.same(resp1.status, 200);

const resp2 = await fetch("http://127.0.0.1:4004/admin", {
headers: {
"X-Forwarded-For": "1.3.2.1",
},
});
t.same(resp2.status, 200);

const resp3 = await fetch("http://127.0.0.1:4004/admin", {
headers: {
"X-Forwarded-For": "1.3.2.2",
},
});
t.same(resp3.status, 403);
t.same(
await resp3.text(),
`Your IP address is not allowed to access this resource. (Your IP: 1.3.2.2)`
);
})
.catch((error) => {
t.fail(error);
})
.finally(() => {
server.kill();
Expand Down
25 changes: 17 additions & 8 deletions library/sources/http-server/checkIfRequestIsBlocked.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable max-lines-per-function */
import type { ServerResponse } from "http";
import { Agent } from "../../agent/Agent";
import { getContext } from "../../agent/Context";
Expand Down Expand Up @@ -25,15 +26,11 @@ export function checkIfRequestIsBlocked(
return false;
}

const result = context.remoteAddress
? agent.getConfig().isIPAddressBlocked(context.remoteAddress)
: ({ blocked: false } as const);

if (result.blocked) {
if (!ipAllowedToAccessRoute(context, agent)) {
res.statusCode = 403;
res.setHeader("Content-Type", "text/plain");

let message = `Your IP address is blocked due to ${escapeHTML(result.reason)}.`;
let message = "Your IP address is not allowed to access this resource.";
if (context.remoteAddress) {
message += ` (Your IP: ${escapeHTML(context.remoteAddress)})`;
}
Expand All @@ -43,11 +40,23 @@ export function checkIfRequestIsBlocked(
return true;
}

if (!ipAllowedToAccessRoute(context, agent)) {
const isAllowedIP =
context.remoteAddress &&
agent.getConfig().isAllowedIP(context.remoteAddress);

if (isAllowedIP) {
return false;
}

const result = context.remoteAddress
? agent.getConfig().isIPAddressBlocked(context.remoteAddress)
: ({ blocked: false } as const);

if (result.blocked) {
res.statusCode = 403;
res.setHeader("Content-Type", "text/plain");

let message = "Your IP address is not allowed to access this resource.";
let message = `Your IP address is blocked due to ${escapeHTML(result.reason)}.`;
if (context.remoteAddress) {
message += ` (Your IP: ${escapeHTML(context.remoteAddress)})`;
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"scripts": {
"install": "node scripts/install.js",
"install-lib-only": "node scripts/install.js --lib-only",
"containers": "cd sample-apps && docker compose up -d --remove-orphans",
"containers": "cd sample-apps && docker compose up -d --remove-orphans --build",
"build": "node scripts/build.js",
"watch": "cd library && npm run build:watch",
"test": "cd library && npm run test",
Expand Down
10 changes: 10 additions & 0 deletions sample-apps/hono-xml/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,16 @@ async function main() {
return c.json({ success: true });
});

app.get("/admin", async (c) => {
return c.html(
`<html lang="en">
<body>
<h1>Admin panel</h1>
</body>
</html>`
);
});

app.post("/add-fast", async (c) => {
const body = await c.req.text();

Expand Down

0 comments on commit 689e46d

Please sign in to comment.