SAML (Security Assertion Markup Language) 是一种基于 XML 的开放标准,用于在安全域之间交换身份验证和授权数据。它主要用于实现单一登录 (Single Sign-On, SSO) 功能,允许用户在一个身份验证服务器(Identity Provider, IdP)上登录一次后,即可访问多个服务提供商 (Service Provider, SP) 上的应用程序,而无需在每个应用程序上重新输入凭据。SAML 2.0 是当前最广泛使用的版本。

核心思想:将用户身份验证的职责从各个服务提供商剥离到专门的身份提供商,通过可信的 XML 断言 (Assertion) 在两者之间传递身份和授权信息。


一、为什么需要 SAML?

随着企业和组织越来越多地使用 SaaS (Software as a Service) 应用和跨域资源,用户常常需要在多个独立的应用程序中重复登录,这不仅降低了用户体验,也增加了密码管理的负担和安全风险。传统的做法是每个应用程序维护自己的用户数据库和认证机制。

SAML 旨在解决这些问题,它提供了一种联邦身份 (Federated Identity) 的解决方案,其核心优势包括:

  • 单一登录 (SSO):显著提升用户体验,只需登录一次即可访问所有集成 SAML 的应用。
  • 企业级的安全性:通过数字签名和加密保证身份断言的完整性和机密性。
  • 降低成本:减少了每个服务提供商维护用户账户和认证逻辑的负担。
  • 标准化:作为开放标准,促进了不同厂商和平台之间的互操作性。
  • 增强审计能力:集中化的认证日志更容易进行安全审计。

二、SAML 核心概念

理解 SAML 协议需要掌握几个关键角色和概念:

2.1 主体 (Principal)

通常指用户,是请求访问受保护资源的一方。

2.2 身份提供商 (Identity Provider, IdP)

负责对用户进行身份验证,并向服务提供商发出包含用户身份和属性的 SAML 断言。IdP 是权威的身份验证源。
示例:企业内部的认证服务器、Okta、Azure AD、Auth0 等。

2.3 服务提供商 (Service Provider, SP)

提供受保护资源或服务的应用程序。它依赖 IdP 进行用户身份验证,并根据 IdP 发送的 SAML 断言来决定是否授权用户访问。
示例:Salesforce、Microsoft 365、Dropbox、自定义 Web 应用等。

2.4 SAML 断言 (SAML Assertion)

由 IdP 生成并发送给 SP 的 XML 文档。它包含关于主体(用户)的声明,是 SAML 协议的核心。断言是 IdP 身份验证结果和授权信息的可信表达。
断言通常由 IdP 进行数字签名,以确保其完整性和真实性。

2.5 元数据 (Metadata)

描述 IdP 和 SP 配置信息的 XML 文档,包括它们的实体 ID、端点 URL、支持的绑定、公钥证书等。元数据使得 IdP 和 SP 能够相互发现并安全地进行配置,减少手动配置的错误并增强安全性。

三、SAML 2.0 框架组成

SAML 2.0 协议由以下主要组件构成:

3.1 SAML 断言 (SAML Assertions)

SAML 断言是包含身份验证和授权信息的 XML 声明。主要有三种类型:

  1. 认证断言 (Authentication Assertion)

    • 声明主体(用户)何时以何种方式通过 IdP 进行了身份验证。
    • 示例:User 'alice' authenticated at 2026-01-14T06:20:00Z using Password method.
  2. 属性断言 (Attribute Assertion)

    • 声明关于主体的特定属性信息,例如用户的姓名、电子邮件地址、角色、部门等。
    • 这些属性信息通常用于 SP 的用户画像建立和权限管理。
    • 示例:User 'alice' has attribute 'email' with value 'alice@example.com'.
  3. 授权决策断言 (Authorization Decision Assertion)

    • 声明 IdP 对某个主体访问特定资源是否授权的决定。
    • 虽然 SAML 本身不直接执行授权,但它可以传达授权系统的决策。
    • 示例:User 'alice' is permitted to access 'document_service'.

3.2 SAML 协议 (SAML Protocols)

SAML 协议定义了如何封装 SAML 断言和请求/响应消息,以及如何在 IdP 和 SP 之间进行通信。常见的协议包括:

  • 身份验证请求协议 (Authentication Request Protocol):SP 向 IdP 请求主体身份验证。
  • 断言消费者服务协议 (Assertion Consumer Service Protocol):IdP 将身份验证断言发送给 SP。
  • 注销协议 (Logout Protocol):用于实现单点注销 (Single Log-Out, SLO)。

3.3 SAML 绑定 (SAML Bindings)

SAML 绑定定义了 SAML 协议消息如何通过底层的通信或消息传递协议(如 HTTP、SOAP)进行传输。它们描述了消息的编码、如何将其添加到协议层的载荷中,以及如何通过传输机制发送。

