单点登录(SSO)

引子

以下内容纯粹是出于对技术的好奇,将网络上搜索的材料结合自己的理解整理而来。由于没有实操经验,纯粹纸上谈兵,如有错误,欢迎斧正。

--------

部分内容于2023/2/2更新

正文

单点登录(Single Sign-on, SSO)是当下WEB应用开发常用的身份认证方法。它使用集中式身份认证模式,允许用户使用相同的身份,在一个系统中通过认证,就可以访问其他相关但独立的系统/服务。每个系统不用自己去设计、实现用户的身份认证。常见的例子如google全家桶,当登录了Gmail之后,再去访问Youtube,就不需要再次手动输入登录信息即可使用服务。

与单点登录易混淆的概念是相同身份登录(Same Sign-on,SSO)。相同身份登录是使用轻量级目录访问协议(Lightweight Directory Access Protocol, LDAP)去访问身份服务器/数据库来进行身份认证。对于每个系统,都需要手动输入用户名、密码。

Web服务器对于已登录的用户进行认证有两种方法:

  • 基于Session cookie

HTTP是无状态的协议。在某些应用场景,需要知道登录的用户的状态,于是就使用了会话(Session)的机制。用户的会话信息存储在应用服务器端,同时会将部分会话信息(如session ID,会话标识)存储在客户端浏览器的cookie中。在后续与服务器的通讯中,浏览器会携带相关信息,服务器通过查询存储的会话信息就能够取得用户的登录状态。

  • 基于令牌(Token)

令牌,通常指JWT(JSON Web Tokens),以JSON格式存储的用户身份及相关信息,在服务器端通过密钥签名后使用base64编码成字符串。因为JWT是经过服务器签名的,客户端只能验证,不能更改。服务器在对用户进行认证后,会将令牌发送给客户端。客户端与服务器进行通信时,会在报文头中以Bearer authentication携带令牌,服务器收到后进行校验。不同于基于cookie的会话管理,令牌是无状态的,服务器本身不存储用户状态。令牌的自包含身份信息属性使得其应用更有弹性,易于扩展。

另一种令牌是由服务器生成的随机字符串,无实际意义。

借用auth0.com的一张图来描述单点登录是如何工作的。Auth0 SSO的核心思想是在认证服务器所在域建立用户的会话信息,所有的认证请求均由认证服务器完成。其实现方法是结合使用Session cookie和令牌。

单点登录(SSO)_第1张图片

图中的Auth Server,就是集中式身份认证服务器,也是实现单点登录的关键。需要使用SSO的应用需要在认证服务器进行注册。用户的身份信息可以存储在认证服务器,也可以在单独的身份服务器,认证服务器通过LDAP去访问获取。集中式身份认证服务器是共同信任的第三方,用户在通过它的认证后,相关系统通过查询认证状态,就能够实现单点登录。

假设domain1.com和domain2.com是两个相关但独立的WEB应用,使用相同的身份认证服务器进行了注册且均激活单点登录功能。

  1. 用户通过浏览器访问domain1.com。假定用户在domain1.com没有登录,即没有活跃状态的会话信息,或者会话信息已过期。
  2. domain1.com服务器检查HTTP请求中没有携带令牌认证报头信息后,将浏览器重定向(redirect)到身份认证服务器(domain3.com)请求对用户进行身份认证,即启动单点登录流程。支持单点登录的协议有多种,比如Kerberos V5,SAML 0,OAuth 0, OIDC等。具体使用哪种协议取决于认证服务器及系统配置。
  3. 认证服务器首先对domain1.com进行认证(确认是已注册的服务),认证通过后再处理domain1.com的用户认证请求。当检查发现不存在该用户的状态信息,如没有会话带过来,或者带过来的会话已过期,则启动登录认证流程。此时,用户浏览器会被重定向到认证服务器的登录页面,要求用户输入账号、密码进行认证。注意:登录页面是由认证服务器提供,用户的输入对于domain1.com是不可见的。
  4. 浏览器在认证服务器所在域(domain3.com)的cookie中写入会话信息,其中不包含敏感信息。根据浏览器的安全策略,只有cookie的所有者才能访问其中的信息。这样做的目的是当后续有重定向到认证服务器的请求时,浏览器会将cookie中的会话信息携带给服务器,作为判断是否已经登录的凭证。信息中包含时间戳,这样可以防止cookie被盗取后的身份伪造,重放攻击。
  5. 认证服务器将生成的访问令牌(Access Token)通过重定向返回给domain1.com。重定向的地址是应用在服务器注册过的,这样可以防止恶意篡改,避免不安全的重定向。
  6. Domain1.com使用接收到的令牌,并使用令牌去获取用户信息(如用户名,邮件地址),结合自己的访问控制策略对用户进行授权。
  7. 浏览器在Domain1.com的cookie保存会话信息。
  8. 用户通过浏览器访问domain2.com。假定用户在domain2.com没有登录,即没有活跃状态的会话信息,或者会话信息已过期。
  9. 浏览器被重定向(redirect)到身份认证服务器(domain3.com)请求对用户进行身份认证。
  10. 认证服务器先完成对domain2.com应用的认证,验证成功后再进行用户认证。由于domain3.com的cookie中存有会话信息,相关信息会被传递给认证服务器。此时,认证服务器根据自己维护的信息查询得到用户登录状态,不会再次启动登录流程。
  11. 认证服务器生成新的访问令牌并通过重定向发送给domain2.com。
  12. Domain2.com验证接收到的令牌,并使用令牌去获取用户信息(如用户名,邮件地址),结合自己的访问控制策略对用户进行授权。
  13. 浏览器在Domain2.com的cookie保存会话信息。

