feat(security): drop scanner probes and hostile paths early in proxy
This commit is contained in:
1 parent
a878d831aa
commit
fb724a35cc
2 files changed
+29
-6
No files matched your search
+8
-5
@@ -2,6 +2,7 @@ import { NextResponse } from "next/server";
|
||||
import { getToken } from "next-auth/jwt";
|
||||
import { env } from "@/env";
|
||||
import { buildContentSecurityPolicy, createCspNonce } from "@/lib/csp";
|
||||
import { isSuspiciousPath } from "@/lib/ddos";
|
||||
import { ddosReject, enforceDdosRateLimit } from "@/lib/ddos-guard";
|
||||
import {
|
||||
isCacheableAssetPath,
|
||||
@@ -19,6 +20,13 @@ const SECURITY_HEADERS: Record<string, string> = {
|
||||
};
|
||||
|
||||
export const proxy = async (req: import("next/server").NextRequest) => {
|
||||
const pathname = req.nextUrl.pathname;
|
||||
|
||||
// Drop scanner probes immediately before performing any rate-limit or DB operations.
|
||||
if (isSuspiciousPath(pathname)) {
|
||||
return ddosReject(403);
|
||||
}
|
||||
|
||||
// Server actions carry an opaque action id in this header. A malformed or
|
||||
// trivially short id (e.g. "x" sent by bots) can never resolve to a real
|
||||
// action; rejecting it here avoids the expensive lookup/render path.
|
||||
@@ -28,15 +36,10 @@ export const proxy = async (req: import("next/server").NextRequest) => {
|
||||
}
|
||||
|
||||
const decision = await enforceDdosRateLimit(req);
|
||||
if (decision.outcome === "suspect") {
|
||||
return ddosReject(403);
|
||||
}
|
||||
if (decision.outcome === "block") {
|
||||
return ddosReject(429, decision.retryAfterSeconds);
|
||||
}
|
||||
|
||||
const pathname = req.nextUrl.pathname;
|
||||
|
||||
// Only /admin needs a real session token for the redirect guard; skipping
|
||||
// JWT decoding on every other request keeps the proxy cheap under load.
|
||||
const adminPath = pathname === "/admin" || pathname.startsWith("/admin/");
|
||||
|
||||
Reference in new issue
Block a user