SpringBoot + Kubernetes云原生微服务实践 - (5) 安全框架设计和实践

安全框架设计和实践

网站安全认证架构演进 ~ 单块阶段

  1. Auth V1 (2006)
    • 认证(authentication)和授权(authorization)
    • 登录阶段
      • 传统安全认证基于服务器端session+浏览器端cookie机制实现,会话session是用户登录状态的一种存储机制,http协议本身是无状态的,一个http请求和下一个http请求是相互独立,互不关联
      • 客户端发起Post请求/user/login;通过校验后,服务器向内存中session添加一条记录:sessionId + 对应用户登录信息;然后服务器将登录成功信息返回给客户端浏览器,同时把sessionId以cookie的形式放入客户端浏览器中
      • session也可存储其他信息,如购物车,相当于用户数据的临时存储
    • 访问阶段
      • 后续访问阶段,浏览器会在后续请求中将sessionId以cookie的方式发送到web服务器端
      • 在操作必须登录的操作时,服务器在收到带sessionId的请求后,在内存session表中进行比对,若能匹配上,说明用户已经登录认证过,服务器就可以提取用户信息,进行下一步操作;也可以在进行操作前,服务器可以根据用户信息中的角色等信息进行鉴权,判断用户是否有足够权限进行操作
    • Spring Security以SecurityFilter机制来实现安全认证
  2. Auth V1.1 ~ Sticky Session
    • V1版本无法应对服务器集群方式部署的情况,导致session只存在于一台服务器
    • 解决方案:Sticky Session,即将用户会话粘在一台服务器上
      • 通过负载均衡器截获并记录sessionId和后台服务器ip的关联信息,请求转发时通过关联信息来做转发,保证在一个会话期间,用户请求和某台服务器绑定
      • Nginx配置即可
    • 问题:
      • 若需要对服务器正常升级部署,或服务器本身出现延迟或宕机,一拨用户的会话会瞬间消失,用户体验差;又如一部分固定用户反馈网站反应慢
      • 扩展性差。粘性会话在负载均衡器和web服务器都保存了状态,整体是有状态架构,随着流量增长,会话对web服务器和负载均衡器都带来了压力,有状态系统难以扩展
    • 解决方案:
      • 会话同步复制:会话数据在服务器间同步复制;服务器间需要复杂的状态同步协议,整体性能和扩展性变低
      • 无状态会话:会话数据不存在服务器,而存在客户端浏览器;通过请求响应循环捎带来传递用户数据;有泄漏风险,需要加密;浏览器对cookie大小有限制,一般4kb,不能存放较大的会话数据
      • 集中状态会话
  3. Auth V1.5 ~ Centralized Session (2009)
    • 将会话数据在专门的服务器上集中存储
    • 会话数据存取性能要求较高,业界一般采用redis这种高性能缓存来做
    • 负载均衡器和服务器都可以水平扩展,集中会话服务器扩展也有很多方案,如redis集群;所以这种方案是高性能、易扩展的解决方案