由于cookie中所保存会话标识的敏感性,服务器在设置cookie时会将其标识为“HttpOnly”,这样可以防止该标识被读取后用于其他的脚本中。所有的客户端和服务器端的通信均应启用HTTPS,防止通信被窃听。

对基于浏览器的WEB应用,记录身份认证服务器所在域的会话是实现单点登录的关键。单点登录为用户访问多系统带来便利,这也对集中式的身份认证服务器提出了更高的要求。一旦服务器出现单点故障,将会使所有依赖单点登录功能的系统受到影响。因此,认证服务器需要有适当的冗余措施来保持高可用性。

目前已经有相当数量的单点登录实现方案,可以参考维基的这篇文章《List of single sign-on implementations》。

说明

主体(Subject):是指提出访问请求的实体、动作的发起者,但不一定是动作的执行者。主体可以是某个人,某个进程。

客体(Object):是指可以接受主体访问的被动实体。凡是可以被操作的信息、资源、对象都可以被认为是客体。

认证(Authentication):确定主体是否就是其所声明的身份。

授权(Authorization):确定认证过的主体是否有权访问资源。

在最开始研究单点登录的过程时,关于认证、授权这块困扰了我许久。这涉及到主体、客体的确认问题。比如A访问B时,A是主体,而B是客体。当B响应A的请求再去访问C时,B就成了主体,C是客体。类似,在谈论认证、授权时,应明确哪个主体对客体的认证、授权。

以OAuth 2.0为例,用户的身份信息存储在认证服务器或者单独的身份服务器。OAuth是一个授权协议,为什么它能在单点登录中实现了认证的功能呢?

在domain1.com向认证服务器发起用户认证请求时,认证服务器会首先对domain1.com进行身份认证。认证方法取决于认证服务器的实现。认证通过后,认证服务器会检查用户的登录状态。假如用户之前没有在domain1.com注册过,用户通过认证服务器提供的登录页面登录并通过验证后,会出现一个页面让用户手动确认授予domain1.com获取自己的身份及相关信息的提示,即用户的明示同意。这是一个标准的授权行为,用户(身份信息的所有者)授予客户(domain1.com)读取自己相关信息的权力。

在后续的流程中,认证服务器通过验证domain1.com有权读取用户的信息,将签名的令牌返回给domain1.com,这是告知domain1.com用户已通过身份认证。

当用户登录domain1.com后访问其提供的资源时,这就变成了domain1.com对用户进行授权。这个授权可以由domain1.com根据自己的规则实现。

参考资料

  1. What Is and How Does Single Sign-On Authentication Work?
  2. Single_sign-on
  3. OpenID Connect 1.0
  4. The OAuth 2.0 Authorization Framework
  5. Assertions and Protocols for the OASIS Security Assertion Markup Language (SAML) V2.0
  6. How does SO's new auto-login feature work?

你可能感兴趣的:(Web安全,安全,web安全)