跳到内容

SAML 安全备忘录

简介

安全断言标记语言(SAML)是一种用于交换授权和身份验证信息的开放标准。带有重定向/POST 绑定的 Web 浏览器 SAML/SSO 配置文件是最常见的 SSO 实现之一。本备忘录将主要关注该配置文件。

验证消息机密性和完整性

TLS 1.2 是在传输层保证消息机密性和完整性最常见的解决方案。有关更多信息,请参阅 SAML 安全(第 4.2.1 节)。此步骤将有助于应对以下攻击:

  • 窃听 7.1.1.1
  • 窃取用户认证信息 7.1.1.2
  • 窃取持有者令牌 7.1.1.3
  • 消息删除 7.1.1.6
  • 消息修改 7.1.1.7
  • 中间人攻击 7.1.1.8

使用认证密钥进行数字签名的消息是保证消息完整性和认证最常见的解决方案。有关更多信息,请参阅 SAML 安全(第 4.3 节)。此步骤将有助于应对以下攻击:

  • 中间人攻击 6.4.2
  • 伪造断言 6.4.3
  • 消息修改 7.1.1.7

断言可以通过 XMLEnc 加密,以防止在传输后敏感属性的泄露。有关更多信息,请参阅 SAML 安全(第 4.2.2 节)。此步骤将有助于应对以下攻击:

  • 窃取用户认证信息 7.1.1.2

验证协议使用

这是安全漏洞的常见区域——参见 Google SSO 漏洞以获取实际示例。他们的 SSO 配置文件容易受到来自恶意 SP(服务提供商)的中间人攻击。

SSO Web 浏览器配置文件最容易受到来自可信合作伙伴的攻击。这个特定的安全漏洞之所以暴露,是因为 SAML 响应不包含安全消息交换所需的所有数据元素。遵循 SAML 配置文件中 AuthnRequest (4.1.4.1) 和 Response (4.1.4.2) 的使用要求将有助于应对此攻击。

AVANTSSAR 团队建议以下数据元素应为必需:

  • AuthnRequest(ID, SP): 一个 AuthnRequest 必须包含一个 ID 和一个 SP。其中 ID 是唯一标识请求的字符串,SP 标识发起请求的 服务提供商。此外,请求 ID 属性必须在响应中返回(InResponseTo="<requestId>")。InResponseTo 有助于保证来自可信 IdP 的响应的真实性。这是导致 Google SSO 易受攻击的缺失属性之一。
  • Response(ID, SP, IdP, {AA} K -1/IdP): 一个 Response 必须包含所有这些元素。其中 ID 是唯一标识响应的字符串。SP 标识响应的接收方。IdP 标识授权响应的身份提供商。{AA} K -1/IdP 是使用 IdP 私钥进行数字签名的断言。
  • AuthAssert(ID, C, IdP, SP): 响应中必须存在一个身份验证断言。它必须包含一个 ID、一个客户端 (C)、一个身份提供商 (IdP) 和一个服务提供商 (SP) 标识符。

验证签名

2012 年,《攻破 SAML:想成为谁就成为谁》一文描述了由于 XML 签名包装攻击导致的 SAML 实现中的漏洞。

以下建议是作为回应提出的(安全 SAML 验证以防止 XML 签名包装攻击):

  • 在使用 XML 文档进行任何安全相关目的之前,始终对其执行模式验证。
    • 始终使用本地的、可信的模式副本进行验证。
    • 绝不允许从第三方位置自动下载模式。
    • 如果可能,检查模式并执行模式强化,以禁用可能的通配符类型或宽松处理语句。
  • 安全地验证数字签名
    • 如果您只期望一个签名密钥,请使用 StaticKeySelector。直接从身份提供商获取密钥,将其存储在本地文件中,并忽略文档中的任何 KeyInfo 元素。
    • 如果您期望多个签名密钥,请使用 X509KeySelector(JKS 变体)。直接从身份提供商获取这些密钥,将其存储在本地 JKS 中,并忽略文档中的任何 KeyInfo 元素。
    • 如果您期望异构签名文档(来自许多身份提供商的许多证书,多级验证路径),请实现基于 PKIX 和可信根证书的完整信任建立模型。
  • 避免签名包装攻击。
    • 在未事先验证的情况下,切勿使用 getElementsByTagName 选择 XML 文档中与安全相关的元素。
    • 除非使用强化的模式进行验证,否则始终使用绝对 XPath 表达式来选择元素。

验证协议处理规则

这又是安全漏洞的另一个常见领域,仅仅是因为需要断言的步骤数量庞大。