网站安全认证架构演进 ~ 微服务阶段

  1. 微服务认证授权挑战 (2014)
    • 后台应用和服务众多,如何对每一个服务应用进行认证鉴权,传统的用户名+密码存入session是否还适用
    • 前端用户体验众多,如果每一个都做登录认证,成本高且难以扩展,并且为了避免重复登录,需要考虑SSO的新需求
  2. Auth V3.0 ~ Auth Service + Token
    • 基于session的安全机制无法完全套用在微服务上,但可以借鉴其思想
    • a. 将登录认证抽取为一个独立的服务,跟独立的用户数据库,该服务统一承担登录认证、会话管理、令牌办法、校验等职责
    • b. 引入令牌token作为服务调用认证鉴权的主要凭证;透明令牌是指令牌是一个无意义的随机字符串,但是令牌是跟Auth service上一次登录会话是相关联的,后续可以通过令牌到Auth service上去校验用户的会话是否有效,也可以进一步查询用户详情信息,所以令牌也称为引用令牌:本身不包含数据,但是是auth service上一次用户会话的引用标识符;引用令牌和sessionId类似
    • 基于Auth Service + Token的登录认证流程:
      • 用户输入用户名、密码,发起post请求;Auth Service收到请求,从数据库中校验用户信息;校验成功后,则建立用户会话session;session可存数据库或redis中
      • Auth Service返回token到客户端,客户端临时存储token(存于cookie或local storage中)
      • 客户端向后台微服务发起请求,会带上本地存储的token(通过cookie或http header)
      • 微服务接收到带token的请求,通过向auth service发送一个validate token的请求,去校验token的合法性;如果通过校验,则执行后续操作(取出token和校验token动作一般放在web或服务框架的过滤器中实现)
      • 在执行后续操作的过程中,微服务若需要额外的用户详情数据,可用token去auth service上获取用户详情信息;根据需要,微服务可通过用户详情中的角色等信息做进一步的鉴权动作
      • 调用完成,响应返回到客户端
    • 可认为是集中式会话的一个改造版,专门针对微服务场景进行了扩展
    • 问题:每个微服务都要实现认证鉴权的逻辑,给微服务的开发方引入了复杂性,无法聚焦于业务逻辑的开发;认证鉴权分布在各个微服务中,会带来不规范容易出错的问题,另一方面有潜在的安全风险,如令牌被开发人员忽略,或使用了老版本有漏洞的认证库
  3. Auth V3.5 ~ Token + Gateway
    • 网关截获令牌,并集中到auth service上进行令牌的校验;适合于大部分安全比较严格的微服务应用场景,如电商等
    • 网关可从auth service获取与token对应的userInfo
    • 引入网关统一认证鉴权之后,对于基于浏览器的客户端应用,如web、spa应用,登录成功之后,auth service可以把token以cookie的形式,种到客户端浏览器中,并种在同一个根域下面,这样的话,如果在同一个浏览器中访问myStore的不同子域的应用和服务时,网关可以统一处理登录态校验,相当于实现了单点登录,提升用户体验
    • 一方面解决了微服务安全认证带来的新挑战,另一方面为myStore网站解耦拆分和微服务化,间接为公司后续业务进一步成长奠定了坚实基础
    • 问题:网站流量大时,为auth service的访问压力比较大,可能成为性能和扩展性的瓶颈,需要严格监控,做好HA,并按序扩容,投入成本高;对于安全不是特别敏感的微服务场景,集中状态校验太笨重,可采用基于JWT的无状态安全校验
  4. Auth 3.6 ~ JWT + Gateway
    • auth service颁发的不是透明令牌,而是JWT令牌(Json Web Token);JWT令牌自包含数据和签名,因此,网关可以自己解析和检验JWT令牌,而不需去auth service上集中校验,校验完成后网关可取出用户标识信息,并通过请求向后传递
    • 可认为是无状态session扩展出来的,根据微服务进行了扩展
    • 简化了架构,降低了auth service的压力,是一种高性能、可扩展的架构,适用于大部分安全要求不太敏感的微服务场景

JWT令牌原理

  1. JWT结构
    • Json Web Token,是RFC7519定义的一个开放标准,一种紧凑和自包含的Json对象格式,通过它可以在多个系统间安全的传输信息;信息经过数字签名,可以校验,而且是可信任的
    • JWT可通过HMAC算法+secret这种方式进行签名,也可基于RSA或ESDSA+公钥密钥对的方式进行签名
    • 主要用于认证授权的信息交换场景
    • 结构为:Header . Payload . Signature,三个部分都是通过base64编码的,可通过jwt.io站点进行反编码查看
  2. JWT示例

  3. JWT类比签名支票

两种JWT流程

  1. HMAC流程
    • auth server和resource server提前协商好用于签名的secret,并严格保密
    • 用户登录请求;auth server通过HMAC算法加secret进行签名,将签名的JWT发送回客户端,客户端收到后进行本地存储;客户端向resource server发出api调用请求,请求中会带上JWT;resource server收到请求后,采用同样的secret对JWT进行解签和校验,通过后执行后续操作,可进一步根据JWT中的数据进行鉴权;最后再进行相应
  2. RSA流程
    • auth server使用private key生成签名,resource server使用public key进行解签
    • 总体上比HMAC更加安全,因只用auth server保存私钥,泄漏概率比secret小
    • 流程与HMAC方式类似
  3. JWT优劣

    优势 不足
    紧凑轻量,尤其适合无线传输场景
    资源服务器自校验,对authServer压力小
    简化authServer实现,无需对用户会话状态进行维护和管理
    无状态和吊销无法两全
    传输开销
  4. 透明令牌 vs JWT
    • 类似Java中的引用传递和值传递

