前阵子帮一家企业处理例行安全巡检的告警,几十条日志里有两类问题被平台标成了高危:一个是Druid Monitor未授权访问漏洞,另一个是Nacos Namespaces未授权访问漏洞。对于做过安全工作的人来说,这两个名字都不陌生,但真正让人头疼的不是“修好它”,而是搞清楚为什么会出现、修完之后会不会又被扫描器打出同类问题。这篇文章不打算把漏洞原理复述一遍,而是从实际处置经验出发,把未授权访问漏洞的判定、修复、验证和防回潮完整串起来,给做开发、运维和安全的同学一套能直接落地的参考。
1. 未授权访问漏洞:看似“锁没锁门”,实际是安全体系的一块缺口
1.1 为什么这个漏洞总被单独拎出来通告
未授权访问漏洞的官方定义并不复杂:某个系统功能或接口在正常情况下需要身份认证后才能访问,但由于配置错误、默认设置或开发疏忽,导致任何人都可以直接访问,不需要登录口令,也不需要任何合法凭证。Druid Monitor和Nacos的Namespace接口就是典型的例子。
这类漏洞之所以总在安全通告里被单独点名,是因为它对攻击者来说成本极低。普通的漏洞挖掘需要构造数据包、分析参数、研究逻辑,而未授权访问只需要一个浏览器或者一条请求,直接输入地址就能看到内部数据。正因如此,自动化扫描器特别偏爱这类漏洞,它只需检查某个路径是否存在且返回预期内容,就能判定为未授权访问漏洞。我在处置告警时经常看到扫描器的报告,十有八九都是这类问题。
从业务角度讲,未授权访问漏洞看起来不是“能直接拿权限”的高危漏洞,但它传递了一个信号:系统在访问控制层面缺乏最基本的检查。这个信号背后往往还有更多深层问题,比如默认配置未修改、管理端口未加白名单、上线流程没有安全评审。如果不把根子堵上,修完Druid,下一个被扫描器发现的可能就是别的组件。
1.2 三类高发原因:默认配置、内网信任、上线缺检
根据我处理过的案例,未授权访问漏洞几乎逃不出三个原因。
第一类是默认配置不设防。很多中间件为了降低使用门槛,默认情况下监控页面或管理接口是没有认证的,比如Druid的StatViewServlet、Nacos早期版本的接口鉴权。开发者只是在本地搭好了服务,全部沿用默认值,一旦服务上线,监控页面也就原样暴露了。
第二类是过度信任内网。这是最可惜的一类。运维同学会想:“这个监控页面只有内网能访问,外网又打不开,不需要设密码。”但现实是,内网里同样可能有低权限用户、被攻陷的主机、误配置的跳板,任何一台内网设备都可能成为攻击者接近管理页面的跳板。更重要的是,很多业务的前端和后端是通过反向代理暴露在公网的,代理把/druid/路径也一并转发出去后,内网限制就形同虚设。我就遇到过Spring Boot应用把Druid监控路径直接暴露到公网的情况,页面上能看到完整的数据库连接池配置。
第三类是上线流程缺少安全验收。开发环境里开着监控页面方便排障,上线时忘了关掉或忘了加认证,于是带着漏洞上线了。近几年有不少组件漏洞是靠自动化扫描发现的,原理扫描器不需要真实攻击,也能判断出接口是否缺少认证,这也是热词里“原理扫描”出现频率高的原因。对这种问题,最好的治理手段不是等扫描器发现,而是把安全检查嵌入到发布流程里。
2. Druid Monitor未授权访问:监控页面背后藏了多少敏感信息
2.1 Druid Monitor到底暴露了什么
Druid是Java生态里常用的一款数据库连接池组件,阿里开源,很多人都在用。Druid提供的监控功能称为StatViewServlet,默认路径是/druid/index.html,运维和开发可以通过这个页面快速查看连接池的运行状态、SQL执行频率、慢查询记录、活跃连接数、Session统计、Spring和Web URI访问统计等。在正常运维场景下,这个页面很好用,出了问题能第一时间定位到是哪条SQL拖慢了数据库。
但问题在于,StatViewServlet的鉴权默认是关闭的。也就是说,只要应用启动了Druid监控功能,任何人访问到/druid路径,都能看到完整的监控面板。我见过最严重的一次,页面上不仅显示着数据库的JDBC URL、驱动类名,连数据源用户名都一清二楚。配合URI监控里访问次数最多的接口,攻击者能很快判断出哪些接口在直接操作数据库,哪些接口存在SQL拼接的可能性,相当于把业务内部结构用一张图呈现在了攻击者面前。
另外,如果配置了reset-enable=true,访客还能直接在页面上点击“重置”按钮,清空所有统计数据。这虽然不直接破坏数据,但会导致运维人员的监控指标失效——你本来想靠这段时间的慢SQL记录排查问题,结果刚查了一半,统计被人一键清空了,所有排查线索全没了。
2.2 快速判断你的Druid监控是不是裸奔
判断方法不依赖任何工具。在获得授权的前提下,打开浏览器或者用curl直接访问一下你的应用地址,路径带上/druid/index.html。如果弹出登录框,说明配置了密码;如果直接显示监控面板,说明未授权访问漏洞存在。扫描器报的“druid monitor未授权访问漏洞”不一定完全准确,因为有些扫描器只看页面标题是否包含druid,而页面可能是404却返回了自定义标题,这种情况会导致误报。所以人工确认是第一步。
我自己的习惯是,看到告警后先做三件事。第一,确认访问的URL是否真的由应用返回监控内容,而不是CDN或统一拦截页面;第二,查看页面里是否出现SQL语句、数据源信息等敏感字段,如果只有空壳页面,风险等级要降一档;第三,用同样的URL从不同的网络位置(比如办公网、测试环境、云环境)分别访问一次,确认暴露面到底有多大。
提示:如果只是用浏览器看到200状态码,不要急着确认漏洞。手动刷新几次,或者查看响应内容是否包含“StatViewServlet”或“JdbcDataSource”等关键字,再下结论。
2.3 修复实操:密码、白名单、权限三层封堵
修复Druid未授权访问,核心思路不是关掉监控,而是让监控“只能给该看的人看”。我的标准做法是三层防护叠加。
第一层,给StatViewServlet加上登录认证。在Spring Boot项目中,可以在application.yml或application.properties里配置Druid的监控Servlet属性。以应用配置文件为例:
spring: datasource: druid: stat-view-servlet: enabled: true login-username: admin login-password: ${DRUID_PASSWORD} allow: 127.0.0.1,10.0.0.0/8 deny: "" reset-enable: false这里有两个关键点。一是把密码用环境变量${DRUID_PASSWORD}注入,不要明文写在代码仓库里,防止项目源码泄露时密码跟着泄露。二是allow选项建议只保留本机和内网网段,如果业务必须走公网,至少也要把公网访问控制交给WAF或安全组,而不是直接裸奔。reset-enable必须设为false,避免统计被重置。
第二层,在边界设备上做访问控制。即便应用内部配置了白名单,边界上的安全组、防火墙也应该同步限制。比如ECS安全组里不要把8080或8443这类端口对公网全放通,而是只放开业务需要的端口,或者把Druid监控路径对应的端口独立出来,仅对运维跳板机的IP开放。网络层和应用层同时收口,才叫真正的白名单。
第三层,如果只是排障需要,建议直接把监控页面关闭。Druid监控不是非开不可,遇到性能问题可以临时开启、用完关闭,或者改用Prometheus采集连接池指标,把数据放到Grafana看板,不暴露Druid页面本身。长期开着监控页面但没人维护,只会扩大攻击面。
2.4 关于“原理扫描”误报的判断心得
热词里的“原理扫描”指的是扫描器根据漏洞存在的原理去做探测,比如请求特定路径并分析响应特征,而不做真正利用。这类扫描准确率比较高,但仍然存在干扰因素。有些中间件或框架会自动生成默认页面,比如Spring Boot的404页面可能带有Whitelabel字样,如果扫描器拿到该状态码并匹配某些特征,就会误报。还有的CDN或云厂商的拦截页会返回200,也会造成误判。
我的习惯是,当扫描器报出Druid未授权访问后,不要直接改上配置就去扫描器里点“已验证”。先人工打开一下路径,截个图存档,确认存在真实风险再进入修复流程。修复后再重新跑一遍同样的检测,同时检查是否还有别的路径暴露,比如/druid/websession.json、/druid/datasource.json等子路径。只要Druid页面做了登录认证,这些接口同样会被拦截,验证时也要注意看子路径是否同步生效。
3. Nacos Namespaces未授权访问:配置中心一旦敞开,等于把钥匙交出去
3.1 Nacos中的Namespace与未授权访问的关系
Nacos是阿里开源的服务发现与配置中心,在微服务架构里几乎是标配。Namespace是Nacos里的隔离概念,可以理解成一个大房子里的不同房间,开发、测试、生产环境各占一个命名空间,彼此互不干扰。热词里提到的“nacos namespaces未授权访问漏洞”,重点不只是某个接口,而是Nacos在开启Namespace场景下,控制台和OpenAPI是否做了有效的身份鉴别。
这个漏洞的背景和Nacos早期的鉴权机制有关。Nacos提供了控制台和一批Open API接口,比如读取配置、注册服务、查询实例列表等。在默认配置下,很多版本的Nacos并没有强制开启鉴权,或者使用了容易猜解的默认密钥对用户Token进行签名。攻击者知道默认密钥后,可以手工伪造Token,在不登录的情况下访问带鉴权保护的接口,实现对任何Namespace下的配置进行读取。
这里要澄清一个容易混淆的点:未授权访问和越权访问在Nacos场景下经常同时出现。严格说,如果服务完全没开鉴权,任何人都能通过Open API读配置,这是未授权访问;如果服务开了鉴权但默认密钥泄露,攻击者用伪造Token访问了本不该访问的Namespace,这是认证绕过,最终效果等同于未授权访问。安全通告一般会把这两种情况归到同一个漏洞类别里,处置方式基本一致——升级版本、改强密钥、开鉴权。
3.2 漏洞为什么危险:配置中心的“钥匙效应”
Nacos的配置中心里存放的东西,是所有微服务启动时需要读取的配置,其中绝大部分是敏感信息:数据库连接池地址、Redis密码、消息中间件账号、第三方API密钥、某些业务开关和环境变量。注册中心里还记录着每个服务实例的IP和端口,攻击者拿着一份完整的服务列表,等于拿到了应用架构图。
我处理过一个很典型的案例。某公司的Nacos跑在K8s集群里,当初部署时为了方便,给Nacos控制台配置了一个ingress域名,没有开鉴权。扫描器扫到之后,安全团队通知了运维,运维第一反应是“虽然没密码,但是外网也不能直接访问吧”。结果一查,那个ingress把Nacos的HTTP端口完整暴露了出去,攻击者不仅能看到所有命名空间列表,还能直接拉取生产环境配置文件。数据库口令就放在配置中心的Data ID里,情况非常危急。
所以我把这个漏洞称为“钥匙效应”——整个微服务体系的配置相当于一整套门钥匙,钥匙放在了一个没有上锁的抽屉里。抽屉本身也许不引人注意,但只要有人路过,随手一拉就打开了。这也是为什么安全通告和扫描器都会把Nacos未授权访问标为高危,等于帮Nacos开着门还不设置密码。
3.3 修复Nacos未授权漏洞的完整路径
修复Nacos未授权访问漏洞,不能只看一个页面是否弹登录框,要从版本、鉴权、网络三个层面同时处理。
第一步是升级版本。Nacos官方在多个版本里针对认证绕过和默认鉴权问题做了修复,像CVE-2021-29441这类问题,在后续版本里已经解决。升级前先确认一下你当前使用的版本,以及发布说明里对鉴权模块的改动,不要盲目跳到最新版而不看变更。升级后要重新验证Token生成逻辑是否变更,避免影响其他系统对接Nacos。
第二步是开启鉴权并替换默认密钥。Nacos的鉴权需要显式开启,在application.properties中配置:
nacos.core.auth.enabled=true nacos.core.auth.system.type=nacos nacos.core.auth.plugin.nacos.token.secret.key=${NACOS_AUTH_SECRET}注意,这里的secret key一定不要再用官方文档里出现的默认值。生产环境中可以通过环境变量注入一段足够长的随机字符串,并且定期轮换。token密钥是身份签名的基础,如果用的是弱密钥或默认密钥,开启鉴权等于原地踏步。
第三步是控制网络暴露面。无论Nacos控制台还是Open API,都不应该直接被公网访问。常见的做法是绑定到内网IP并让K8s服务不发布公网Ingress;对于必须从远程访问的场景,通过堡垒机或运维代理跳转。安全组配置也建议按最小化原则,只允许业务子网访问Nacos的8848和9848端口,控制台端口单独管理,不要对全0.0.0.0/0开放。
3.4 升级后要复查的三个点
在Nacos修复验证中,我有三个必做的复查动作,很多团队容易忽略。
第一个复查点:确认旧的未授权访问接口是否关闭。升级后直接访问/nacos/v1/console/health/readiness、/nacos/v1/ns/instance/list等路径,看是否仍然能拿到数据。如果能拿到,说明要么升级失败,要么鉴权配置没生效,需要继续排查。
第二个复查点:确认不同Namespace之间的隔离是否真的生效。用两个不同环境的账号分别登录控制台,检查各自能看到哪些Namespace。生产环境的Namespace不应该出现在测试账号的可读列表里,如果出现了,说明权限模型配置不够细,需要按角色重新分配权限。
第三个复查点:检查服务端到Nacos的调用是否还能正常完成。开启鉴权后,微服务客户端会使用账号信息去Nacos拉取配置和注册实例,如果客户端没有配置正确的账号信息,服务可能启动报错或者拉不到配置。我见过很多团队在升级后只盯着控制台能登录,却没注意业务服务已经连续报错半个小时后才发现问题。改动前先在测试环境验证一遍客户端兼容性,再推生产。
做完这三个复查点,才算把Nacos未授权访问漏洞真正修复到位,而不是把漏洞从“能访问”改成“登录框式访问”。
4. 修复之后的验证与防回潮:从一次告警到常态化防护
4.1 常见未授权访问组件的统一排查视角
Druid和Nacos只是两个高发点。实际环境里还有很多组件同样可能出现未授权访问漏洞,我整理出一个统一的排查视角:看它是不是“管理类组件”,是不是“默认不认证”,是不是“需要有数据读写能力”。
Redis、Kafka、Elasticsearch、Hadoop YARN、MinIO、Jenkins等都是常见目标。以统一视角来看,它们的风险取决于三件事:一是是否绑定在0.0.0.0上,监听地址做得太宽意味着任意主机都能连接;二是是否依赖单纯的网络隔离而没做认证,一旦内网被渗透,认证缺失就会被利用;三是管理面板和API是否区分清楚,比如Kafka的JMX端口、ES的9200端口,如果为了方便监控全部暴露出去了,扫描器很容易识别到这些组件特征。
给安全团队的建议是,不要等扫描器逐个组件去报,而是建立一份资产清单,把每个对外端口、服务类型、认证方式、版本号登记下来。新服务上线时对照清单做差异检查,凡是清单之外的新开放端口,都要走安全审批。这套机制比任何单一漏洞修复都管用。
4.2 安全上线自检清单(可以直接拿去用)
如果你希望把未授权访问漏洞挡在发布前,下面这些检查项可以直接做成一张上线检查表:
| 检查项 | 检查方法 | 通过标准 |
|---|---|---|
| 管理端口暴露面 | 查看监听地址和云安全组规则 | 管理端口仅对内网/运维网段开放,不对公网全放通 |
| 默认账号和默认口令 | 检查组件配置文件和常见默认口令列表 | 不存在的默认口令,全部改为随机强口令并由密钥系统托管 |
| 监控页面/管理面板认证 | 访问对应URL观察是否要求登录 | 所有管理页面必须要求身份认证,且认证独立于应用自身 |
| 组件版本和CVE | 对比版本号与已知漏洞通告 | 已修复涉及未授权访问的关键缺陷,避免停留在过期版本 |
| 网络边界收敛 | 核对反向代理、Ingress、防火墙转发规则 | 不配置与业务无关的大范围转发路径 |
| 敏感信息存储 | 检查Nacos、Druid配置项中是否明文密码 | 密码等敏感项通过环境变量或密文配置注入 |
| 日志与监控 | 检查管理页面访问日志是否留存 | 对登录日志、敏感接口访问日志有留存和告警 |
对照这张表,可以快速定位未授权访问漏洞产生的直接原因。很多问题并不出在单个组件上,而是端口、认证、版本、日志四个维度都不满足要求,漏洞才会一层层漏出去。
4.3 发现告警后的半小时应急流程
如果扫描器或者态势感知平台突然报出了“未授权访问漏洞”告警,不要慌张,也不要直接关掉页面。我梳理了一套半小时内可完成的处置流程。
前5分钟:确认告警的有效性。先看一下扫描器报的URL和端口,判断是否为真实业务地址;如果扫描器只给了路径,就自己访问一遍,把响应内容保存下来。如果访问后确实能拿到敏感数据,按已确认的漏洞等级进入处置。
接下来10分钟:限制暴露面。对于确认存在的未授权访问漏洞,最优先的操作是立刻在网络边界上限制访问来源,比如在安全组或防火墙里加上只允许特定运维IP访问管理端口。这一步不需要改代码,也不需要发布,几秒钟就能完成,却能把最紧急的暴露面关掉。
后面的15分钟:定位并修复根因。根据系统归属找到开发和运维负责人,查明漏洞原因——是默认配置、版本过旧还是上线忘检查。参照上文Druid和Nacos的修复方式完成配置修改,同时在测试环境验证后重新发布。
注意:修复时一定要记住“先限制再修复”的顺序。如果先改代码再等发布,期间漏洞可能继续暴露几个小时;先做网络限制,再从容修复,才是稳妥的顺序。
4.4 防止回潮的三个习惯
处置完一次告警,不代表以后不会再出现。我自己在跟踪长期安全运营中,总结出三个比较有用的防回潮习惯。
第一个习惯是每季度做一次“公网视角”巡检。不使用内网工具,而是从外网的角度,请求核心业务域名下疑似存在管理组件特征路径,比如/druid/、/nacos/、/actuator/、/api/等。这个动作成本很低,却最容易发现配置漂移。很多团队会在某次紧急排障时临时打开历史监控路径,忘了关闭,季度巡检能及时把它找出来。
第二个习惯是把管理组件的变更纳入变更管理。凡是涉及Nacos、Druid、Redis、Kafka等组件的配置调整,都要在变更记录中说明“是否修改了认证方式、是否改变了网络暴露面”。上线之后由安全团队在环境中复核一次,而不是只靠开发自己承诺。
第三个习惯是不要迷信“内网”或“跳板机”带来的安全感。现代架构里,K8s的NodePort、Ingress、LoadBalancer、服务网格都可能在不知不觉间把内网服务带向公网。每次查看暴露情况时,要把K8s的Ingress和Service的externalTrafficPolicy也纳入检查列表。这听起来像是很基础的常识,但在实际处置中,很多未授权访问漏洞的根因恰恰是某个自动创建的LoadBalancer服务把管理端口映射到了公网。
把这三个习惯坚持下去,你会发现安全扫描器对“未授权访问漏洞”的告警量会明显下降。安全这件事,本质上不是某一个漏洞修得有多漂亮,而是能不能让同样的错误不再重复出现。
最后再分享一个我自己踩过的坑:有个项目我修完Druid未授权访问漏洞,直接在扫描器里点了“已修复”,结果过了两周又被同一个扫描器报出来。后来一查,原来是每次应用升级时,配置中心会把旧配置推送到新实例,Druid的login-username和login-password又被覆盖成了空值。从那以后,我每次修复都会把关键配置固化到基础设施的IaC或镜像里,并在监控页面加了一个外部探测告警——只要检测到管理页面不需要登录,就在群里自动提醒。这个思路也推荐给大家:防御未授权访问,最好能做成自动化的校验,而不是靠人肉每次记得检查。