处理 SAML 响应是一个开销很大的操作,但所有步骤都必须经过验证。

  • 验证 AuthnRequest 处理规则。有关所有 AuthnRequest 处理规则,请参阅 SAML Core (3.4.1.4)。此步骤将有助于应对以下攻击:
    • 中间人攻击 (6.4.2)
  • 验证响应处理规则。有关所有响应处理规则,请参阅 SAML Profiles (4.1.4.3)。此步骤将有助于应对以下攻击:
    • 断言窃取 (6.4.1)
    • 中间人攻击 (6.4.2)
    • 伪造断言 (6.4.3)
    • 浏览器状态暴露 (6.4.4)

验证绑定实现

  • 对于 HTTP 重定向绑定,请参阅 SAML 绑定 (3.4)。要查看编码示例,您可能需要参考 Google 参考实现中的 RequestUtil.java。
  • 对于 HTTP POST 绑定,请参阅 SAML 绑定 (3.5)。缓存的考虑也非常重要。如果 SAML 协议消息被缓存,它随后可能被用作断言窃取 (6.4.1) 或重放 (6.4.5) 攻击。

验证安全对策

重新审视 SAML 安全文档中存在的每个安全威胁,并确认您已针对您特定实现中可能存在的威胁应用了适当的对策。

应考虑的其他对策包括:

  • 在适当情况下优先使用 IP 过滤。例如,如果 Google 为每个可信合作伙伴提供独立的端点并为每个端点设置 IP 过滤器,这项对策就可以防止 Google 最初的安全漏洞。此步骤将有助于应对以下攻击:
    • 断言窃取 (6.4.1)
    • 中间人攻击 (6.4.2)
  • SAML 响应的生命周期宜短。此步骤将有助于应对以下攻击:
    • 断言窃取 (6.4.1)
    • 浏览器状态暴露 (6.4.4)
  • SAML 响应宜采用 OneTimeUse(一次性使用)。此步骤将有助于应对以下攻击:
    • 浏览器状态暴露 (6.4.4)
    • 重放 (6.4.5)

需要架构图吗?SAML 技术概述包含最完整的图表。对于带有重定向/POST 绑定的 Web 浏览器 SSO 配置文件,请参阅第 4.1.3 节。事实上,在所有 SAML 文档中,技术概述从高层次角度来看是最有价值的。

未经请求的响应(即 IdP 发起的 SSO)对服务提供商的考虑

由于缺乏 CSRF 保护,未经请求的响应在设计上本身就安全性较低。然而,由于 SAML 1.1 的向后兼容性特性,它仍然得到许多支持。一般的安全建议是不支持此类身份验证,但如果必须启用,以下步骤(除了上面提到的一切)应该有助于您保护此流程:

  • 遵循 SAML Profiles(第 4.1.5 节)中提到的验证过程。此步骤将有助于应对以下攻击:
    • 重放 (6.1.2)
    • 消息插入 (6.1.3)
  • 如果 RelayState 参数的约定是 URL,请确保该 URL 已验证并明确列在允许列表中。此步骤将有助于应对以下攻击:
  • 在响应或断言级别实施适当的重放检测。这将有助于应对以下攻击:
    • 重放 (6.1.2)

身份提供商和服务提供商的考虑

SAML 协议很少是首选的攻击媒介,但拥有备忘录以确保其稳健性仍然很重要。各种端点更容易成为目标,因此 SAML 令牌如何生成以及如何被消费在实践中都非常重要。

身份提供商 (IdP) 的考虑

  • 验证 X.509 证书的算法兼容性、加密强度、导出限制
  • 验证生成 SAML 令牌的强认证选项
  • IDP 验证(哪个 IDP 铸造了令牌)
  • 尽可能使用/信任根 CA
  • 与公共互联网时间源同步
  • 定义身份验证的保证级别
  • 对于身份断言,优先使用非对称标识符而非个人身份信息(例如社会安全号等)
  • 签署每个单独的断言或整个响应元素

服务提供商 (SP) 的考虑

  • 验证用户会话状态
  • 在使用 SAML 令牌时设置授权上下文的粒度级别(您是否使用组、角色、属性)
  • 确保每个断言或整个响应元素都已签名
  • 验证签名
  • 验证是否由授权的 IDP 签名
  • 根据 CRL/OCSP 验证 IDP 证书的过期和吊销状态
  • 验证 NotBefore 和 NotOnorAfter
  • 验证 Recipient 属性
  • 定义 SAML 注销的标准
  • 仅通过安全传输交换断言
  • 定义会话管理的标准
  • 尽可能验证从 SAML 票据断言中获取的用户身份。

输入验证

SAML 是一种安全协议并不意味着输入验证就不再需要了。

  • 确保所有 SAML 提供商/消费者都进行适当的输入验证

密码学

依赖密码算法的解决方案需要跟进密码分析的最新进展。