目录:
漏洞利用:绕过守门人
技术解析
影响范围:不仅仅是身份验证绕过
检测与缓解
修复方案
Next.js 是由 Vercel 开发的广受欢迎的 React 框架,它凭借无缝集成的服务器端渲染、静态生成和强大的中间件系统,驱动着数百万个 Web 应用程序。然而,在 2025 年 3 月,一个关键漏洞 CVE-2025-29927 震撼了整个生态系统。该漏洞暴露了一个缺陷,使攻击者能够轻易绕过基于中间件的安全控制。该问题由安全研究员 Rachid Allam(又名 zhero)发现,突显了 Next.js 中间件的强大与风险。让我们深入探讨该漏洞的技术细节、其工作原理以及对开发者的影响。
中间件:隐藏缺陷的守门人
在 Next.js 中,中间件充当守门人,在请求到达路由或 API 端点之前对其进行拦截。它是一个多功能工具,可用于身份验证检查、路径重写、重定向,甚至设置如内容安全策略(CSP)等安全响应头。例如,典型的中间件可能如下所示:
Copy// middleware.js
export function middleware(request) {
const session = request.cookies.get("session");
if (!session && request.nextUrl.pathname.startsWith("/dashboard")) {
return Response.redirect(new URL("/login", request.url));
}
}
在这里,中间件确保只有经过身份验证的用户才能访问 /dashboard。看起来很简单,对吧?但 CVE-2025-29927 通过滥用一个用于防止无限循环的内部机制,彻底颠覆了这种逻辑。
罪魁祸首? 一个名为 x-middleware-subrequest 的请求头。Next.js 在内部使用该请求头来跟踪中间件执行情况,并防止递归问题。例如,当一个中间件触发另一个请求,而该请求又回到同一个中间件时,可能会导致循环调用。理论上,这个机制是合理的:如果请求头表明中间件已经执行(或达到递归限制),则会跳过执行。
但问题在于——这个请求头并未被严格限制为内部使用。任何人都可以在外部请求中手动添加它。
漏洞利用:绕过守门人
该漏洞的核心在于 Next.js 处理 x-middleware-subrequest 的方式。
在较旧的 Next.js 版本(12.2 之前),中间件会检查该请求头的值是否与中间件文件的路径匹配(例如 pages/_middleware)。如果匹配,则中止执行。
在较新的 Next.js 版本(12.2 及以上),官方引入了 MAX_RECURSION_DEPTH 递归深度限制,默认值为 5。如果请求头中的值包含 中间件路径重复 5 次或以上(用冒号 : 分隔),Next.js 就会认为发生了递归循环,并 直接跳过该中间件。
以下是一个利用该漏洞绕过中间件的示例,针对使用 App Router 的现代 Next.js 应用:
Copycurl -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware" http://example.***/dashboard
或者,如果应用使用 /src 目录:
Copycurl -H "x-middleware-subrequest: src/middleware:src/middleware:src/middleware:src/middleware:src/middleware" http://example.***/dashboard
通常情况下,中间件会将未经身份验证的用户重定向到 /login。但借助这个请求头,攻击者的请求可以直接绕过中间件,直接访问受保护的 /dashboard 路由。没有会话?没关系。服务器会误以为中间件已经完成了身份验证检查。
技术解析
让我们深入了解其内部机制。在 Next.js 15.2.2(截至当时的最新受影响版本)中,中间件执行逻辑位于 runMiddleware 函数中。以下是该漏洞代码的简化版本:
Copyexport const run = async function runWithTaggedErrors(params) {
const subreq = params.request.headers["x-middleware-subrequest"];
const subrequests = typeof subreq === "string" ? subreq.split(":") : [];
if (subrequests.length >= 5) {
return; // Skip middleware execution
}
// Proceed with middleware logic
};
逻辑非常直接:如果 x-middleware-subrequest 请求头存在,并且其值被冒号(:)分割后包含 五个或更多部分,中间件就会 直接退出。这个机制的本意是防止无限循环,比如当一个中间件重写请求并再次触发自身时。然而,该请求头没有任何来源验证,因此攻击者可以随意伪造它,将一个安全机制变成了一个安全漏洞。
在旧版本(11.1.4 到 12.1.x)中,检查逻辑更简单:如果该请求头的值与中间件文件的路径匹配(如 pages/_middleware),则直接跳过执行。无论是哪种方式,都给攻击者留下了可乘之机。
影响范围:不仅仅是身份验证绕过
这不仅仅是接管管理面板的问题,它的影响波及多个安全层面:
-
• 身份验证绕过:可在无需凭据的情况下访问受保护的路由。
-
• CSP 规避:绕过设置 CSP(内容安全策略)请求头的中间件,可能导致 XSS(跨站脚本攻击)。
-
• 缓存投毒:如果绕过的重写规则导致 404 或 500 错误,CDN 可能会缓存该状态,从而对合法用户造成 拒绝服务(DoS)。
-
• 地理限制绕过:绕过基于区域的访问控制中间件。
例如,假设某个网站使用中间件来设置 CSP:
export function middleware(request) {
const response = NextResponse.next();
response.headers.set("Content-Security-Policy", "default-src 'self'");
return response;
}
一旦利用该漏洞,该 CSP 头将不会生效,导致应用暴露在 脚本注入攻击 的风险之下。
检测与缓解
如何判断你的应用是否受到影响?
如果你的 自托管 Next.js 应用(使用 next start 且 output: standalone)依赖中间件进行安全检查,而没有额外的后端验证,你就处于风险之中。
哪些环境不会受影响?
-
• 托管在 Vercel 或 ***lify 上的应用(它们在漏洞披露前已修复)。
-
• 采用 静态导出(Static Export) 的 Next.js 应用。
修复方案
最安全的做法是 更新到已修补的版本:
-
• Next.js 15.x:升级到 15.2.3 或更高版本。
-
• Next.js 14.x:升级到 14.2.25 或更高版本。
-
• Next.js 13.x:升级到 13.5.9 或更高版本。
-
• Next.js 12.x:升级到 12.3.5 或更高版本。
无法立刻升级?
你可以在 反向代理(Reverse Proxy)或 Web 应用防火墙(WAF) 处 屏蔽 x-middleware-subrequest 请求头。以下是 Nginx 的配置示例:
Copyif ($http_x_middleware_subrequest) {
return 403;
}
要测试该漏洞,ProjectDiscovery 的 Nuclei 提供了一个方便的模板:
Copyid: CVE-2025-29927
info:
name:Next.jsMiddlewareBypass
severity:critical
description:DetectsNext.jsmiddlewarebypassviax-middleware-subrequestheader
http:
-method:GET
path:"/admin"
headers:
x-middleware-subrequest:"middleware:middleware:middleware:middleware:middleware"
matchers:
-type:status
status:
- 200
如果在预期返回 403 或重定向的情况下收到 200 响应,这就表明存在问题。