写点什么

【揭秘 SAML 协议 — Java 安全认证框架的核心基石】 从初识到精通,带你领略 Saml 协议的奥秘,告别 SSO 的迷茫与困惑

作者:洛神灬殇
  • 2024-02-03
    江苏
  • 本文字数:4395 字

    阅读完需:约 14 分钟

【揭秘SAML协议 — Java安全认证框架的核心基石】 从初识到精通,带你领略Saml协议的奥秘,告别SSO的迷茫与困惑

注意:特此声明:本文首发在掘金:https://juejin.cn/post/7330680498686214180,未经允许,请勿进行侵权私自转载

SAML 协议简介

SAML(Security Assertion Markup Language)是由 OASIS 制定的基于 XML 的开放标准。它用于在身份提供者(IdP)和服务提供者(SP)之间交换身份验证和授权数据,从而支持跨域单点登录,提高身份认证和授权管理的安全性和效率。

SAML 作用和效果

SAML 在 Web-based 单点登录(SSO)中发挥着至关重要的作用。借助 SAML,用户只需进行一次身份验证,即可访问多个不同的应用程序或服务,而无需重复输入凭证。这种集中化的身份验证和授权机制不仅提高了用户体验,还增强了安全性。现在,让我们进一步探讨 SAML 的工作原理。

为什么要使用 SAML


首先,使用 SAML 可以显著提升用户体验。通过实现单点登录(SSO),用户只需进行一次身份验证,即可访问多个不同的系统服务。这意味着用户无需分别记忆多个系统的用户名和密码,只需记住一个即可。


其次,使用 SAML 还有助于提高系统的安全性。在 SAML 框架下,我们只需向身份提供者(IdP)提供用户名和密码进行身份验证,而无需将这些信息存储在每个资源服务器上。这样,认证信息的安全性得到了保障,因为它们仅在 IdP 中存储了一份。


最后,通过集中存储和管理用户的认证信息,SAML 还有助于降低系统的复杂性。

SAML 角色组成

在 SAML 协议中,有三个核心角色:主体(principal)、身份提供者(Identity Provider,简称 IdP)和服务提供者(Service Provider,简称 SP)。



  • 主体(principal)通常代表人类用户/浏览器终端

  • IdP 主要负责进行身份认证,并将用户的认证信息和授权信息传递给 SP。

  • SP 的主要职责是验证用户的认证信息,并授权用户访问指定的资源信息。


通过这样的角色划分和分工,SAML 协议能够有效地支持跨域单点登录,提高身份认证和授权管理的安全性和效率。

SAML 是怎么工作

通过一个详细的流程图来深入了解 SAML 如何实现 SSO 认证。请注意,根据请求方式的不同(重定向和 POST),SAML 的认证流程略有差异。


首先,我们来看看通过重定向方式进行的 SAML SSO 认证流程:



  1. 用户尝试访问受保护的资源(例如某个应用或服务)。

  2. 服务提供者(SP)识别出用户未经过身份验证,并重定向用户到身份提供者(IdP)进行身份验证。

  3. 用户在 IdP 的网站上输入用户名和密码进行身份验证。

  4. IdP 验证用户信息,并将包含身份验证和授权信息的 SAML 响应发送回 SP。

  5. SP 验证 SAML 响应,并授予用户访问受保护资源的权限。


接下来,我们来看看通过 POST 方式进行的 SAML SSO 认证流程:



  1. 用户尝试访问受保护的资源。

  2. SP 识别出用户未经过身份验证,并生成包含重定向 URL 的 SAML 请求的 HTML 表单。

  3. SP 将 HTML 表单发送给用户,要求用户填写用户名和密码。

  4. 用户在表单中输入用户名和密码,并提交给 IdP 进行身份验证。

  5. IdP 验证用户信息,并将包含身份验证和授权信息的 SAML 响应发送回 SP。

  6. SP 验证 SAML 响应,并授予用户访问受保护资源的权限。


通过以上两种方式,我们可以看到 SAML 通过在 IdP 和 SP 之间交换身份验证和授权信息,实现了 SSO 认证,从而简化了用户的登录过程,提高了系统的安全性。

核心协议详解

上面中用户可以理解为 web 浏览器,我们看一下如果用户想请求 SP 服务提供者的资源的时候,SAML 协议是怎么处理的。


  1. 用户通过用户请求 SP 服务提供者,比如:https://www.xx.xx.com,在 SP 接收到请求后,它会进行必要的安全检查。如果发现已经存在一个有效的安全上下文,SP 直接进入最后一步,继续处理请求。

  2. 在上一步中,如果 SP 没有找到有效的安全上下文,它会生成对应的 SAML 请求,并通过重定向用户代理(User Agent)将用户转至 IdP,以确保用户能够通过身份验证并获得访问受保护资源的权限。

  3. 通过与 IdP 的交互,用户可以完成身份验证,并获得必要的授权信息,以便于之后访问受保护的资源。


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

RelayState 标志

在 SAML 协议中,RelayState 是一个重要的组成部分,主要用于防范 CSRF 攻击。RelayState 是 SP(服务提供者)维护的一个状态信息。简单来说,它就像是一个“凭证约定”,帮助 SP 追踪用户的请求,并确保请求是从合法的来源发送的。


