先说结论:这次排查下来,Nacos未授权访问这个洞本身不算新奇,真正让我警觉的是它背后暴露出来的三个习惯性问题——默认不设防、内网全信任、变更无回溯。如果你们公司微服务架构里也跑着Nacos,而且一直没动过鉴权配置,那这篇文章值得你看完。我会把从漏洞确认、影响面研判到完整加固落地的每一步都写出来,包括中间踩过的坑和最后怎么验证效果,全程用我们实际操作的顺序来讲,你可以直接照着抄作业。
1. 场景回顾:配置中心的险情是怎么浮现的
1.1 例行巡检撞上未授权访问
事情起源于一次很常规的安全巡检。我们这边每周会有一次针对核心中间件的端口扫描和访问验证,主要看有没有把管理后台裸奔在公网或者内网可随意访问。那周轮到配置中心Nacos,我按老流程打开浏览器,输入地址访问控制台。
意外的是,页面没有出现登录框,而是直接跳转到了配置列表页。我第一反应以为是浏览器缓存了之前某个账号的登录态,于是换了无痕窗口重新访问,结果还是一样。接着我直接在测试机上用curl敲了两条请求:
# 尝试拉取配置列表 curl 'http://192.168.10.15:8848/nacos/v1/cs/configs?dataId=&group=&tenant=' # 尝试查看用户列表 curl 'http://192.168.10.15:8848/nacos/v1/auth/users?pageNo=1&pageSize=9'返回结果让我心里一沉:配置接口直接吐出了一大串配置内容,包含某几个生产环境的数据库连接串和中间件密码(当时显示的是脱敏前的明文配置),用户列表接口也正常返回了现有账号信息。也就是说,这台Nacos不仅是控制台未登录可进,它的开放API也是完全匿名可调的,且同时具备读写权限。
在继续深挖之前,我先明确了几个事实:这个Nacos部署在内网,但内网里跑着上百个业务节点,任何一个节点被攻破,横向移动到这台配置中心几乎没有任何阻碍。换句话说,问题的影响范围远不止“控制台被人看一眼”这么简单。
1.2 快速评估影响面:从读到写都没有设防
确认未授权访问之后,我们没有急着去改配置,而是先花了一个下午把影响面彻底摸清楚。这个步骤特别重要,因为只有知道了最坏的影响,才能说服团队和技术负责人同意停机维护和改造方案。
梳理出来的风险面大致有五块:
| 风险点 | 验证方式 | 实际结果 |
|---|---|---|
| 配置信息泄露 | 匿名调用配置拉取接口 | 所有配置可读,含数据库密码、中间件凭证 |
| 配置被篡改 | 匿名调用配置发布接口 | 可以新增和修改任意配置 |
| 账号体系暴露 | 匿名调用用户管理接口 | 可列举用户、可新增用户 |
| 服务注册信息泄露 | 匿名调用服务列表接口 | 全部微服务节点的IP和元数据可查 |
| 控制台接管 | 无痕模式直接访问 | 未登录直接进入管理界面 |
每条风险我都在测试环境做了最小化验证,没有对生产数据做任何写操作。确认的结果是:只要网络可达,这台配置中心就相当于向攻击者敞开了大门。攻击者可以读取全部配置拿到各类密码,可以修改任一配置把恶意内容推送给所有微服务,甚至可以直接创建一个新的管理账号,长期潜伏在系统里,每次进出都走正规通道,极难被发现。
到这里,问题已经不只是“开个鉴权”这么简单了。我们面对的是一个需要从版本、配置、密钥、账号、网络、客户端六个维度同时整改的系统工程。
2. 漏洞原理拆解:Nacos为什么会出这种问题
2.1 默认信任内网的设计边界
要理解这个漏洞为什么存在,得先搞清楚Nacos的默认设计逻辑。早期的Nacos版本在设计时,默认假设服务部署在可信的内网环境中,所以鉴权模块是默认关闭的,所有访问者被视为内网可信用户。
这种设计思路在互联网早期或许还能接受,但放到现在这个安全环境下就完全行不通了。微服务架构里,配置中心保存的是全公司最敏感的资产:数据库密码、Redis密码、消息队列凭证、第三方平台密钥、业务开关配置。可以说,谁能拿到配置中心,谁就拿到了整个业务系统的“密码本”。
更麻烦的是,很多团队在部署Nacos时沿用默认配置,安装完能跑就行,没人去翻过配置文件里的安全选项。在Nacos 1.x系列中,鉴权开关默认就是关闭的;到了2.x早期版本,同样存在默认配置不开启鉴权的情况。官方后续版本在不断强化安全默认值,但存量部署要是不主动升级,漏洞就会一直躺在那里。
我用一个生活化的类比来解释:这就像一栋写字楼,门禁系统是装好的,但物业默认把它调成了“常开模式”,楼里的每个人都默认是好人,谁进来都不会被拦。只要没人去把门禁模式改成“验证通过才放行”,那么外部人员只要知道了这栋楼的地址,就能自由进出每一层。
2.2 未授权访问的风险链路,比想象中更远
单看“未授权访问”这四个字,可能觉得危害不算大。但在实际攻击链路中,这往往只是第一步。我把可能被利用的路径拆开来看:
第一跳是配置读取。攻击者拿到数据库连接串后,可以直接连上核心数据库,执行任意SQL语句。这时候配置中心的问题就直接升级成了数据库泄露,影响从配置中心蔓延到了整个数据层。
第二跳是配置写入。攻击者可以修改任意微服务的配置,比如把一个服务调用的第三方接口地址改成自己控制的地址,或者把一个业务开关从“关闭”改成“打开”。配置中心的配置一旦下发,所有监听的客户端会立刻刷新,这个过程是自动化的,根本不需要攻击者一台台去操作服务器。
第三跳是账号创建。Nacos的用户管理接口在未授权状态下可以添加新用户,如果新用户被赋予管理权限,攻击者就拥有了一个合法的长期后门。后面即使团队发现异常,排查登录日志也找不到入侵痕迹,因为对方用的是一组“合法”账号。
第四跳是内网横向。通过服务列表接口拿到所有微服务节点IP后,攻击者就有了完整的内网资产地图,可以针对业务节点发起更精准的攻击。配置中心在这里扮演的角色,就像一个免费的情报中心。
所以,Nacos未授权访问绝不是一个“控制台没锁门”的小问题,它是一个典型的高危入口。这也是为什么我们在加固方案里反复强调,不能只做表面上的“开个鉴权”,必须从多个层面同时堵漏。
3. 加固方案设计与实施
3.1 定方案:不能一关了之,要有分步走
摸清影响面后,下一步就是制定加固方案。这里我先列了三个可选方案做对比:
| 方案 | 内容 | 优点 | 缺点 |
|---|---|---|---|
| 基础版 | 仅开启鉴权、修改默认密码 | 操作快、影响小 | 密钥仍是默认的,留了后门 |
| 推荐版 | 开启鉴权、更换自定义密钥、账号整改、网络隔离 | 安全收益高,对业务影响可控 | 需要客户端配合改造 |
| 完整版 | 推荐版全部内容、版本升级、审计加固 | 最彻底,可长期维护 | 改动面大,需要分批实施 |
实际执行时,我们选了完整版的思路,但拆成三个阶段来做,避免一次性改动太大导致线上事故。阶段一是开启鉴权和密钥轮换,阶段二是账号权限整改,阶段三是网络层访问控制。版本升级穿插在前期完成,因为旧版本的Nacos即使开了鉴权,也存在已知的安全缺陷,不升级的话,前面的加固会被后续发现的漏洞抵消。
这里要特别提醒:任何配置中心的安全整改,都必须在业务低峰期进行,并且提前通知所有相关团队。因为开启鉴权后,现有客户端将无法继续匿名访问,小到服务启动失败,大到线上动态刷新报错,都可能在切换瞬间集中出现。
3.2 备份先行:升级不是说说而已
动手改配置前,备份是第一要务。我们的Nacos配置数据存储在MySQL中,备份的主要对象是配置相关的几张表:config_info、config_info_gray、his_config_info、users、roles、permissions。备份方式用的是MySQL自带的mysqldump,执行时锁表保障一致性:
mysqldump -u数据库用户 -p密码 --single-transaction --set-gtid-purged=OFF nacos_config > nacos_config_$(date +%F).sql另外把整个Nacos的conf目录也做了一份文件级备份,里面包含了当前的application.properties配置。如果后续改造发现某个参数配错了,至少可以迅速回退到现有状态,不至于连之前的配置都找不回来。
备份完事后,我们直接进行了版本升级。考虑到原有实例上承载的业务量不小,我没有采用原地替换的方式,而是新起了两个新版本的Nacos节点,等数据同步完成后,把流量从旧节点切过去。这个过程说白了就是:旧配置中心预留只读观察,新配置中心承载读写,业务侧通过修改server-addr指向新节点来完成切换,这个操作天然给了我们一层安全保障。
3.3 核心步骤:开启鉴权与更换密钥
版本升级完成后,核心的鉴权配置就提上日程了。Nacos的鉴权配置集中在一个配置文件里——application.properties。我们需要在文件中新增或修改以下几项:
### 开启鉴权 nacos.core.auth.enabled=true ### 设置自定义Token密钥,必须是Base64编码,长度不小于32字节 nacos.core.auth.token.secret.key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ### 设置服务端身份标识,用于服务间通信校验 nacos.core.auth.server.identity.key=ServerIdentity nacos.core.auth.server.identity.value=自定义标识值这里有两个特别容易踩坑的点。第一个是nacos.core.auth.token.secret.key,网上很多教程直接把这个改成任意的英文字符串,那么简单了事的做法是不够的。官方要求的格式是Base64编码字符串,并且解码后的字节长度不能小于32字节。如果密钥强度不够,攻击者可以暴力破解或者直接使用默认密钥伪造Token。我们用的是这样生成的:
# 生成一个符合要求的随机密钥 openssl rand -base64 32生成的字符串直接粘贴到配置里即可,每次生成结果都不一样,不能复用默认值。
第二个坑是nacos.core.auth.server.identity.key和nacos.core.auth.server.identity.value,这两个值必须所有节点完全一致,否则集群节点之间通信会直接报错。如果Nacos部署的是单机模式,这个配置可以省略,但考虑到后面会扩集群,我们在一开始就把这两个值设置好了。
配置修改完,需要重启Nacos服务才能生效。重启后再次访问控制台,发现页面终于跳转到了登录页,之前的未授权访问问题在控制台层面已经封堵住了。这里提醒一句:控制台登录页出现后,还要确认刚才配置的密钥是否生效,否则后续伪造Token的风险依然存在。验证方式稍后在复测阶段详细说明。
3.4 账号权限整改:少就是好
开启鉴权后,Nacos自己的账号体系开始发挥作用。此时默认的账号密码依旧是nacos/nacos,如果不改,等于把门锁换了个新锁,但钥匙还插在门上。
账号整改我分成了三步。第一步是修改默认管理员密码。通过控制台操作,用默认账号登录后进入用户管理界面,直接修改密码。第二步是创建分类账号:给运维团队创建一个管理员账号,负责日常配置管理和节点维护;给业务团队创建一个只读账号,方便他们在控制台查看配置,但不能修改。第三步是清理无用账号,把历史遗留的、离职人员创建的账号全部删除,确保每个账号都能追溯到负责人。
这里有一个经验之谈:配置中心的账号体系最好和公司的统一认证平台打通,用单点登录来管理。如果公司还没有统一认证,那至少要把账号命名规范定下来,格式统一为姓名拼音首字母-业务标识,方便后续审计时排查。
另外,Nacos的用户角色权限模型支持细粒度的配置权限控制。如果你们有多个业务线共用一套Nacos,建议按命名空间隔离,并给不同团队分配不同命名空间的读写权限。我们这次把所有业务配置按 namespace 拆分后,权限管理清晰了很多,某个团队只能看到自己的配置,跨团队搜索配置的情况基本杜绝了。
3.5 网络层访问控制:最后一道安全兜底
配置层和账号层的加固做完后,还差最后一道防线——网络访问控制。再强的应用层鉴权,也挡不住端口全开带来的风险。Nacos的默认端口是8848,2.x版本还引入了gRPC端口9848,如果这两个端口在内网所有网段都能访问,那只要内网有一台机器被攻破,攻击者依然可以发起暴力破解或利用新发现的漏洞。
我们的做法是在防火墙策略上做了白名单限制:
- 8848端口:只允许运维管理网段和办公网指定的运维跳板机访问,其他网段一律拒绝。
- 9848端口:这是2.x新增的gRPC通信端口,客户端和服务端通信会用到,需要开放给业务网段。但同样限制了来源网段。
- 控制台页面:如果是从公网访问,必须通过跳板机或堡垒机,禁止直接将8848端口映射到公网。
网络层加固有一个原则:默认拒绝,白名单放通。这个原则执行起来会带来一些沟通成本,因为总有业务方过来说“我这边需要拉个配置,怎么访问不了”。但安全这个东西本来就是这样的,前期麻烦一点,后期才安全。
如果你的Nacos是部署在Kubernetes里,还可以配合NetworkPolicy做Pod级别的网络隔离,只允许需要连接配置中心的微服务Pod访问Nacos的Service,效果类似防火墙白名单,但粒度更细。
4. 客户端适配与平滑切换
4.1 客户端连接配置改造
服务端开启鉴权后,客户端这块如果不跟着改,线上服务会立刻出问题。我们团队使用的技术栈是Spring Cloud Alibaba,客户端的适配主要改两个配置文件。
第一个是bootstrap.yml,改造后的核心配置如下:
spring: cloud: nacos: config: server-addr: 192.168.10.20:8848 namespace: public username: config-reader password: 自定义密码 file-extension: yaml discovery: server-addr: 192.168.10.20:8848 namespace: public username: config-reader password: 自定义密码第二个需要关注的是老版本客户端兼容性问题。如果你用的spring-cloud-starter-alibaba-nacos-config版本比较老,客户端代码里根本没有实现“发送用户名密码”的逻辑,那即使服务端开了鉴权,客户端也只会傻傻地裸连,然后收到403报错。这种情况下,正确的做法是升级客户端依赖版本,而不是回退服务端配置。我们当时有一个老项目就卡在这个问题上,最后通过升级依赖版本解决的。
还有个容易忽略的坑:如果你的服务既要用Nacos做配置中心,又用它做服务注册与发现,那么config和discovery两个模块下的username和password都要配置,漏配一个就会导致服务注册不上但配置能拉取的诡异现象。
4.2 分批切换与回滚预案
基础设施层面改完,真正的考验在业务切换上。我们采用了“先试点、再批量、最后全量”的三步走方案。
第一步,选两个非核心的业务服务做试点。这两个服务在测试环境先验证配置拉取和服务注册是否正常,确认没问题后再在生产环境改配置、重启服务。观察半天,检查日志里有没有403错误、配置是否成功加载、注册中心能不能看到实例心跳。
第二步,开放一个配置管理页面给所有业务团队,把客户端改造方式发成文档,让各团队按文档自行修改并提交变更计划。我们统一排期,每天只切换十来个服务,每批切换完观察半小时。如果某个服务切入后出现异常,立刻回滚它到旧服务地址。
第三步,全部业务切换完成后,安排一次全量回归。重点看三个指标:各服务启动是否正常、动态配置刷新能否生效、控制台上的服务列表心跳是否全部在线。
回滚预案是我在整个实操中特别强调的一环。配置中心的安全加固一旦开始,最怕的就是出现“改到一半改不回去”的尴尬局面。我们当时保留旧版Nacos集群运行了一个星期,新集群稳定后,才把旧集群的只读模式关停。这种双跑期的存在,给所有参与改造的人吃了一颗定心丸。哪怕新集群出现意料之外的问题,随时都能切回旧集群,业务不中断。
5. 加固效果验证与风险复测
5.1 未授权访问复测清单
加固完成后,必须用验证结果来说话。我把之前发现漏洞时的检测方法重新执行了一遍,做成了一份复测清单:
| 检测内容 | 检测方式 | 加固前结果 | 加固后结果 |
|---|---|---|---|
| 未登录访问控制台 | 无痕浏览器直接访问控制台地址 | 直接进入配置列表页 | 跳转到登录页 |
| 匿名调用配置拉取接口 | curl 不带Token请求配置接口 | 返回全部配置内容 | 返回403禁止访问 |
| 匿名调用用户列表接口 | curl 不带Token请求用户列表 | 返回用户列表数据 | 返回403禁止访问 |
| 匿名调用添加用户接口 | curl POST添加用户 | 可以成功创建用户 | 返回403禁止访问 |
| 默认口令尝试 | 浏览器使用nacos/nacos登录 | 可以登录 | 登录失败 |
| 伪造Token访问 | 使用旧默认密钥生成Token后请求接口 | 可以访问 | 返回403禁止访问 |
我在测试环境执行了完整的复测,除了最后一项伪造Token的验证是在隔离的测试机完成,其余都在生产环境做了最小化探测。最终结果是:六项检测全部通过,未授权访问路径已经全部关闭。
复测过程中有一个小细节值得写出来:伪造Token验证这一项,操作时特别小心。我在旧的Nacos节点上导出了原来的默认密钥,生成一个Token去请求新版Nacos接口,确认返回403后,立刻销毁了这个Token并清理了测试记录。整个过程没有任何对生产数据的读写,仅仅是验证鉴权是否真正生效。
5.2 功能回归与监控观察
安全验证通过后,业务功能回归同样不容忽视。配置中心最核心的职责是“配置下发”和“服务发现”,这两个能力如果被加固操作误伤,安全性再高也没用。
我们回归验证了三类场景。第一类是配置拉取:随机挑了几个典型服务,确认它们启动后能正常读取到各自namespace下的配置。第二类是动态刷新:在控制台修改一个测试配置项,观察客户端是否在几秒内收到了变更事件并完成刷新。第三类是服务注册与发现:检查所有已切换的服务在Nacos控制台上是否都显示在线,心跳间隔是否正常。
观察周期我们拉长到了一周,重点盯Nacos服务端和客户端的错误日志,排查有没有间歇性403或者连接超时。一周下来,日志干净,业务无感,加固操作算是平稳落地了。这里补充一个容易忽略的点:开启鉴权后,Nacos控制台的登录会有token过期时间,如果你习惯在控制台长时间挂着操作,可能遇到“编辑配置时报token过期”的情况。这属于正常现象,重新登录即可,不是故障。
6. 常见问题与日常安全运维要点
6.1 加固过程中容易踩的坑
整个过程中,我们踩过几个比较典型的坑,也帮其他团队排查过类似问题,集中整理成一张速查表:
| 问题现象 | 原因分析 | 处理办法 |
|---|---|---|
| 开启鉴权后客户端启动报403 | 客户端未配置用户名密码,或客户端版本太老不支持鉴权 | 在bootstrap.yml中补充账号信息;升级客户端依赖版本 |
| 控制台登录后操作报token过期 | Token过期是正常机制 | 重新登录,或适当调大token有效期配置 |
| 服务注册不上,配置却能拉取 | config和discovery两个模块的账号配置漏了一个 | 补全discovery模块下的username/password |
| 集群节点间通信报错 | server.identity.key/value配置不一致 | 检查所有节点配置文件,确保完全一致并重启 |
| 修改配置后客户端不生效 | 服务没有开启动态刷新,或namespace配错 | 确认spring.cloud.nacos.config.refresh-enabled为true,检查namespace |
| 升级新版本后旧API调用失败 | 1.x和2.x的接口路径有差异 | 按新版本API规范更新调用代码,或短期保留兼容层 |
这些坑里最让我印象深刻的是“改了配置不生效”那次。当时有同事反馈,明明在控制台改了配置,业务侧却毫无反应。排查了一圈,最后发现是客户端bootstrap.yml里namespace配错了,连到了另一个命名空间的配置。要知道,配置中心这种东西,一个小小的namespace写错,表面上完全看不出异常,但实际行为就是货不对版。所以强烈建议团队内部统一namespace命名规范,并且把客户端配置做成公共模板,减少人工手写出错的机会。
6.2 配置中心的日常安全运维
安全加固不是一次性项目,配置中心的防护更应该是持续性的日常动作。结合这次实践,我把后续要做的事总结成了几条基线,你们可以参考:
第一,每季度复测一次未授权访问。不用搞复杂工具,就把我上面那张复测清单里的六项检测跑一遍,几分钟出结果。重点确认鉴权配置没有被后续升级或变更意外改回去。
第二,Nacos版本的升级要提上常态化日程。官方有新版本发布时,我会去翻一下release notes,如果涉及安全修复,就要在一个月内安排升级。升级前先在测试环境做兼容性验证,再按前面说的方法分批切换。
第三,定期审计账号和权限。每季度导出一份账号列表,逐一确认每个账号的负责人和权限范围。离职人员账号必须第一时间注销,这是底线。如果账号体系已经接入统一认证平台,这条可以靠流程自动保证。
第四,监控必须覆盖配置中心。至少要在监控系统里加上Nacos节点的端口存活检查、JVM内存使用率、客户端连接数、鉴权失败日志告警这几个指标。尤其是批量鉴权失败告警,这通常意味着有人在尝试暴力破解。
第五,配置内容里的敏感信息要收敛。即使Nacos本身已经加了鉴权,也不建议在配置里明文存放数据库密码。更稳妥的做法是配合使用专门的密钥管理服务,配置里只引用密钥的ID,由应用在运行时从密钥服务动态获取。这样就算配置中心被突破,攻击者拿到的也只是密钥引用,而不是密钥本身。
最后分享一点个人体会
这次Nacos加固上线后,我重新翻了之前写的巡检记录,发现未授权访问其实不是最近才出现的,漏洞可能已经存在了很久,只是因为内网环境一直没人发现而已。
我个人在实际操作中的体会是:配置中心这类基础设施,安全基线建立起来之后,最大的挑战已经不在技术本身,而在流程和管理。技术上的修复就是改配置、改版本、改账号,每一样都有文档可查;难的是让整个团队形成“任何变更都要回顾安全配置”的意识。
最后分享一个小技巧:在Nacos的application.properties里加配置时,建议把鉴权相关参数集中放在一起,加上注释说明修改人和修改日期。以后再做版本升级或者配置变更时,一眼就能看出哪些是安全相关配置,哪些是功能性配置,不至于在几十个参数里大海捞针。这个小习惯,关键时刻能帮你省下大量的排查时间。