漏洞分析与实践之基于SAML实现的单点登录系统
字数 1963 2025-08-29 08:32:00

基于SAML的单点登录系统漏洞分析与实践教学文档

1. SAML基础概念

1.1 SAML定义

SAML(Security Assertion Markup Language)是一种基于XML的开放标准,用于在各方(特别是身份提供者和服务提供者)之间交换认证和授权数据。

1.2 核心组件

  • 身份提供者(IdP):负责用户身份识别和认证的系统
  • 服务提供者(SP):用户需要访问的应用系统
  • SAML声明(Assertion):包含用户身份和其他属性的XML消息

1.3 工作模式

  1. IdP-Initiated:用户首先访问IdP,认证后获得SAML Response,再访问SP
  2. SP-Initiated:用户首先访问SP,被重定向到IdP认证,再返回SP

2. SAML工作流程

2.1 基本流程

  1. 用户尝试访问SP资源
  2. 用户被重定向到IdP进行认证
  3. 认证成功后,IdP生成SAML Response(包含SAML Assertion)
  4. 用户浏览器将SAML Response转发给SP
  5. SP验证签名并提取用户身份信息
  6. 验证通过后授予访问权限

2.2 SAML Response结构

<SAMLResponse>
  <Issuer>https://idp.com/</Issuer>
  <Assertion ID="_id1234">
    <Subject>
      <NameID>user@user.com</NameID>
    </Subject>
  </Assertion>
  <Signature>
    <SignedInfo>
      <CanonicalizationMethod Algorithm="xml-c14n11"/>
      <Reference URI="#_id1234"/>
    </SignedInfo>
    <SignatureValue>签名数据</SignatureValue>
  </Signature>
</SAMLResponse>

3. 漏洞原理分析

3.1 漏洞成因

  1. XML标准化处理差异

    • 签名验证时使用的CanonicalizationMethod会忽略XML注释
    • 但某些XML解析库在处理NameID时不会忽略注释
  2. 具体表现

    • 原始NameID:user@user.com.evil.com
    • 修改后NameID:user@user.com<!--注释-->.evil.com
    • 签名验证时两者被视为相同(忽略注释)
    • 但某些解析器提取NameID时可能只获取注释前部分

3.2 技术细节

  • 标准化方法http://www.w3.org/2001/10/xml-exc-c14n#
  • 解析不一致
    • 签名验证:忽略注释,test@example<!--注释-->.comtest@example.com
    • 某些解析器:test@example<!--注释-->.comtest@example

4. 漏洞复现实践

4.1 环境准备

  1. 下载受影响版本的OneLogin Python-SAML Toolkit(v2.3.0)
  2. 搭建基于Flask的SAML Demo系统
  3. 在IdP上创建两个测试用户:
    • 用户A:test1@cnnt.com
    • 用户B:test1@cnnt.com.cnnt.com

4.2 攻击步骤

  1. 获取合法SAML Response

    • 以用户B身份登录,获取SAML Response
  2. 修改SAML Response

    • 将NameID改为:test1@cnnt.com<!---->.cnnt.com
    • 对应Attribute中的email也做同样修改
  3. 重新编码

    • 对修改后的XML进行base64encode+urlencode
  4. 发送篡改后的Response

    • 将篡改后的SAML Response发送给SP
    • 观察是否成功获取用户A的访问权限

4.3 关键代码示例

原始NameID:

<NameID>test1@cnnt.com.cnnt.com</NameID>

篡改后NameID:

<NameID>test1@cnnt.com<!---->.cnnt.com</NameID>

5. 漏洞影响范围

5.1 受影响实现

  • OneLogin python-saml (CVE-2017-11427)
  • OneLogin ruby-saml (CVE-2017-11428)
  • Clever saml2-js (CVE-2017-11429)
  • OmniAuth-SAML (CVE-2017-11430)
  • Shibboleth (CVE-2018-0489)
  • Duo Network Gateway (CVE-2018-7340)

5.2 利用限制

  1. 需要已认证用户的合法SAML Response
  2. 目标用户的NameID必须是攻击者用户NameID的前缀
    • 例如:攻击者用户为123456,目标用户为1234

6. 防御措施

6.1 修复方案

  1. 升级到已修复版本:

    • OneLogin python-saml v2.4.0+
    • 其他库的相应修复版本
  2. 实施NameID格式检查:

    • 禁止NameID中包含XML注释
    • 严格验证NameID的格式和内容

