Spring Cloud 安全排查:Actuator、网关改写与 Nacos 凭据
Spring Cloud 安全排查:Actuator、网关改写与 Nacos 凭据
网关鉴权并不覆盖所有入口。注册中心、配置中心、追踪系统和 Actuator 都可能通过内网或管理端口被访问。安全检查应从“谁能连到它、能做什么、凭据多久失效”三个问题开始,而不是只看网关配置。
下面列的是排查顺序。配置键和默认行为会随组件版本变化,上线前应对照所用版本的官方文档与实际部署核验。
flowchart TD subgraph External ["外网未授权访问 / 潜在攻击者"] Attacker["攻击请求"] end subgraph DefenseLine ["微服务纵深防御体系"] Gateway["API 网关 (Spring Cloud Gateway)<br/>JWT 签名校验 & Header 防篡改"] subgraph InternalMesh ["内网安全隔离区"] ServiceA["业务微服务 A"] ServiceB["业务微服务 B"] Actuator["Actuator 敏感端点 (/env, /heapdump)<br/>绑定独立管理端口或彻底禁用"] Nacos["Nacos 配置中心<br/>开启 Auth & Jasypt 密文存储"] end end Attacker -->|1. 正常业务流量| Gateway Gateway -->|2. 透传已被签名的 User Context| ServiceA ServiceA -->|3. 内网 mTLS / 秘钥验证 RPC| ServiceB Attacker -.->|错误配置: 直连内网端口| Actuator Attacker -.->|错误配置: 越权访问内网接口| ServiceA1. 隐患入口一:Spring Boot Actuator 端点暴露
Spring Boot Actuator 提供了强大的应用监控能力,包含/actuator/env、/actuator/heapdump、/actuator/beans等端点。如果在生产环境配置文件中将敏感端点向公网暴露,后果极其严重:
heapdump端点泄漏:攻击者可以直接下载整台机器的内存 Dump 文件,从中提取数据库连接密码、Redis 授权密钥以及 JWT 签名私钥。env格式泄露与 RCE 隐患:通过环境配置端点,不仅能拿到明文配置,在旧版本 Spring Cloud 中甚至可能被利用引发远程代码执行(RCE)。
源码原理与防护配置
Actuator 的端点暴露由ManagementServerProperties与EndpointAutoConfiguration控制。默认情况下,绝大部分端点在 Spring Boot 2.x/3.x 中未通过 Web 暴露,但某些开发者为了调试方便,在 YAML 中配置了include: "*"。
严谨的防御方案,是在配置文件中仅暴露健康检查端点,并将管理端口与业务端口进行物理隔离:
management: server: port: 8090 # 将 Actuator 绑定至独立的物理/虚拟端口,禁止公网网关路由映射 address: 127.0.0.1 # 限制仅本地环回地址访问 endpoints: web: exposure: include: "health,prometheus" # 仅暴露健康检查与指标采集 exclude: "env,heapdump,threaddump,configprops"2. 隐患入口二:API 网关路径剥离(StripPrefix)与未授权绕过
在 Spring Cloud Gateway 中,常见做法是配置StripPrefix=1或Path=/api/v1/user/**转发规则。如果后端微服务同时包含了未授权的内部管理接口(如/internal/reset-password),而网关的 Filter 正确性未经过严格打靶,容易造成越权访问。
例如,当网关配置了如下谓词:
spring: cloud: gateway: routes: - id: user_service uri: lb://user-service predicates: - Path=/user-service/** filters: - StripPrefix=1攻击者可能通过构造特殊的 URL 请求(如/user-service/internal/reset-password),绕过外网鉴权 Filter 链条,直接命中后端微服务的内部敏感接口。
防御方案:微服务内部鉴权 Filter
在后端业务微服务中,必须配置全局安全拦截器,校验请求是否来自网关透传的内部合法 Header。如果缺失网关私钥签名的 Header,直接拒绝请求:
@Component public class SecurityHeaderInterceptor implements HandlerInterceptor { private static final String INNER_SIGN_HEADER = "X-Internal-Gateway-Token"; // 运行时由部署环境注入;示例不包含密钥或默认值。 private final String expectedSecret = System.getenv("INTERNAL_GATEWAY_TOKEN"); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String requestUri = request.getRequestURI(); // 内部接口路径前缀强制校验网关签名 if (requestUri.startsWith("/internal/")) { String token = request.getHeader(INNER_SIGN_HEADER); if (token == null || !token.equals(expectedSecret)) { response.setStatus(HttpServletResponse.SC_FORBIDDEN); response.getWriter().write("Forbidden: Internal endpoint requires valid gateway token."); return false; } } return true; } }3. 隐患入口三:Nacos 配置中心明文存储与密码泄漏
在微服务体系中,所有的数据库密码、MQ 凭据与第三方 Secret 都统一托管在 Nacos 或 Apollo 配置中心。
两个常见的安全隐患:
- Nacos 未开启身份认证:默认安装的 Nacos 社区版未开启
nacos.core.auth.enabled=true,攻击者访问 8848 端口直接读取甚至篡改全量 DataID 配置文件。 - 数据库密码明文存储:配置文件中直接写数据库密码。
解决方案:优先使用受管密钥服务
密文放在配置文件中不等于完成密钥治理:解密口令仍需要安全分发、轮换和审计。生产环境优先使用云 KMS、Vault 或平台提供的 Secret 注入;下例只展示应用如何引用由部署环境提供的值:
spring: datasource: url: ${DB_URL} username: ${DB_USERNAME} # 使用 ENC(...) 保护明文密码 password: ${DB_PASSWORD_CIPHERTEXT}4. 模拟渗透演练与避坑清单
为了验证安全防护措施是否生效,可以进行以下模拟演练:
- 场景模拟设定:模拟内部员工网络暴露环境,使用 curl 工具绕过 API 网关,直接访问后端微服务 Pod IP 的 8080 端口与 8090 管理端口:
- 使用经批准的测试环境地址验证管理端点是否被隔离;不要在文中暴露实际网络地址。
- 在经批准的测试环境中,验证伪造 Host 头或路径是否会绕过网关;不要在文章中记录真实域名、地址或接口。
- 预期防御效果:
- Actuator 8080 端口返回
404 Not Found。 - 内部接口由于缺失网关秘钥 Header,拦截器拦截并返回
403 Forbidden。
- Actuator 8080 端口返回
针对 Spring Cloud 微服务全家桶的安全检查 Checklist:
- 全面禁用生产环境无用端点:显式关闭 Actuator 的敏感泄露接口。
- 网关与微服务双向鉴权:建立 Gateway 到 Microservice 的私密 Header 校验机制,防范内网 IP 直连绕过攻击。
- Nacos 开启认证并管理凭据:核对当前版本的认证配置与初始账号状态,禁用默认或弱凭据;敏感配置交由受管密钥服务或部署环境注入。
