写点什么

SAML 和 OAuth2 这两种 SSO 协议的区别

发布于: 2021 年 01 月 02 日

简介

SSO 是单点登录的简称,常用的 SSO 的协议有两种,分别是 SAML 和 OAuth2。本文将会介绍两种协议的不同之处,从而让读者对这两种协议有更加深入的理解。


SAML

SAML 的全称是 Security Assertion Markup Language, 是由 OASIS 制定的一套基于 XML 格式的开放标准,用在身份提供者(IdP)和服务提供者 (SP)之间交换身份验证和授权数据。


SAML 的一个非常重要的应用就是基于 Web 的单点登录(SSO)。


在 SAML 协议中定义了三个角色,分别是 principal:代表主体通常表示人类用户。identity provider (IdP)身份提供者和 service provider (SP)服务提供者。


IdP 的作用就是进行身份认证,并且将用户的认证信息和授权信息传递给服务提供者。


SP 的作用就是进行用户认证信息的验证,并且授权用户访问指定的资源信息。


接下来,我们通过一个用 SAML 进行 SSO 认证的流程图,来分析一下 SAML 是怎么工作的。



上图中 User Agent 就是 web 浏览器,我们看一下如果用户想请求 Service Provider 的资源的时候,SAML 协议是怎么处理的。


  1. 用户通过 User Agent 请求 Service Provider,比如:

http://sp.flydean.com/myresource
复制代码

SP 将会对该资源进行相应的安全检查,如果发现已经有一个有效的安全上下文的话,SP 将会跳过 2-7 步,直接进入第 8 步。


  1. 如果在第一步的时候,SP 并没有找到相应的有效安全上下文的话,则会生成对应的 SAMLRequest,并将 User Agent 重定向到 IdP:

302 RedirectLocation: https://idp.flydean.com/SAML2/SSO/Redirect?SAMLRequest=request&RelayState=token
复制代码

RelayState 是 SP 维护的一个状态信息,主要用来防止 CSRF 攻击。


其中这个 SAMLRequest 是用 Base64 编码的,下面是一个 samlp:AuthnRequest 的例子:


  <samlp:AuthnRequest    xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"    ID="aaf23196-1773-2113-474a-fe114412ab72"    Version="2.0"    IssueInstant="2020-09-05T09:21:59Z"    AssertionConsumerServiceIndex="0"    AttributeConsumingServiceIndex="0">    <saml:Issuer>https://sp.flydean.com/SAML2</saml:Issuer>    <samlp:NameIDPolicy      AllowCreate="true"      Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"/>  </samlp:AuthnRequest>
复制代码

为了安全起见,SAMLRequest 还可以使用 SP 提供的签名 key 来进行签名。


  1. User agent 将会发送一个 get 请求到 IdP 的 SSO server :

GET /SAML2/SSO/Redirect?SAMLRequest=request&RelayState=token HTTP/1.1Host: idp.flydean.com
复制代码

IdP 收到这个 AuthnRequest 请求之后,将会进行安全验证,如果是合法的 AuthnRequest,那么将会展示登录界面。


  1. 用户可以输入用户名密码进行登录。登录成功之后,IdP 将会返回一个 XHTML form:

  <form method="post" action="https://sp.flydean.com/SAML2/SSO/POST" ...>    <input type="hidden" name="SAMLResponse" value="response" />    <input type="hidden" name="RelayState" value="token" />    ...    <input type="submit" value="Submit" />  </form>
复制代码

这个 form 中包含了 SAMLResponse 信息,SAMLResponse 中包含了用户相关的信息。


同样的 SAMLResponse 也是使用 Base64 进行编码过的。


<samlp:Response    xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"    ID="identifier_2"    InResponseTo="identifier_1"    Version="2.0"    IssueInstant="2020-09-05T09:22:05Z"    Destination="https://sp.flydean.com/SAML2/SSO/POST">    <saml:Issuer>https://idp.flydean.com/SAML2</saml:Issuer>    <samlp:Status>      <samlp:StatusCode        Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>    </samlp:Status>    <saml:Assertion      xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"      ID="identifier_3"      Version="2.0"      IssueInstant="2020-09-05T09:22:05Z">      <saml:Issuer>https://idp.flydean.com/SAML2</saml:Issuer>      <!-- a POSTed assertion MUST be signed -->      <ds:Signature        xmlns:ds="http://www.w3.org/2000/09/xmldsig#">...</ds:Signature>      <saml:Subject>        <saml:NameID          Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">          3f7b3dcf-1674-4ecd-92c8-1544f346baf8        </saml:NameID>        <saml:SubjectConfirmation          Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">          <saml:SubjectConfirmationData            InResponseTo="identifier_1"            Recipient="https://sp.flydean.com/SAML2/SSO/POST"            NotOnOrAfter="2020-09-05T09:27:05Z"/>        </saml:SubjectConfirmation>      </saml:Subject>      <saml:Conditions        NotBefore="2020-09-05T09:17:05Z"        NotOnOrAfter="2020-09-05T09:27:05Z">        <saml:AudienceRestriction>          <saml:Audience>https://sp.flydean.com/SAML2</saml:Audience>        </saml:AudienceRestriction>      </saml:Conditions>      <saml:AuthnStatement        AuthnInstant="2020-09-05T09:22:00Z"        SessionIndex="identifier_3">        <saml:AuthnContext>          <saml:AuthnContextClassRef>            urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport         </saml:AuthnContextClassRef>        </saml:AuthnContext>      </saml:AuthnStatement>    </saml:Assertion>  </samlp:Response>
复制代码

