近日,Next.js 官方披露了一个严重级别的安全漏洞(CVE-2025-29927/GHSA-f82v-jwr5-mffw),该漏洞影响了大量使用 Next.js 中间件实现授权功能的应用程序。
漏洞概述
基本信息
- 漏洞编号:CVE-2025-29927 / GHSA-f82v-jwr5-mffw
- 漏洞类型:授权绕过(CWE-285)
- 严重级别:严重(Critical)
- CVSS 评分:9.1/10.0
- 影响版本:
- 11.1.4 至 13.5.6
- 14.0 至 14.2.24
- 15.0 至 15.2.2
- 修复版本:14.2.25、15.2.3
漏洞简述
此漏洞允许攻击者通过添加特定 HTTP 请求头(x-middleware-subrequest
)完全绕过在 Next.js 中间件中实现的授权检查,从而获取对受保护资源的未授权访问。由于许多 Next.js 应用仅在中间件层实现授权逻辑,这使得该漏洞的影响范围极广且危害严重。
技术深度分析
Next.js 中间件机制回顾
Next.js 的中间件功能允许开发者在页面渲染前拦截请求,实现如授权检查、请求重写等功能。中间件在服务端执行,通常位于项目根目录的middleware.js
或_middleware.js
文件中。
一个典型的授权中间件实现如下:
import { NextResponse } from 'next/server'
export function middleware(request) {
// 获取会话或令牌
const token = request.cookies.get('token')?.value
// 授权检查
if (!token || !verifyToken(token)) {
// 未授权,重定向到登录页
return NextResponse.redirect(new URL('/login', request.url))
}
// 授权通过,继续请求
return NextResponse.next()
}
export const config = {
matcher: ['/dashboard/:path*', '/api/protected/:path*'],
}
漏洞原理
该漏洞的根本原因在于 Next.js 中间件处理子请求的机制存在缺陷:
-
内部子请求标识:当中间件需要向内部路由发出请求时(例如获取数据或验证信息),Next.js 会自动添加
x-middleware-subrequest
头,以标识这是一个内部请求,防止中间件陷入无限循环。 -
来源验证缺失:漏洞出现的关键点是 Next.js 没有正确验证这个头的来源。当外部请求携带此头时,中间件错误地将其识别为内部子请求。
-
中间件执行逻辑:当检测到
x-middleware-subrequest
头时,Next.js 会跳过对该请求的中间件执行,直接将请求传递给目标路由或 API。 -
授权绕过实现:攻击者只需在请求中添加
x-middleware-subrequest: 1
头,就能使中间件的授权检查被完全跳过,直接访问受保护资源。
漏洞复现
以下是一个简单的漏洞利用脚本:
const fetch = require('node-fetch')
async function exploitAuthBypass() {
const response = await fetch('https://target-app.com/api/protected-data', {
method: 'GET',
headers: {
// 关键漏洞利用点:添加这个头即可绕过中间件授权
'x-middleware-subrequest': '1',
},
})
if (response.ok) {
const data = await response.json()
console.log('成功绕过授权:', data)
}
}
exploitAuthBypass()
影响评估
受影响场景
此漏洞主要影响以下场景:
-
仅依赖中间件授权:应用程序只在中间件中实现授权检查,而 API 路由或页面组件本身不做额外验证。
-
混合授权模式:即使实施了多层授权,如果部分路由仅依赖中间件保护,这些路由仍然易受攻击。
-
第三方授权库:一些基于 Next.js 中间件的授权库可能同样受到影响,尤其是那些将授权逻辑封装在中间件中的库。
具体危害
- 敏感信息泄露:攻击者可以访问受保护的 API 端点,获取敏感数据。
- 业务逻辑绕过:可以绕过基于角色的访问控制,执行未授权操作。
- 个人隐私风险:可能导致用户个人信息被未授权访问。
- 账户接管:在某些情况下,可能导致账户接管或权限提升。
全面防御策略
立即修复方案
-
升级 Next.js 版本:
- 对于 Next.js 15.x,升级到 15.2.3 或更高版本
- 对于 Next.js 14.x,升级到 14.2.25 或更高版本
- 对于 Next.js 11.1.4 至 13.5.6,应考虑升级到最新的安全版本
-
临时缓解措施(如无法立即升级):
- 在网关/代理层过滤或删除所有外部请求中的
x-middleware-subrequest
头 - Nginx 配置示例:
# 删除所有传入的x-middleware-subrequest头 proxy_set_header x-middleware-subrequest "";
- AWS WAF 示例规则:
{ "Name": "block-middleware-header", "Priority": 1, "Action": { "Block": {} }, "VisibilityConfig": {...}, "Statement": { "ByteMatchStatement": { "SearchString": "x-middleware-subrequest", "FieldToMatch": { "Headers": { "MatchPattern": "All" } }, "TextTransformations": [{ "Priority": 0, "Type": "NONE" }], "PositionalConstraint": "CONTAINS" } } }
- 在网关/代理层过滤或删除所有外部请求中的
安全最佳实践
-
深度防御策略:
-
在 API 路由和中间件中都实现授权检查
-
示例 API 路由实现:
import { getServerSession } from 'next-auth/next' export default async function handler(req, res) { // 即使有中间件保护,也在API路由中重复授权检查 const session = await getServerSession(req, res) if (!session) { return res.status(401).json({ error: '未授权访问' }) } // 处理授权请求... res.status(200).json({ data: '敏感数据' }) }
-
-
不依赖单层保护:
- 将授权逻辑从中间件移至 API 路由或页面组件
- 使用 Next.js 的
getServerSideProps
或getStaticProps
进行页面级别的授权检查
-
使用更安全的授权模式:
- 考虑使用 JWT 或其他带签名的令牌机制
- 实现细粒度的权限检查,不仅验证身份,还验证操作权限
-
使用 next-auth 的建议:
- 如果使用 next-auth,不要仅依赖中间件,同时使用
getServerSession
在每个路由中验证会话 - 确保正确配置 next-auth 的回调和事件处理函数
- 如果使用 next-auth,不要仅依赖中间件,同时使用
-
请求验证增强:
- 对于关键 API,考虑实现请求签名机制
- 使用 CSRF 令牌防止跨站请求伪造
检测与审计
漏洞检测方法
-
主动测试:
- 使用未认证的客户端向受保护 API 发送带有
x-middleware-subrequest
头的请求 - 如果成功访问,则表明应用存在漏洞
- 使用未认证的客户端向受保护 API 发送带有
-
日志分析:
- 检查访问日志中是否存在包含
x-middleware-subrequest
头的请求 - 关注这些请求的响应状态码和相关会话信息
- 检查访问日志中是否存在包含
-
代码审计:
- 审查中间件实现,确认授权逻辑是否仅存在于中间件
- 检查 API 路由是否有独立的授权验证
总结与思考
这个 Next.js 中间件授权绕过漏洞再次提醒我们,在构建 Web 应用安全架构时,不应该依赖单一防御层。虽然中间件提供了便捷的集中式授权机制,但它不应成为唯一的安全屏障。
安全是一个持续的过程,需要在开发、测试和运维的各个环节都给予足够重视。针对此类漏洞,我们不仅需要进行技术修复,更应反思整体安全架构设计,实施更全面的安全策略。
作为开发者,我们应当:
- 保持对安全最佳实践的学习和更新
- 采用多层次安全防御策略
- 定期进行安全审计和测试
- 及时更新框架和依赖到安全版本
通过这些措施,我们可以更好地保护我们的应用和用户数据安全。
参考资料
- GitHub 安全公告: GHSA-f82v-jwr5-mffw
- Next.js 官方文档: 中间件
- Next.js GitHub 仓库: 修复提交