Staffjoy安全认证架构和SSO

  1. Staffjoy Auth
    • 登录认证由WWW服务承担,令牌集中校验由Faraday网关承担
    • 登录认证阶段
      • 用户通过浏览器向WWW服务的login端口post一个登录请求;WWW服务接收到请求,通过调用Account API校验email和password是否正确,校验通过后,WWW服务生成JWT,并以cookie的形式将JWT种到用户浏览器中(种在根域上,即staffjoy.com);登录成功后,WWW服务还会向浏览器发送302跳转指令,将用户跳转到默认应用(管理员跳转App应用,普通雇员跳转MyAccount应用)或原先视图访问的应用
    • 后续访问阶段
      • App单页应用通过浏览器向应用发送http请求,假设请求Account API的数据,英文整个staffjoy的所有应用服务都会在同一个根域下,所以请求会自动带上cookie+JWT,faraday网关会截获请求,提取出cookie中的JWT,并进行校验,同时提取其中的用户信息userId,然后将请求向后台account API进行转发,并在http header中带上userId;account API接收到带有userId的http请求,相当于已经知道这个请求是哪个用户发起的,可以进行进一步的操作,将操作结果通过faraday网关简介返回到用户的浏览器
  2. Staffjoy JWT Cookie
    • 通过浏览器查看cookie,value值即JWT

安全认证代码剖析 ~ 用户认证

  1. 引入JWT生成和检验库
    • com.auth0.java-jwt 3.6.0
  2. xyz.staffjoy.common.crypto.Sign
    • 生成算法:generateSessionToken()
    • 校验算法:verifySessionToken()
  3. xyz.staffjoy.common.auth.Sessions
    • 登录login种cookie:loginUser()
    • cookie中取出JWT:getToken()
    • 登出logout清空cookie:logout()
  4. xyz.staffjoy.faraday.core.interceptor.AuthRequestInterceptor
    • JWT校验 + 取出用户会话数据:getSession()
    • 网关传递认证授权信息:setAuthHeader()
  5. xyz.staffjoy.common.auth.AuthContext 认证上下文助手类
    • 获取userId:getUserId()
    • 获取授权信息:getAuthz()
  6. xyz.staffjoy.common.auth.FeignRequestHeaderInterceptor
    • Feign客户端传递用户认证信息

安全认证代码剖析 ~ 服务间调用鉴权

鉴权:如Account API上的createAccount操作,只允许通过WWW服务或Company服务间接操作,不允许通过Faraday网关直接操作

  1. 服务间调用授权截获器 xyz.staffjoy.common.auth.AuthorizeInterceptor
    • preHandle() 检查是否有授权标注
    • xyz.staffjoy.common.auth.Authorize 授权标注类
  2. 控制器调用鉴权,如xyz.staffjoy.account.controller.AccountController中
    • 如createAccount接口用@Authorize标注,定义http头有哪些权限才可调用该操作
    • 用户角色鉴权:validateAuthenticatedUser()
    • 环境鉴权:validateEnv()
  3. API Client传递服务调用方,如xyz.staffjoy.account.client.AccountClient中
    • 方法参数添加@RequestHeader(AuthConstant.AUTHORIZATION_HEADER) String authz
  4. 授权Header定义:xyz.staffjoy.common.auth.AuthConstant

  5. Staffjoy Auth Enforcement
    • 用户认证在架构上可强制执行,这点是由网关来保证,因为所有用户操作必须通过网关来转发;网关调内部服务,需要强制加合法的授权header;保证外部访问内部是安全的
    • 服务间调用的鉴权,是一种内部约定机制,即,服务提供方和消费方相互约定一些授权的header,这个机制无法完全强制执行,可能被绕开,比方说某个内部调用方冒充使用别人的授权header,这个问题在内部服务之间的调用是ok的,因为假定内部服务在同一个授信域里,都会遵循这个规范

用户角色鉴权扩展

  1. 参考权限模型
    • 实体:App、User、Role、Group
    • 关联关系:
      • UserRegistration:App <-> User
      • GroupMember:User <-> Group
  2. Auth 3.7 ~ JWT + RBAC(Role Based Access Control)
    • 增加RBAC service:Auth Service在生成令牌时,可通过RBAC service获取用户关联了哪些app、关联了哪些group、有哪些role,这些信息可以填充到JWT数据结构中,一起返回给用户端
    • 之后客户端访问后台服务时,网关做初步解析和校验,将相关信息继续往后传递
    • 后面的服务拿到该用户的信息,可以做进一步的鉴权动作

猜你喜欢

转载自www.cnblogs.com/wnzhong/p/12133625.html