微服务架构把单体应用拆成几十个甚至上百个独立服务之后,安全边界从一道大门变成了几十扇小门。很多团队在落地SpringCloud时只关注了服务注册、配置中心和网关的打通,却忽略了全局安全策略的连贯性,导致出现“网关做了鉴权、内部服务裸奔”或者“每个服务各写一套安全逻辑、规则不一致”的问题。全局安全防护的核心不是单个服务的防御,而是从流量入口到服务间通信、再到配置与日志的整条链路统一设计。
先理清SpringCloud安全防护的边界
SpringCloud体系里安全防护至少要覆盖五个层面:接入层网关、服务间调用、配置中心、熔断降级链路、以及审计与日志。很多人把安全等同于网关加一个JWT校验,这远远不够。网关只能挡住外部伪造请求,挡不住内部某个服务被攻破后横向调用其他服务。全局安全策略必须假设“内网也不完全可信”,对服务间调用做身份传递和最小权限控制。
在SpringCloud技术栈中,Spring Cloud Gateway负责接入层路由与过滤,OpenFeign或RestTemplate负责服务间调用,Nacos或Consul负责注册与配置,Sentinel负责流量控制,Spring Security负责认证与授权。全局安全策略要做的就是把这些组件串成一条连续的信任链,而不是各自为政。
网关层安全:不止是校验Token
网关是所有外部流量的第一道关口。在Spring Cloud Gateway中,全局过滤器(GlobalFilter)是实施安全策略的最佳位置。通常需要做几件事:解析并验证JWT或OAuth2令牌、提取用户身份与权限信息、把身份信息写入请求头传给下游服务、对高危URI进行额外限制。
一个常见的错误做法是网关只验证Token签名,不校验Token是否被吊销、不检查用户是否仍存在、不区分访问来源。全局策略中应当明确:网关负责“认证”,也就是确认你是谁;细粒度的“授权”可以下放到各服务,但基础的身份信息必须由网关统一注入。下游服务默认信任网关注入的身份头,因此网关必须剥离客户端传入的任何同名头,防止身份伪造。
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
try {
Claims claims = JwtUtil.parseToken(token.replace("Bearer ", ""));
ServerHttpRequest mutatedRequest = exchange.getRequest().mutate()
.header("X-User-Id", claims.getSubject())
.header("X-User-Roles", String.join(",", claims.get("roles", List.class)))
.build();
return chain.filter(exchange.mutate().request(mutatedRequest).build());
} catch (Exception e) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
}
@Override
public int getOrder() {
return -100;
}
}
网关还需要配置IP黑白名单、请求频率限制、请求体大小限制。Spring Cloud Gateway可以结合Redis做分布式限流,防止单用户或单IP对接口的恶意调用。对于文件上传类接口,必须在网关层限制请求体大小,避免大流量请求直接穿透到后端服务造成内存压力。
服务间调用的身份传递与信任链
内部服务之间的调用不能完全不做鉴权。很多生产环境的安全事故就发生在攻击者通过某个对外服务拿到服务器权限后,直接访问内网其他服务的HTTP接口。全局策略需要规定:所有服务间调用必须携带身份上下文,并且被调用方要验证调用来源。
使用OpenFeign时,可以编写一个RequestInterceptor,从当前请求上下文(通常放在ThreadLocal中)取出用户身份,写入下游请求头。这样用户身份就能在整条调用链上透传。被调用服务通过Spring Security的过滤器读取这些头信息,建立SecurityContext,实现方法级权限控制。
@Configuration
public class FeignConfig {
@Bean
public RequestInterceptor requestInterceptor() {
return requestTemplate -> {
ServletRequestAttributes attributes =
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes != null) {
HttpServletRequest request = attributes.getRequest();
String userId = request.getHeader("X-User-Id");
String roles = request.getHeader("X-User-Roles");
if (userId != null) {
requestTemplate.header("X-User-Id", userId);
}
if (roles != null) {
requestTemplate.header("X-User-Roles", roles);
}
}
};
}
}
更严格的做法是服务间调用使用独立的服务身份凭证,比如给每个服务签发自己的客户端凭证,调用时携带服务令牌。被调用方不仅校验用户身份,还要校验调用方服务是否有权限访问该接口。这种方式能有效防止“某个服务被攻破后横向调用任意接口”的情况。
配置中心的安全加固
Nacos、Consul这类配置中心存储了大量敏感信息:数据库密码、Redis密码、第三方API密钥等。全局安全策略必须包含配置中心的访问控制。首先,配置中心必须开启认证,不能使用默认账号密码。其次,敏感配置项应使用加密存储,例如使用Jasypt对配置文件中的密码进行加密,应用启动时通过环境变量或启动参数传入解密密钥。
# application.yml
spring:
datasource:
password: ENC(3k2lJf9sKd8Qw7RtY6uIoP1aZxCvBnM)
jasypt:
encryptor:
password: ${JASYPT_ENCRYPTOR_PASSWORD}
配置中心还应按命名空间或分组隔离不同环境,生产环境的配置读写权限必须与开发环境严格分离。运维人员对配置的修改操作要记录审计日志,便于追溯。对于数据库密码这类高频变更的敏感配置,建议接入专门的密钥管理服务,配置中心只存引用,不存明文。
熔断与限流的安全兜底
Sentinel或Resilience4j的熔断限流不仅是稳定性手段,也是安全防护的重要一环。当某个服务被攻击导致响应变慢或错误率飙升时,熔断器可以快速切断故障链路,防止雪崩效应。全局策略中应为每个核心接口配置合理的限流阈值和熔断规则。
从安全角度看,限流规则要区分用户维度、IP维度和接口维度。比如登录接口按IP限流,防止暴力破解;下单接口按用户限流,防止脚本刷单;内部管理接口按服务来源限流,只允许特定服务调用。Sentinel支持热点参数限流和来源限流,可以灵活配置这些规则。
熔断策略中需要关注“半开状态”的安全风险。当熔断器进入半开状态时,会放行少量请求探测下游是否恢复。如果攻击者恰好在这个窗口发送恶意请求,可能导致熔断器误判。因此半开状态的探测请求应该使用健康检查接口,而不是直接放行业务请求。
日志与审计的统一规范
全局安全策略的最后一环是日志与审计。微服务架构下,一次用户请求可能经过多个服务,如果每个服务的日志格式不统一、不包含链路追踪ID,出了问题很难还原完整攻击路径。全局策略应规定:每个服务必须记录统一的日志格式,包含TraceId、用户ID、请求路径、响应状态码、耗时等字段。
使用Sleuth或Micrometer Tracing可以自动生成TraceId并在服务间传递。日志中应避免记录敏感信息,如密码、Token、身份证号、银行卡号等。对于登录、权限变更、配置修改、删除操作等关键行为,必须记录独立的审计日志,与普通业务日志分开存储。
审计日志的保留时间也要有明确规定,通常不少于六个月。日志收集系统本身也要做访问控制,只有安全审计人员可以查看完整日志,开发人员只能查看脱敏后的日志或自己负责服务的日志。
全局安全策略的落地顺序
安全策略的落地不能一蹴而就,建议按风险优先级分阶段实施。第一阶段先解决最紧急的问题:网关统一鉴权、剥离客户端伪造头、配置中心改密、敏感配置加密。第二阶段完善服务间身份传递和来源校验,接入统一的熔断限流规则。第三阶段建设完整的日志审计体系,定期进行安全演练和渗透测试。
全局安全策略不是一套代码或一个配置,而是一套持续运行的机制。每个新增服务上线前必须通过安全检查清单:是否接入了统一鉴权、是否遵循了日志规范、是否配置了限流规则、敏感配置是否加密。只有把安全要求嵌入到开发和运维流程中,才能真正实现全局防护。
SpringCloud微服务的安全防护本质上是在分布式环境中重建信任链。网关负责建立初始信任,服务间调用传递信任,配置中心保护信任所需的凭证,熔断限流防止信任被滥用,日志审计记录信任的每一次使用。这五个环节环环相扣,缺一不可。
