在微服务架构下谈安全,和单体应用完全是两个维度。单体架构下,安全往往聚焦于应用本身,加个Shiro或Spring Security,把登录鉴权做好,基本就解决了一大半问题。但一旦系统拆分成几十个甚至上百个微服务,安全边界就从应用内部转移到了服务与服务之间的网络通信上。你不仅要防外部攻击,还得防内部服务被劫持后横向扩散。SpringCloud生态提供了从网关层到服务间通信再到配置加密的一整套安全体系,但真正搭建起来,坑全在细节里。

网关层是第一道防线,但别把安全全押在网关上

SpringCloud Gateway或者Zuul通常作为统一入口,承担了流量过滤、身份认证和请求转发的角色。很多人习惯在网关层做一个全局的Token校验,校验通过后就把请求转发给下游服务,下游服务直接信任网关传递过来的用户信息。这种做法看似高效,实际上埋下了巨大的安全隐患。一旦网关本身出现漏洞,或者内网中某个服务被攻破,攻击者完全可以伪造请求头,绕过认证直接调用下游接口。

正确的做法是,网关只做粗粒度的准入控制,比如验证Token是否合法、是否过期,然后把解析出的用户身份信息通过加密的方式传递给下游,下游服务仍然需要对这个身份信息进行二次校验。具体实现上,可以用JWT签发一个内部使用的令牌,网关在验证完外部Token后,生成一个短有效期的内部JWT,用对称加密算法签名后通过请求头传给下游。下游服务拿到这个内部JWT后,必须验证签名和有效期,不能直接信任明文传递的userId。

服务间通信必须走零信任,内网不再是安全区

传统观念里,内网服务之间的调用被认为是安全的,防火墙把外部威胁挡住了,内部就可以裸奔。但现实是,大量数据泄露事件恰恰发生在内网横向移动阶段。SpringCloud微服务体系中,服务间调用通常走Feign或者RestTemplate,如果不加任何安全措施,任何一个被攻破的服务都可以随意调用其他服务的接口,甚至直接访问数据库。

零信任架构的核心思想是,永远不信任任何请求来源,每次调用都必须经过认证和授权。在SpringCloud技术栈里,可以结合OAuth2.0的客户端模式来实现服务间认证。每个微服务本身作为一个资源服务器,同时也是一个客户端,调用其他服务时需要携带自己的客户端凭证去授权服务器换取access_token。这个token的scope要精确到具体接口级别,而不是一个通用的服务级别权限。

具体实施时,建议用Spring Security搭配Spring Cloud Security,每个服务都引入资源服务器配置,开启方法级别的权限控制。比如订单服务调用库存服务的扣减接口,库存服务需要验证这个请求携带的token是否具备inventory:write这个scope。这样一来,即使攻击者拿到了某个服务的权限,也只能在它被授权的范围内操作,无法随意扩散。

配置中心的安全往往被严重低估

SpringCloud Config或者Nacos作为配置中心,集中管理了所有服务的配置信息,包括数据库密码、API密钥、第三方服务的凭证等。如果配置中心本身没有做好安全加固,就等于把所有敏感信息集中暴露在了一个地方。很多团队把配置中心部署在内网后,连基本的访问认证都不加,直接裸跑,这是极其危险的。

配置中心至少要开启Basic认证或者集成OAuth2.0,确保只有合法的微服务实例才能拉取配置。同时,敏感配置项绝对不能明文存储。SpringCloud Config支持对配置内容进行对称加密,可以在配置文件中用{cipher}前缀标记加密项,服务启动时自动解密。加密密钥不要写在配置文件里,而是通过环境变量或者启动参数注入,避免密钥和密文放在同一个地方。

另外,配置中心的Git仓库权限也要严格管控。很多团队把配置文件直接放在公开的Git仓库里,或者仓库权限设置过宽,导致配置文件被泄露。配置仓库应该设置为私有,并且开启分支保护,合并代码必须经过Code Review,防止有人恶意篡改配置。

JWT不是银弹,用不好反而成为安全短板