6.2 最佳实践

  1. 使用一致的XML解析方法
  2. 实施严格的输入验证
  3. 监控异常的认证尝试
  4. 定期审计SAML实现

7. 总结

本漏洞利用SAML实现中XML处理不一致的问题,通过精心构造包含注释的NameID绕过签名验证,实现权限提升。虽然利用有一定限制,但对使用受影响SAML实现的系统构成严重威胁。及时更新库版本并实施严格的输入验证是防御此类漏洞的关键。

8. 参考资源

基于SAML的单点登录系统漏洞分析与实践教学文档 1. SAML基础概念 1.1 SAML定义 SAML(Security Assertion Markup Language)是一种基于XML的开放标准,用于在各方(特别是身份提供者和服务提供者)之间交换认证和授权数据。 1.2 核心组件 身份提供者(IdP) :负责用户身份识别和认证的系统 服务提供者(SP) :用户需要访问的应用系统 SAML声明(Assertion) :包含用户身份和其他属性的XML消息 1.3 工作模式 IdP-Initiated :用户首先访问IdP,认证后获得SAML Response,再访问SP SP-Initiated :用户首先访问SP,被重定向到IdP认证,再返回SP 2. SAML工作流程 2.1 基本流程 用户尝试访问SP资源 用户被重定向到IdP进行认证 认证成功后,IdP生成SAML Response(包含SAML Assertion) 用户浏览器将SAML Response转发给SP SP验证签名并提取用户身份信息 验证通过后授予访问权限 2.2 SAML Response结构 3. 漏洞原理分析 3.1 漏洞成因 XML标准化处理差异 : 签名验证时使用的 CanonicalizationMethod 会忽略XML注释 但某些XML解析库在处理NameID时不会忽略注释 具体表现 : 原始NameID: user@user.com.evil.com 修改后NameID: user@user.com<!--注释-->.evil.com 签名验证时两者被视为相同(忽略注释) 但某些解析器提取NameID时可能只获取注释前部分 3.2 技术细节 标准化方法 : http://www.w3.org/2001/10/xml-exc-c14n# 解析不一致 : 签名验证:忽略注释, test@example<!--注释-->.com → test@example.com 某些解析器: test@example<!--注释-->.com → test@example 4. 漏洞复现实践 4.1 环境准备 下载受影响版本的OneLogin Python-SAML Toolkit(v2.3.0) 搭建基于Flask的SAML Demo系统 在IdP上创建两个测试用户: 用户A: test1@cnnt.com 用户B: test1@cnnt.com.cnnt.com 4.2 攻击步骤 获取合法SAML Response : 以用户B身份登录,获取SAML Response 修改SAML Response : 将NameID改为: test1@cnnt.com<!---->.cnnt.com 对应Attribute中的email也做同样修改 重新编码 : 对修改后的XML进行base64encode+urlencode 发送篡改后的Response : 将篡改后的SAML Response发送给SP 观察是否成功获取用户A的访问权限 4.3 关键代码示例 原始NameID: 篡改后NameID: 5. 漏洞影响范围 5.1 受影响实现 OneLogin python-saml (CVE-2017-11427) OneLogin ruby-saml (CVE-2017-11428) Clever saml2-js (CVE-2017-11429) OmniAuth-SAML (CVE-2017-11430) Shibboleth (CVE-2018-0489) Duo Network Gateway (CVE-2018-7340) 5.2 利用限制 需要已认证用户的合法SAML Response 目标用户的NameID必须是攻击者用户NameID的前缀 例如:攻击者用户为 123456 ,目标用户为 1234 6. 防御措施 6.1 修复方案 升级到已修复版本: OneLogin python-saml v2.4.0+ 其他库的相应修复版本 实施NameID格式检查: 禁止NameID中包含XML注释 严格验证NameID的格式和内容 6.2 最佳实践 使用一致的XML解析方法 实施严格的输入验证 监控异常的认证尝试 定期审计SAML实现 7. 总结 本漏洞利用SAML实现中XML处理不一致的问题,通过精心构造包含注释的NameID绕过签名验证,实现权限提升。虽然利用有一定限制,但对使用受影响SAML实现的系统构成严重威胁。及时更新库版本并实施严格的输入验证是防御此类漏洞的关键。 8. 参考资源 Duo Labs SAML漏洞报告 SAML 2.0核心规范 XML签名规范