常用的绑定包括:

  • HTTP Redirect Binding
    • SAML 消息以 URL 查询字符串参数的形式传输,通过 HTTP GET 重定向实现。
    • 适用于传输较小的 SAML 请求,因为 URL 长度有限制。
    • 消息通常经过 Base64 和 URL 编码,可能还会被压缩。
  • HTTP POST Binding
    • SAML 消息嵌入到 HTML 表单的隐藏字段中,通过 HTTP POST 请求提交。
    • 适用于传输较大的 SAML 消息(如断言),不受 URL 长度限制。
    • 消息通常经过 Base64 编码。
  • HTTP Artifact Binding
    • 不直接传输 SAML 消息,而是传输一个引用 (Artifact)
    • 接收方(SP/IdP)收到 Artifact 后,会通过后台通信(通常是基于 SOAP over HTTP 的 SOAP Binding)向发送方请求实际的 SAML 消息内容。
    • 这种方式避免了敏感信息直接通过浏览器传输,增加了安全性,但增加了通信的复杂性。

3.4 SAML 配置集 (SAML Profiles)

SAML 配置集(或称剖面)结合特定的 SAML 断言、协议和绑定,定义了用于解决特定用例的完整通信流。它们规定了消息的顺序、格式和底层传输机制。

最常见和最重要的配置集是:

  • Web 浏览器 SSO 配置集 (Web Browser SSO Profile)
    • 用于实现基于 Web 浏览器的单点登录。
    • 可以分为 SP-Initiated (由 SP 发起) 和 IdP-Initiated (由 IdP 发起) 两种流。
    • 通常使用 HTTP Redirect Binding 传输 SAML AuthN Request,使用 HTTP POST 或 HTTP Artifact Binding 传输 SAML Response。

四、SAML 2.0 Web 浏览器 SSO 流程详解 (SP-Initiated)

SP-Initiated SSO 是最常见的 SAML SSO 流程,由用户尝试访问 SP 上的受保护资源发起。

流程细节解析:

  1. 用户请求:用户通过浏览器访问 SP 上的受保护资源。
  2. SP 发起认证请求:SP 检测到用户未登录,生成一个 SAML 身份验证请求 (AuthNRequest)。这个请求包含 SP 的实体 ID、期望的 IdP、以及当 IdP 完成认证后回调的 SP 端点 (AssertionConsumerServiceURL)。SP 使用 IdP 的 SSO 端点 URL 和 HTTP Redirect Binding 将用户重定向到 IdP。
  3. IdP 接收请求并认证用户:IdP 接收 AuthNRequest,验证其签名(如果SP对请求进行了签名)。如果用户尚未登录 IdP,IdP 会显示登录界面。用户成功登录后,IdP 创建一个用户会话。
  4. IdP 生成 SAML 响应:IdP 生成一个 SAML Response,其中包含一个或多个 SAML Assertion。断言中包含用户的身份信息(如用户名)、认证时间、认证方法和可选的用户属性。这个 SAML Response 会用 IdP 的私钥进行数字签名,以证明其来源和未被篡改。
  5. IdP 返回 SAML 响应:IdP 使用 SP 的 Assertion Consumer Service (ACS) URL 和 HTTP POST BindingSAML Response 发送给用户浏览器(通过自动提交一个 HTML 表单)。
  6. SP 接收并验证响应:浏览器将 SAML Response POST 到 SP 的 ACS 端点。SP 接收到响应后,会执行以下关键步骤:
    • 验证数字签名:SP 使用 IdP 的公钥验证 SAML Response 的数字签名,确保它确实由 IdP 发出且未被篡改。
    • 验证时间戳:检查断言是否在有效期内(NotBeforeNotOnOrAfter)。
    • 验证接收者:确认断言是发给当前 SP 的。
    • 安全存储:保护收到的断言,防止重放攻击。
    • 提取用户信息:从断言中提取用户的身份信息和属性。
  7. SP 建立会话:SP 根据断言中的用户信息在自身系统中建立用户会话(如,设置一个 Session Cookie),并将用户重定向到最初请求的资源。

五、SAML 2.0 消息实例 (简要 XML 结构)

SAML 消息是复杂的 XML 文档。以下是一个简化后的 SAML 断言 (Assertion) 结构示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?xml version="1.0" encoding="UTF-8"?>
<saml2:Assertion
xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"
ID="_a75ad07a-9a96-4e58-86d1-1234567890ab"
IssueInstant="2026-01-14T06:30:00.000Z"
Version="2.0">
<saml2:Issuer>https://idp.example.com/sso</saml2:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<!-- 数字签名:包含签名信息、证书等,用于验证断言的真实性 -->
</ds:Signature>
<saml2:Subject>
<saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">alice</saml2:NameID>
<saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml2:SubjectConfirmationData NotOnOrAfter="2026-01-14T06:35:00.000Z"
Recipient="https://sp.example.com/saml/acs"/>
</saml2:SubjectConfirmation>
</saml2:Subject>
<saml2:Conditions NotBefore="2026-01-14T06:29:00.000Z" NotOnOrAfter="2026-01-14T06:35:00.000Z">
<saml2:AudienceRestriction>
<saml2:Audience>https://sp.example.com</saml2:Audience>
</saml2:AudienceRestriction>
</saml2:Conditions>
<saml2:AuthnStatement AuthnInstant="2026-01-14T06:29:50.000Z"
SessionIndex="_session123"
SessionNotOnOrAfter="2026-01-14T07:30:00.000Z">
<saml2:AuthnContext>
<saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
</saml2:AuthnContext>
</saml2:AuthnStatement>
<saml2:AttributeStatement>
<saml2:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xs:type="xs:string">alice@example.com</saml2:AttributeValue>
</saml2:Attribute>
<saml2:Attribute Name="role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xs:type="xs:string">admin</saml2:AttributeValue>
</saml2:Attribute>
</saml2:AttributeStatement>
</saml2:Assertion>

