type
status
date
slug
summary
tags
category
icon
password

什么是SAML

SAML全称安全断言标记语言(Security Assertion Markup Language),它是一种基于XML的开放标准,用于表示和交换用户属性、身份和认证信息。在对用户进行一次身份验证的基础上,将验证结果传递给多个应用程序,达到单点登录SSO的效果。
SAML是一种身份验证,并不包括用户授权认证的过程。身份验证用于确认用户的身份,类似于身份证,用来展示一个人的信息并证明“我是我“。而授权则是确认用户的权限,表明用户他能进行哪些操作

SAML是如何运行的

📎
三个参与方:
1. 用户 2. 身份提供方(IDP):是一种存储和管理用户数字身份的服务,IDP 可以通过验证账号密码等方式来检查用户身份,并提供用户身份列表供其他服务提供商(如 SSO)检查。 3. 服务提供方(SP):用户使用的相关服务,如B站、淘宝、飞书都是服务的提供方.
notion image
如上图所示,处理流程:
  1. 用户访问SP提供的服务页面,并进行SSO登录
  1. SP通过重定向跳转到IDP服务
  1. IDP识别到用户未登录则会跳转到登录页面,用户进行登录操作
  1. IDP登录成功后,返回SAML Response断言信息
  1. SP获取到SAML断言后根据结果提供对应的访问策略 SAML断言包含了SP所需要的所有信息,包括断言的ID来源、签发时间、有效时间、SP的地址等信息。
在SP重定向到IDP时会发送一个AuthNRequest消息
可以看出,该XML里面存储了几个关键信息:
  • ID="ONELOGIN_809707f0030a5d00620c9d9df97f627afe9dcc24"
    • 唯一ID
    • notion image
  • IssueInstant="2014-07-16T23:52:45Z"
    • 签发时间
  • Destination="<http://idp.example.com/SSOService.php>"
    • IDP地址
  • ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
    • 使用的协议
  • AssertionConsumerServiceURL="<http://sp.example.com/demo1/index.php?acs>"
    • 回调SP的接口地址
  • <saml:Issuer><http://sp.example.com/demo1/metadata.php></saml:Issuer>
    • 发起方
IDP登录成功后就会返回响应的SAML Response
返回结果中也有一些关键信息:
  • InResponseTo="ONELOGIN_4fee3b046395c4e751011e97f8900b5273d56685"
    • 对应于SP发起请求的ID
  • <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
    • 响应结果
  • <saml:AuthnStatement AuthnInstant="2014-07-17T01:01:48Z" SessionNotOnOrAfter="2024-07-17T09:01:48Z" SessionIndex="_be9967abd904ddcae3c0eb4189adbe3f71e327cf93">
    • 会话有效期
  • <saml:Attribute Name="uid" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
    • 返回结果相关属性参数
整个流程图如下图所示:
notion image
上述用户以SP为入口是一种场景,还有一种场景是用户先登录IDP,然后在选择指定的SP应用,IDP再跳转到SP应用中去。
notion image
该场景处理流程:
  • 用户访问IDP,进行登录;登录完成选择SP访问
  • IDP重定向到SP,生成SAML Response,并调用SP 的ACS url 将结果返回
  • SP验证SAML Response,并授权访问

代码实践

我是用go进行代码编辑和测试,使用https://samltest.id 这个网站进行测试,用到的三方库是 go get github.com/crewjam/saml
服务启动后,首先访问 http://localhost:8001/saml/metadata 获取xml元数据,上传到https://samltest.id/upload.php ,再访问 http://localhost:8001/auth 就会跳转到samltest的登录页面。
notion image
选择页面下方任意一个提供的账号密码进行登录,登录成功后就会显示如下信息
notion image
通过Wireshake抓包,监听lo网卡,端口设置tcp.port == 8001,我们可以得到
notion image
可以看出,首先访问/auth地址时,我们启动的服务(SP)将请求重定向到了https://samltest.id/idp/profile/SAML2/Redirect/SSO, 然后我们输入账号密码验证成功后,IDP就回调了/saml/acs接口,发送了saml断言信息,我们服务根据信息再经过重定向到我们最开始访问的/auth接口,最终返回具体的信息。整个测试过程,我们启动的服务是作为服务提供方,https://samltest.id, 则是作为身份提供方,对身份进行验证,并返回验证结果和身份的相关属性。

对接Okta

为了更好的模拟真实的对接场景,我将通过与okta进行SSO集成对接进行演示。使用ruby进行测试。首先登录okta后台,选择Application --> Create App Integration创建应用,然后再选择SAML2.0;再输入应用名。
notion image
  1. Single sign on URL 填写的是SP的回调接口Audience URI 填写SP的metadata地址
  1. Attribute Statements可填写一些属性,如用户名,ID等信息。
notion image
应用创建完成后,再将该应用授权给指定用户,在Directory --> People --> Add person 创建用户,然后点击该用户,选择Assign Application选择授权的应用。
notion image
notion image
所有的步骤操作完成后,我们获取okta的saml 登录证书地址,选择Application,点击创建的应用,再选择Sign on,就可看到okta提供的证书,为了拿到其地址我们点击View Idp metadata,他就会回跳转到新的页面,页面地址就是我们需要的IDP metadata url,将其替换代码的相应位置即可。
notion image
接下来测试流程就和上面经过抓包,使用我们对相关请求使用工具(https://www.scottbrady91.com/tools/saml-parser) 进行解码处理得到:
这是在重定向时携带的SAML Request的信息,包含ID、发起时间、目标IDP地址,回调SP的地址和发起者。
这是okta登录成功后回调请求/saml/acs接口时发送的SAML Response,包含目的SP回调地址,该消息对应的请求ID,响应状态,用户属性等。

总结

SAML协议制定于2005年,所以在制定的时候主要针对Web应用程序,并没有考虑后来的App,在兼容性上不是那么好。特别是在2012后OAuth2的出现,越来越多的人在单点登录上的第一选择更多是OAuth2(后面也会写相关文章来介绍OAuth2)。但SAML通过HTTP Redirect 和Post 协议来传递身份验证消息,并使用Form格式进行数据提交,整个协议交互比较简单,方便使用集成,在今天还是有它的一席之地的。

参考文档

DNS隧道攻击和防护为什么压力测试QPS总是上不去
  • Twikoo