SSO单点登录分享

背景

随着互联网的发展,各种网页应用或是app应用如雨后春笋般不断涌现。在这些应用中少不了的一项功能必定是用户登录,通常只有在用户登录【一般使用帐号密码作为登录凭证】才能看到不一样的内容或者是属于你的专属内容。随着你注册过的应用不断增长,你的帐户密码凭证也在不断增长。除非你学过特殊的记忆法,不然在脑海中维护这个庞大的密码库显然是一件不可能完成的事。而所有的应用都使用同一个凭证又显得过于愚蠢,为撞库提供了极大的便利性。即便是再安全的密码也有时效性,当你不小心泄漏了这个通用密码时,那将是灾难性的事故。三个月更换一次密码是一件很酷的事,但是当你需要更新上百次时那么这件事就显得不那么酷了。同时,又由于人的固有怠惰性,登录每个应用都要输入一次账号密码也会觉得痛不欲生。尽管已经有session和cookie这一对好兄弟记住了你的登录态。但是时效性决定了这不会是个一劳永逸的办法。在上述的背景下,SSO(单点登录)应运而生。【互联网的最终优美应该是用户通过点点点就能获得他们所想要的东西,当使用键盘时一切就都显得那么丑陋。】

什么是SSO

简单来说,即有一个应用承载了帐号密码登录凭证功能。举个例子,现在的企鹅的全家桶基本能通过微信授权登录,而一般的应用也会提供微信登录这个功能。微信即承载了认证中心的功能,只要你微信是处于登录状态,登录其他的应用都轻而易举。

该怎么实现SSO

在谈SSO之前我们首先要明确一个概念:认证(Authentication)和 授权(Authorization)。认证即让系统知道你是谁,授权即让系统知道你能做什么。这两者是相辅相成的,严谨地来说,只有你被统一的认证中心认证并授权获取你的某些信息,你才能访问访问第三方系统中的内容。明白了认证和授权后,我们可以简单地假设下SSO整体流程。

  1. 首先用户想要登录一个新的系统A,用户过于懒不想输入凭证进行登录,于是点击了SSO登录。
  2. 点击后跳转了系统S(认证中心),系统S已经登录或者需要我们重新登录(系统S帮我们记住了凭证信息,只要一点即可填充,再点击登录按钮),系统S去告知系统A这个用户是合法的并能授予哪些权限。
  3. 当系统A收到系统S的告知后,用户便能正常访问系统A了。
    尽管这三步看起来异常简单,然而如何控制这三步的安全性是一个难题。接下来谈谈两者常用的实现方式Oauth2和SAML2.

Oauth2

Oauth2占据了SSO的半壁江山,说到SSO必然伴随着Oauth2,但确切地来说Oauth2是一种授权协议,但是在使用Oauth2的过程中不可避免地混杂了认证因素。为什么会这样说,我们先来看看Oauth2的步骤:

  1. 用户访问系统A(客户端),重定向到系统S(授权服务商),系统S询问用户是否进行授权【这一步需要用户已经在系统S登录】
  2. 用户同意给予系统A授权。
  3. 系统A使用上一步获得的授权,向系统S申请令牌。
  4. 系统S对系统A的请求进行认证以后,确认无误,同意发放令牌。
  5. 系统A使用令牌,向资源系统R(资源服务商)申请获取资源。
  6. 系统R确认令牌无误,同意向系统A开放资源。
+--------+                               +---------------+
|        |--(A)- Authorization Request ->|   Resource    |
|        |                               |     Owner     |
|        |<-(B)-- Authorization Grant ---|               |
|        |                               +---------------+
|        |
|        |                               +---------------+
|        |--(C)-- Authorization Grant -->| Authorization |
| Client |                               |     Server    |
|        |<-(D)----- Access Token -------|               |
|        |                               +---------------+
|        |
|        |                               +---------------+
|        |--(E)----- Access Token ------>|    Resource   |
|        |                               |     Server    |
|        |<-(F)--- Protected Resource ---|               |
+--------+                               +---------------+