关键元素:

  • Issuer:断言的签发者(通常是 IdP 的实体 ID)。
  • Signature:用于 IdP 对整个断言进行数字签名,确保完整性和真实性。
  • Subject:关于断言主体(用户)的信息,包含 NameID (用户标识) 和 SubjectConfirmation (如何确认主体身份的方式)。
  • Conditions:断言的有效性条件,如 NotBefore (生效时间)、NotOnOrAfter (失效时间) 和 AudienceRestriction (指定接收方)。
  • AuthnStatement:认证断言,声明用户认证的时间和方式。
  • AttributeStatement:属性断言,包含用户属性信息。

Python 库提示:
在 Python 中,可以使用 python-samlpysaml2 等库来简化 SAML 消息的生成、解析和签名验证。这些库抽象了底层的 XML 处理和加密细节。

六、SAML 的优缺点

6.1 优点:

  1. 实现 SSO:核心优势,提升用户体验和管理效率。
  2. 安全性高:通过数字签名、加密和时间戳等机制,保证消息的完整性、机密性和抗重放性。
  3. 开放标准:互操作性强,被广泛支持,避免厂商锁定。
  4. 联邦身份管理:适用于跨企业、跨组织的身份认证。
  5. 不共享用户凭据:SP 不会直接接触到用户的密码,密码只在 IdP 处验证,提高了安全性。

6.2 缺点:

  1. 复杂性高:SAML 协议基于 XML,消息结构复杂,实现和配置都相对繁琐,容易出错。
  2. XML 臃肿:XML 消息通常比 JSON 消息更大,可能增加网络传输开销。
  3. 调试困难:由于消息编码、签名、重定向等环节较多,调试和问题排查相对复杂。
  4. 不直接支持移动应用:SAML 设计之初主要针对 Web 浏览器环境。虽然可以通过一些变通方法间接应用于移动端,但不如 OAuth 2.0/OIDC 原生支持好。
  5. 缺乏原生 REST API 支持:对于现代基于 RESTful API 的微服务架构,其 XML 消息和重定向机制不如 OAuth 2.0/OIDC 这种基于令牌的协议更“自然”。
  6. 需元数据交换:IdP 和 SP 之间需要交换和配置元数据,这本身也是一个配置开销。

七、安全性考虑

尽管 SAML 提供了强大的安全机制,但实施时仍需关注潜在的安全风险:

  1. 数字签名验证:SP 必须严格验证所有传入 SAML Response 的数字签名,确保其由可信的 IdP 签发且未被篡改。
  2. IdP 公钥管理:SP 必须安全地获取和存储 IdP 的公钥证书,并定期更新。
  3. 时间戳验证:检查断言的 NotBeforeNotOnOrAfter 时间戳,防止过期或未生效的断言被使用。
  4. 受众限制 (Audience Restriction):验证断言是否确实是发给当前 SP 的,防止跨 SP 滥用断言。
  5. 防止重放攻击 (Replay Attack)
    • SAML ResponseAssertion 必须有唯一的 ID。
    • SP 应该跟踪并存储最近接收到的断言 ID,拒绝任何重复的 ID。
    • 结合时间戳验证,确保只处理最新生成且未超期的断言。
  6. 加密:对包含敏感属性的 SAML 断言进行加密(使用 SP 的公钥加密),以保护其机密性。
  7. 传输层安全 (TLS/HTTPS):所有 SAML 消息传输都必须通过 HTTPS 进行,以防止中间人攻击和数据窃听。
  8. XML 安全漏洞:注意防范 XXE (XML External Entity) 攻击等 XML 特有的漏洞。
  9. 单点注销 (SLO) 的复杂性:SLO 比 SSO 更难以稳健地实现,因为涉及跨域会话的同步销毁,实际应用中可能并不总是可靠。

八、总结

SAML 2.0 作为一个成熟的企业级联邦身份标准,在 Web 应用程序的单一登录领域占据了主导地位。它通过定义 IdP 和 SP 之间的标准化通信协议和 XML 消息格式,解决了跨域身份验证和授权的挑战。其基于数字签名和加密的安全机制提供了强大的保障。

尽管 SAML 在配置和实现的复杂性方面存在一定的挑战,且在移动应用和 RESTful API 领域的适用性不如 OAuth 2.0/OIDC,但其在传统企业应用和 SaaS 集成场景中的价值依然不可替代。对于构建企业级 SSO 解决方案,深入理解 SAML 2.0 及其安全最佳实践至关重要。