跨站请求伪造(Cross-Site Request Forgery,简称 CSRF) 是一种常见的网络攻击手段。攻击者诱导受害者在不知情的情况下执行恶意请求,通常是为了在受害者的身份下进行非法操作。

RelayState 在防范 CSRF 攻击中的具体操作


  • 请求的追踪:当用户从一个应用或服务(例如,SP)发送请求到另一个应用或服务(例如,IdP)进行身份验证时,SP 会将一个特定的 RelayState 参数附加到请求中。这个 RelayState 参数包含了一个唯一的标识符或令牌,用于标识这个特定的请求。

  • 验证返回的请求:当 IdP 完成身份验证后,它会将用户重定向回 SP,并附带原始的 RelayState 参数。SP 接收到请求后,会检查返回的 RelayState 参数是否与原始请求中的匹配。

  • 如果匹配,说明请求是合法的;

  • 如果不匹配,则很可能是 CSRF 攻击。

SAMLRequest 请求体

在 SAML 协议中,samlp:AuthnRequest元素是用于身份验证请求的 XML 元素,它包含了发起身份验证请求所需的必要信息,SAMLRequest 是经过 Base64 编码的<samlp:AuthnRequest>,以下是一个 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="id1234567890"  Version="2.0"  IssueInstant="2024-02-02T18:17:54Z"  Destination="https://sp.example.com/SAML2/SSO/POST"  ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST">  <saml:Issuer>https://idp.example.com/SAML2</saml:Issuer>  <samlp:NameIDPolicy    Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"    AllowCreate="true"/>  <samlp:RequestedAuthnContext Comparison="exact">    <saml:AuthnContextClassRef>      urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport    </saml:AuthnContextClassRef>  </samlp:RequestedAuthnContext></samlp:AuthnRequest>
复制代码

元素解释

  • <saml:Issuer>:标识发出请求的身份提供商(IdP)的实体 ID。在这里,它是https://idp.example.com/SAML2

  • <samlp:NameIDPolicy>:定义了 NameID 策略,用于指定如何创建和管理 NameID(用于标识用户的唯一名称)。在这里,Format属性指定了 NameID 的格式为“transient”,表示该 NameID 是临时的且仅在当前会话中有效。AllowCreate属性设置为“true”,表示允许创建新的 NameID。

  • <samlp:RequestedAuthnContext>:指定了所请求的身份验证上下文,用于定义所需的身份验证方法或条件。在这里,Comparison属性设置为“exact”,表示请求的身份验证上下文必须与提供的身份验证上下文完全匹配。

  • <saml:AuthnContextClassRef>:元素指定了身份验证类别的引用,这里是“PasswordProtectedTransport”,表示使用受密码保护的传输来进行身份验证。


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

用户重定向 IDP 数据信息

在接收到前一步的请求后,SP 将 RelayState 和 SAMLRequest 进行整合,并通过 HTTP 302 重定向将用户(浏览器)引导至 IdP 的 SSO 服务器,请求的消息体如下:


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


IdP 在接收到 AuthnRequest 请求后,会进行严格的安全验证。如果验证通过,IdP 会展示其登录界面,允许用户进行身份验证。用户可以输入用户名密码进行登录。

登录成功之后

在完成安全验证后,IdP 将返回一个 XHTML 表单,该表单内嵌了经过 Base64 编码的 SAMLResponse 信息。SAMLResponse 中包含了用户的相关数据,且同样以 samlp:Response 的形式进行编码。


<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="2023-01-05T09:22:05Z"    Destination="https://sp.xxxx.com/SAML2/SSO/POST">    <saml:Issuer>https://idp.xxxx.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="2023-01-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.xxxx.com/SAML2/SSO/POST"            NotOnOrAfter="2023-09-05T09:27:05Z"/>        </saml:SubjectConfirmation>      </saml:Subject>      <saml:Conditions        NotBefore="2023-09-05T09:17:05Z"        NotOnOrAfter="2023-09-05T09:27:05Z">        <saml:AudienceRestriction>          <saml:Audience>https://sp.xxx.com/SAML2</saml:Audience>        </saml:AudienceRestriction>      </saml:Conditions>      <saml:AuthnStatement        AuthnInstant="2023-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>
复制代码


我们观察到 samlp:Response 中包含 saml:Assertion 信息,并且针对于相关的交互流程进行梳理



  1. 当用户代理收到 XHTML 表单后,它会将该表单提交给 SP。

  2. 在 SP 中,断言消费者服务会处理该请求,创建相应的安全上下文,并重新定向用户代理至目标资源页面。

  3. 随后,用户代理再次请求 SP 资源,由于安全上下文已经建立,SP 可以直接返回所需资源,而无需再次与 IdP 进行认证。


注意,上述信息交换完全由前端浏览器完成,SP 与 IdP 之间不存在直接通信


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

发布于: 刚刚阅读数: 3
用户头像

洛神灬殇

关注

🏆 InfoQ写作平台-签约作者 🏆 2020-03-25 加入

👑 后端技术架构师,前优酷资深工程师 📕 个人著作《深入浅出Java虚拟机—JVM原理与实战》 💻 10年开发经验,参与过多个大型互联网项目,定期分享技术干货和项目经验

评论

发布
暂无评论
【揭秘SAML协议 — Java安全认证框架的核心基石】 从初识到精通,带你领略Saml协议的奥秘,告别SSO的迷茫与困惑_SAML2.0_洛神灬殇_InfoQ写作社区