我们可以看到 samlp:Response 中包含有 saml:Assertion 信息。


  1. user agent 收到 XHTML form 之后将会提交该 form 给 SP。

  2. SP 中的 assertion consumer service 将会处理这个请求,创建相关的安全上下文,并将 user agent 重定向到要访问的资源页面。

  3. user agent 再次请求 SP 资源。

  4. 因为安全上下文已经创建完毕,SP 可以直接返回相应的资源,不用再次到 IdP 进行认证。

我们可以看到上面的所有的信息交换都是由前端浏览器来完成的,在 SP 和 IdP 之间不存在直接的通信。


这种全部由前端来完成信息交换的方式好处就是协议流非常简单,所有的消息都是简单的 GET 或者 POST 请求。


如果为了提高安全性,也可以使用引用消息。也就是说 IdP 返回的不是直接的 SAML assertion,而是一个 SAML assertion 的引用。SP 收到这个引用之后,可以从后台再去查询真实的 SAML assertion,从而提高了安全性。


SAML 的缺点

SAML 协议是 2005 年制定的,在制定协议的时候基本上是针对于 web 应用程序来说的,但是那时候的 web 应用程序还是比较简单的,更别提对 App 的支持。


SAML 需要通过 HTTP Redect 和 HTTP POST 协议来传递用户信息,并且通常是通过 HTML FORM 的格式来进行数据的提交的。如果应用程序并不是 web 应用,比如说是一个手机 App 应用。


这个手机 APP 应用的启动链接是 my-photos://authenticate , 但是手机 app 可能并不能获取到 Http POST 的 body 内容。他们只能够通过 URL 来进行参数的传递。


这就意味着,在手机 APP 中不能够使用 SAML。


当然,要想工作也可以,不过需要进行一些改造。比如通过第三方应用对 POST 消息进行解析,然后将解析出来的 SAMLRequest 以 URL 参数的形式传递给 APP。


另一种方法就是使用 OAuth2.


OAuth2

因为 Oauth2 是在 2012 年才产生的。所以并没有那么多的使用限制。我们可以在不同的场合中使用 OAuth2。


我们先来看一下 OAuth2 中授权的流程图:



一般来说 OAuth2 中有 4 个角色。


resource owner: 代表的是资源的所有者,可以通过提供用户名密码或者其他方式来进行授权。通常来是一个人。


resource server:代表的是最终需要访问到资源的服务器。比如 github 授权之后获取到的用户信息。


client: 用来替代 resource owner 来进行交互的客户端。


authorization server: 用来进行授权的服务器,可以生成相应的 Access Token。


整个流程是这样的:


Client 向 resource owner 发起一个授权请求,resource owner 输入相应的认证信息,将 authorization grant 返回给 client。


client 再将获取到的 authorization grant 请求授权服务器,并返回 access token。


client 然后就可以拿着这个 access token 去请求 resource server,最后获取到受限资源。


OAuth2 的缺点

OAuth2 并没有指定 Resource Server 怎么和 Authorization Server 进行交互。也没有规定返回用户信息的内容和格式。这些都需要实现方自己去决定。


OAuth2 默认是在 HTTPS 环境下工作的,所以并没有约定信息的加密方式。我们需要自己去实现。


最后,OAuth2 是一个授权协议,而不是认证协议。对于这个问题,其实我们可以考虑使用 OpenID Connect 协议。因为 OpenID Connect 就是基于 OAuth2 实现的,并且添加了认证协议。


OpenID Connect 简称为 OIDC,已成为 Internet 上单点登录和身份管理的通用标准。 它在 OAuth2 上构建了一个身份层,是一个基于 OAuth2 协议的身份认证标准协议。


OAuth2 实际上只做了授权,而 OpenID Connect 在授权的基础上又加上了认证。


OIDC 的优点是:简单的基于 JSON 的身份令牌(JWT),并且完全兼容 OAuth2 协议。


两者的对比

在 SAML 协议中,SAML token 中已经包含了用户身份信息,但是在 OAuth2,在拿到 token 之后,需要额外再做一次对该 token 的校验。


但是另一方面,OAuth2 因为需要再做一次认证,所以可以在 Authorization Server 端对 token 进行无效处理。


CAS 简介

做过 SSO 的应该都听说过 CAS。CAS 的全称是 Central Authentication Service,是一个企业级的开源的 SSO 认证框架。


CAS 内部集成了 CAS1,2,3,SAML1,2,OAuth2,OpenID 和 OpenID Connect 协议,非常的强大。我们会在后面的文章中介绍 CAS 的使用。


本文作者:flydean 程序那些事

本文链接:http://www.flydean.com/saml-vs-oauth2/

本文来源:flydean 的博客

欢迎关注我的公众号:「程序那些事」最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!


发布于: 2021 年 01 月 02 日阅读数: 50
用户头像

关注公众号:程序那些事,更多精彩等着你! 2020.06.07 加入

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧,尽在公众号:程序那些事!

评论

发布
暂无评论
SAML和OAuth2这两种SSO协议的区别