JWT在微服务架构中几乎成了标配,无状态、可扩展、跨语言支持好,这些优点让它在分布式场景下非常受欢迎。但JWT的滥用带来的安全问题同样触目惊心。最常见的问题包括:密钥强度不够被暴力破解、token过期时间设置过长、敏感信息直接放在payload里明文传输、退出登录后token无法主动失效等。

使用JWT时,签名算法至少要选择RS256或者ES256这种非对称算法,避免使用HS256这种对称算法在多个服务间共享密钥。私钥由授权服务独有,公钥分发给各个资源服务器用于验签,这样即使某个资源服务器被攻破,攻击者也拿不到私钥,无法伪造token。

token的有效期要分两个维度设计,access_token的有效期控制在5到15分钟,refresh_token的有效期可以长一些,但需要绑定设备指纹或者客户端标识,刷新时进行二次校验。至于token无法主动失效的问题,可以引入一个黑名单机制,把需要强制下线的用户token存入Redis,资源服务器验签时先查黑名单。虽然这牺牲了一部分无状态的特性,但在安全要求高的场景下是必要的妥协。

API级别的限流和防重放同样属于安全范畴

很多人把限流归到性能优化或者流量治理的范畴,但实际上,限流是防御DDoS攻击和暴力破解的第一道屏障。SpringCloud Gateway内置了RequestRateLimiter过滤器,基于Redis的令牌桶算法可以实现网关层的限流。但仅仅在网关层限流是不够的,关键接口需要在服务层面再做一层限流,防止攻击者绕过网关直接攻击服务。

防重放攻击则容易被忽视。攻击者截获一个合法的请求后,可以在短时间内重复发送这个请求,造成数据错乱或者资源耗尽。解决方案是在请求中加入时间戳和随机数,服务端对时间戳和随机数的组合进行去重校验。可以把这个逻辑封装成一个Spring拦截器,对写操作接口统一开启防重放校验,时间窗口一般设置在60秒以内,过期的请求直接丢弃。

日志安全与审计追踪,出了事得知道发生了什么

安全防护做得再好,也不能保证百分之百不被攻破。一旦发生安全事件,日志就是追溯攻击路径、评估损失范围的唯一依据。微服务架构下,一次请求可能跨越多个服务,日志分散在各个节点上,如果不做集中采集和链路追踪,出了事根本拼凑不出完整的调用链。

ELK或者EFK日志平台是标配,但更重要的是日志内容本身的安全性。敏感信息绝对不能原样输出到日志里,比如用户的手机号、身份证号、密码、token等。可以在日志框架层面配置脱敏规则,用正则匹配敏感字段并自动替换为脱敏后的内容。同时,审计日志要和业务日志分离,记录每一次关键操作的操作人、操作时间、操作内容、IP地址和操作结果,审计日志的存储周期要满足合规要求,并且设置为只追加不可删除。

容器化和Kubernetes环境下的额外安全考量

SpringCloud微服务跑在Kubernetes集群上已经成为主流,这带来了新的安全维度。Pod之间的网络通信默认是互通的,如果不配置NetworkPolicy,一个被攻破的Pod可以扫描整个集群。需要根据服务间的实际调用关系,配置精细化的NetworkPolicy,只放行必要的入站和出站流量。

镜像安全同样关键,基础镜像要定期扫描漏洞并更新,应用镜像构建时不要包含构建工具和源码,用多阶段构建减小镜像体积和攻击面。容器运行时以非root用户运行,挂载的卷设置为只读,敏感配置通过Kubernetes Secret挂载,而不是打包在镜像里。Secret本身也要开启静态加密,防止etcd数据泄露导致Secret被直接读取。

整套安全架构搭建下来,核心思路其实就一条:把安全内化到每一层,而不是寄希望于某一层能挡住所有攻击。网关做粗粒度过滤,服务间做零信任认证,配置和密钥做加密存储,JWT做精细化的生命周期管理,日志做全链路追踪和脱敏,容器环境做网络隔离和最小权限。每一层各司其职,组合起来才能构成一个真正抗揍的防御体系。