创作声明
AI创作声明
本文由AI辅助创作,经作者人工审核与修订。内容旨在技术交流与学习,如有疏漏或错误,欢迎指正。
免责声明
本文内容仅供学习与研究用途,不保证完全准确或适用于所有环境。读者依据本文操作所产生的一切后果,作者及平台不承担任何法律责任。请遵守法律法规,勿将技术用于非法目的。
版权声明
本文为原创内容,版权归作者所有。未经授权,禁止商业用途转载。非商业转载请注明出处并保留本声明。
准备工作
Docker的常用命令
docker compose pull #将远程镜像拉取到本地
docker compose up -d #启动容器,并且不包含下载日志
docker ps #查看开放端口
docker compose logs #查看日志
docker compose down #销毁容器
docker compose build #重启容器
docker compose exec web bash #进入名为web的服务容器并打开 Bash 终端的命令
漏洞概述
CVE-2025-29927 是一个影响 Next.js 全栈 React 框架 的 授权绕过(Authorization Bypass) 漏洞,影响使用 Next.js 中间件(middleware)做授权检查 的应用场景。漏洞赋予未授权用户在特定条件下访问受限路由或资源的能力,是高风险配置错误类漏洞。
- 受影响版本:
- Next.js v11.1.4 至 <12.3.5
- Next.js v13.0.0 至 <13.5.9
- Next.js v14.0.0 至 <14.2.25
- Next.js v15.0.0 至 <15.2.3
- 漏洞类型:不当授权/鉴权绕过(CWE-285/CWE-863)
- CVSS v3.1 评分:9.1/10(Critical)
正常访问流程逻辑
┌────────────┐
│ Client │
└─────┬──────┘
│ ① HTTP 请求
▼
┌────────────────────┐
│ Next.js Middleware │
│ - 身份校验 │
│ - 权限判断 │
└─────┬──────────────┘
│ ② 校验通过
▼
┌────────────────────┐
│ Protected Route │
│ /admin /api/... │
└────────────────────┘
在正常情况下,所有客户端请求在到达受保护资源之前,均需经过 Next.js 中间件进行身份认证与访问控制。中间件根据用户会话信息或访问令牌判断请求是否具有访问权限,从而防止未授权访问。
攻击流程原理图
┌──────────────┐
│ Attacker │
│ (Unauth) │
└─────┬────────┘
│ ① 构造 HTTP 请求
│ + x-middleware-subrequest
▼
┌────────────────────┐
│ Next.js Middleware │
│ ❌ 误判为内部请求 │
│ ❌ 跳过鉴权逻辑 │
└─────┬──────────────┘
│ ② 未授权直达
▼
┌────────────────────┐
│ Protected Resource │
│ /admin /api/... │
└────────────────────┘
修复后安全流程
┌────────────┐
│ Client │
└─────┬──────┘
│ HTTP 请求
▼
┌────────────────────────┐
│ Middleware │
│ - 忽略外部 header │
│ - 强制身份校验 │
└─────┬──────────────────┘
│
▼
┌────────────────────┐
│ Protected Resource │
└────────────────────┘
漏洞原理
这个漏洞的本质不是低级内存误用,而是 Web 框架信任了来自客户端的内部标识信息,从而错误地跳过授权检查。
关键因素:x-middleware-subrequest 请求头
在 Next.js 的 middleware 实现中:
- 中间件机制用于管理授权、重写和缓存逻辑。
- 为了避免内部请求的无限递归,Next.js 使用头部
x-middleware-subrequest标识已处理的请求循环。 - 当前漏洞存在于没有对该头部来源做信任校验的逻辑里:如果请求被设置了这个头部,Next.js 会错误地认为它已经过了中间件检查并直接传递到受保护的路由处理器。
换句话说,就是:
服务器信任了本应由内部框架控制的 header 字段作为“已授权”的标记,但没有验证来源,因此客户端可伪造该标记绕过安全检查。
如果某个 Next.js 应用将登录 / 权限检查逻辑放在 middleware 里(这很常见),攻击者只需构造带 x-middleware-subrequest 的外部请求就能访问原本受保护的页面或 API。
为什么这会绕过授权?Next.js 的 middleware 设计初衷是为了优化内部流程,并避免重复执行中间件逻辑,但实现时错误地把根据 header 判断是否“已被执行过”和根据身份授权结果混淆,导致:
if (header x-middleware-subrequest exists) { skip middleware entirely; }
而没有检查该 header 是否由可信环境生成,就直接信任客户端输入。
影响范围
只要你使用:
- 自建部署的 Next.js(非 Vercel Hosted)
- 且使用 middleware 处理身份验证、访问控制 就可能受到影响。如果没有 middleware 授权逻辑,则可能不会构成严重威胁。
漏洞复现
正常情况下,输入admin:password能够看到管理员后台。
但是如果我们在抓包的基础上,在请求头加上一行“x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware”的值。即使不用登录密码,便能够达到同样的效果。漏洞利用非常简单,但是立即就获取到管理员权限,因而该漏洞危害极其严重。
修复建议
- 升级 Next.js 到安全版本(最推荐)
官方已经在以下版本修复了这个漏洞:
| 版本主线 | 修复版本 |
|---|---|
| Next.js 12.x | ≥ 12.3.5 |
| Next.js 13.x | ≥ 13.5.9 |
| Next.js 14.x | ≥ 14.2.25 |
| Next.js 15.x | ≥ 15.2.3 |
- 短期缓解措施(无法立刻升级时)
在无法立即升级框架的情况下,可以采取以下防护措施:
🔹 屏蔽恶意 header
在应用入口层(例如 Nginx、Cloudflare、Ingress Controller)阻止带有 x-middleware-subrequest 的外部请求到达 Next.js:
# 示例 (Nginx) if ($http_x_middleware_subrequest) { return 403; }
这样能够防止攻击者利用该 header 绕过中间件。
🔹 拒绝受信以外来源的内部标记
如果你不能升级框架,尽量在自定义中间件中校验 header 可信性,比如:
if (req.headers["x-middleware-subrequest"] && !trustedOrigin) { reject(); }
虽然不能完全保证安全,但可以减缓风险。
- 中间件层增加多层校验
除了依赖框架内的鉴权,还应在应用代码层做多层授权验证:
- 强制检查 JWT / Session 而不是只依赖 middleware 调用顺序。
- 在业务路由里增加额外鉴权逻辑(防止单点绕过)。
- 对关键资源(如 admin)加额外策略(RBAC / ACL)。 这类逻辑补充可以减少单点点破坏性影响。
基于该漏洞的安全检测与防护规则
检测思路:外部客户端请求中,携带了本应仅由 Next.js 内部生成的请求头: x-middleware-subrequest。
威胁建模
| 项 | 内容 |
|---|---|
| 攻击面 | HTTP 请求头 |
| 可控性 | 客户端完全可控 |
| 合法来源 | Next.js 内部子请求 |
| 异常点 | 外部请求携带内部标记 |
| 检测难度 | 低 |
| 误报概率 | 极低 |
WAF 检测规则设计
- 通用 WAF 逻辑规则(抽象描述)
规则名称:Next.js Middleware Authorization Bypass Attempt
规则描述:检测外部 HTTP 请求中非法携带x-middleware-subrequest请求头的行为
风险等级:High / Critical
处置建议:阻断 + 记录
检测条件(逻辑):
IF
HTTP Header 包含 "x-middleware-subrequest"
AND
请求来源 ≠ 内部 Next.js 子请求
THEN
判定为高危异常请求
- ModSecurity(OWASP CRS 风格)
ModSecurity 规则示例
SecRule REQUEST_HEADERS:x-middleware-subrequest ".+" \
"id:202529927,\
phase:1,\
block,\
t:none,\
msg:'Next.js Middleware Authorization Bypass Attempt (CVE-2025-29927)',\
severity:CRITICAL,\
tag:'application-multi',\
tag:'cve-2025-29927',\
tag:'nextjs',\
tag:'auth-bypass'"
规则特点
- phase:1(请求头阶段,性能开销极低)
- 不依赖 URI / 参数
- 不依赖 payload 特征
- 不怕混淆、不怕编码
IDS / NIDS 检测规则(Suricata / Snort)
Suricata 规则示例
alert http any any -> any any (
msg:"CVE-2025-29927 Next.js Middleware Auth Bypass Attempt";
http.header;
content:"x-middleware-subrequest";
nocase;
classtype:attempted-admin;
sid:202529927;
rev:1;
)
规则说明
- 基于 HTTP Header 内容匹配
- 不依赖具体 URI
- 适用于南北向流量检测 Snort 规则示例
alert tcp any any -> any 80 (
msg:"Next.js Middleware Authorization Bypass Attempt";
content:"x-middleware-subrequest";
http_header;
sid:202529927;
rev:1;
)
SIEM / 日志关联检测规则(进阶)
适合写成 “多源日志安全分析”。 检测逻辑
IF
HTTP 请求头包含 x-middleware-subrequest
AND
Source IP ≠ 应用服务器 IP
THEN
高置信度授权绕过告警
可关联字段
| 字段 | 用途 |
|---|---|
| src_ip | 攻击源 |
| uri | 被访问资源 |
| status_code | 是否绕过成功 |
| user-agent | 攻击工具指纹 |
有关/next.js/CVE-2025-29927的安全检测与防护规则,使用python中的flask和Tensorflow和Modsecurity的技术
- 基于 Flask 的请求检测(应用层/反向代理)
部署一个 Flask 应用作为反向代理或 API 网关,对每个请求进行预处理,检测恶意头并拦截。
from flask import Flask, request, abort
import re
app = Flask(__name__)
# 敏感路径列表
SENSITIVE_PATHS = ['/admin', '/api/private', '/dashboard', '/user/*']
@app.before_request
def check_middleware_bypass():
# 检查是否包含攻击头
if 'x-middleware-subrequest' in request.headers:
header_value = request.headers.get('x-middleware-subrequest')
# 规则1:检测头是否存在(正常请求极少携带此头)
# 规则2:检测值是否符合攻击模式(通常为数字或特定格式)
if header_value and re.match(r'^\d+$', header_value):
# 记录攻击日志
log_attack(request)
# 可选择拦截或仅记录
abort(403, description="Forbidden: Suspicious request header")
# 检查请求路径是否敏感且未授权(可根据实际情况增强)
for pattern in SENSITIVE_PATHS:
if request.path.startswith(pattern.rstrip('*')):
# 在此可进一步验证用户会话等
pass
def log_attack(request):
with open('attack.log', 'a') as f:
f.write(f"{request.remote_addr} - {request.method} {request.path} - {request.headers}\n")
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
- 基于 TensorFlow 的异常流量检测(机器学习模型)
使用 TensorFlow 构建一个简单的神经网络模型,识别包含攻击特征的请求。适用于大规模流量分析。
特征提取 从每个 HTTP 请求中提取以下特征:
- 是否包含
x-middleware-subrequest头(0/1) - 该头的长度
- 该头的值是否为纯数字(0/1)
- 请求路径长度
- 请求路径是否包含敏感关键词(如
admin,api) - User-Agent 异常度(长度、字符分布等)
- 请求方法(GET/POST 等编码为 one-hot)
训练数据准备 收集正常业务流量和模拟攻击流量(包含伪造头的请求),标记为正常(0)和攻击(1)。可以使用 Flask 应用模拟攻击生成样本。
模型训练示例
import tensorflow as tf
from tensorflow.keras import layers, models
import numpy as np
# 假设已有特征矩阵 X 和标签 y
# X 形状: (样本数, 特征数)
# y 形状: (样本数,)
model = models.Sequential([
layers.Dense(64, activation='relu', input_shape=(X.shape[1],)),
layers.Dropout(0.3),
layers.Dense(32, activation='relu'),
layers.Dropout(0.3),
layers.Dense(1, activation='sigmoid')
])
model.compile(optimizer='adam',
loss='binary_crossentropy',
metrics=['accuracy'])
history = model.fit(X, y, epochs=10, batch_size=32, validation_split=0.2)
# 保存模型
model.save('nextjs_middleware_detector.h5')
实时检测集成
将训练好的模型集成到 Flask 应用中,对每个请求进行实时评分,若概率高于阈值则拦截。
import numpy as np
from tensorflow.keras.models import load_model
model = load_model('nextjs_middleware_detector.h5')
def extract_features(request):
# 实现特征提取逻辑
features = []
# ... 计算特征 ...
return np.array(features).reshape(1, -1)
@app.before_request
def ml_detection():
features = extract_features(request)
prob = model.predict(features)[0][0]
if prob > 0.8: # 阈值可调整
log_attack(request)
abort(403, description="Blocked by ML detection")
- 基于 ModSecurity 的 WAF 规则
在 ModSecurity(如 Apache/NGINX 模块)中添加以下规则,直接拦截攻击请求。
# 文件名: modsecurity_crs_65_nextjs_cve_2025_29927.conf
# 规则1:检测 x-middleware-subrequest 头,若存在且值为数字则阻断
SecRule REQUEST_HEADERS:x-middleware-subrequest "@rx ^\d+$" \
"id:1001001,\
phase:1,\
block,\
capture,\
t:none,\
msg:'Next.js CVE-2025-29927 Middleware Bypass Attempt',\
logdata:'Matched Header: x-middleware-subrequest: %{MATCHED_VAR}',\
tag:'attack-middlware-bypass',\
tag:'cve-2025-29927',\
severity:'CRITICAL',\
setvar:'tx.anomaly_score=+%{tx.critical_anomaly_score}'"
# 规则2:检测该头存在且请求路径为敏感目录(如 /admin)则阻断
SecRule REQUEST_HEADERS:x-middleware-subrequest "!@eq 0" \
"id:1001002,\
phase:1,\
chain,\
block,\
msg:'Next.js CVE-2025-29927 Exploit with Sensitive Path',\
tag:'attack-middlware-bypass'"
SecRule REQUEST_URI "@beginsWith /admin" \
"setvar:'tx.anomaly_score=+%{tx.critical_anomaly_score}'"
# 规则3:检测分块传输或编码绕过(可选)
SecRule REQUEST_HEADERS:Transfer-Encoding "@rx chunked" \
"id:1001003,\
phase:1,\
t:none,\
pass,\
nolog,\
chain"
SecRule REQUEST_HEADERS:x-middleware-subrequest "!@eq 0" \
"block,\
msg:'Chunked encoding with suspicious header'"