对于授权码模式来说,客户端去向授权服务申请授权码,授权服务返回一个授权码,客户端再用这个授权码去向授权服务申请一个访问令牌。整体流程如下:

     +----------+
     | Resource |
     |   Owner  |
     |          |
     +----------+
          ^
          |
         (B)
     +----|-----+          Client Identifier      +---------------+
     |         -+----(A)-- & Redirection URI ---->|               |
     |  User-   |                                 | Authorization |
     |  Agent  -+----(B)-- User authenticates --->|     Server    |
     |          |                                 |               |
     |         -+----(C)-- Authorization Code ---<|               |
     +-|----|---+                                 +---------------+
       |    |                                         ^      v
      (A)  (C)                                        |      |
       |    |                                         |      |
       ^    v                                         |      |
     +---------+                                      |      |
     |         |>---(D)-- Authorization Code ---------'      |
     |  Client |          & Redirection URI                  |
     |         |                                             |
     |         |<---(E)----- Access Token -------------------'
     +---------+       (w/ Optional Refresh Token)

我们可以整个流程简而言之就是系统A去向系统S请求令牌,系统A用这个令牌去向系统R请求资源。对于系统A来说,它并不知道是哪一个用户授权了这个令牌,甚至它不知道这个用户是否真实存在。这也是Oauth2最大的问题,很多时候用户并不存在,这对系统A来说这是好事【因为它不必确定用户是否真实存在】,但对系统S来说十分糟糕,对于不存在的用户来说根本无法进行认证。另外在步骤1中授权的前提是用户已经在系统S中认证过,但是这个认证是系统S本身的认证,并不能等同于Oauth2的认证。也有一些协议在Oauth2的基础上进行了认证,譬如OpenId Connect。
Oauth2并没有规定Access Token该如何设计,也没有设计一个规范去约束资源服务商如何去验证access token。使用access token去获取用户属性来完成OAuth2去认证用户这个过程看起来诱人,却也存在严重的问题。在授权服务商经过身份认证的过程中这个access token是有效的,但是当我们经过一段时间后用refresh token去向授权服务商请求access token时我们是不需要再次进行授权的也就不需要进行用户认证。这个有效的access token去获取用户属性就会出现严重的问题,可能这个用户被禁用或者已经不存在。
接下来我们再看看access token和refresh token干了什么,

  +--------+                                           +---------------+
  |        |--(A)------- Authorization Grant --------->|               |
  |        |                                           |               |
  |        |<-(B)----------- Access Token -------------|               |
  |        |               & Refresh Token             |               |
  |        |                                           |               |
  |        |                            +----------+   |               |
  |        |--(C)---- Access Token ---->|          |   |               |
  |        |                            |          |   |               |
  |        |<-(D)- Protected Resource --| Resource |   | Authorization |
  | Client |                            |  Server  |   |     Server    |
  |        |--(E)---- Access Token ---->|          |   |               |
  |        |                            |          |   |               |
  |        |<-(F)- Invalid Token Error -|          |   |               |
  |        |                            +----------+   |               |
  |        |                                           |               |
  |        |--(G)----------- Refresh Token ----------->|               |
  |        |                                           |               |
  |        |<-(H)----------- Access Token -------------|               |
  +--------+           & Optional Refresh Token        +---------------+

从流程中我们可以看到,refresh token对于资源服务商来说是不可知的。假设access token在资源服务商这里已经是不安全了或者是过期了,客户端就可以通过refresh token的形式向授权服务商申请一个新的access token【这种方式不需要用户再次对其授权,因为用户之前已经授权过了】。客户端拿到新的可用的access token再去向资源服务商请求资源。对于大公司来说,Oauth2这种轻量级的协议满足不了对于安全性的严谨定义。对于小公司来说,授权服务商和资源服务商在大部分情况下是等同的。refresh token就失去了它的作用,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值