四枚SAML漏洞从报告到修复:签名与身份解析不一致的教训
四枚SAML漏洞从报告到修复:签名与身份解析不一致的教训
四个SAML SSO认证绕过漏洞根因相同:签名验证与身份提取对同一XML解析不一致。
一次安全审计揭示了四个 SAML SSO 认证绕过漏洞,它们无需破解加密或窃取私钥,根源出奇一致:同一份 SAML 响应在签名验证和身份提取两个环节被不同解析器、不同 XPath 乃至不同命名空间处理方式解读成了不同内容,攻击者可据此让验签看到用户 A、提取器读到管理员 B。修复的核心是消除双解析器,让安全决策与业务逻辑基于同一份经 C14N 规范化处理的 XML 树,并严格校验命名空间、使用绝对路径。文章同时提醒,这类"先验签、后解析"的风险普遍存在于部分 JWT 与 WS-Security 实现中,团队应立即审计相关代码路径。
SAML SSO 是企业身份认证的基石,但一次安全审计揭示了四个认证绕过漏洞,根源出奇地一致:同一份 SAML 响应在签名验证和身份提取两个环节被解读成了不同的内容。
漏洞的本质:双解析器不一致
签名验证与身份提取为何会"各说各话"
SAML 响应是一段带数字签名的 XML。验证逻辑检查签名是否覆盖了某个节点,然后另一段代码再从同一文档中提取用户身份属性。问题在于,这两段代码往往使用不同的 XML 解析器、不同的 XPath 表达式,甚至对命名空间的处理方式也不一样。
攻击者可以利用这种差异:构造一份 XML,让签名验证器看到的是用户 A 的数据,而身份提取器读到的是用户 B(通常是管理员)的身份。签名本身完全合法,但系统被绕过了。
XML 规范化(C14N) 是 W3C 定义的一套算法,用于将逻辑等价的 XML 文档转换为字节级一致的标准形式。XML 规范允许同一份逻辑文档存在大量等价写法——属性顺序可以调换、命名空间可以声明在不同层级、空元素可以写成自闭合或展开形式、字符可以实体转义或直接书写。这些差异在 XML 信息集层面等价,但字节序列完全不同。签名验证通常作用于字节序列或规范化后的节点集,因此若签名方与验证方采用不同的规范化方式,就会出现"验签通过但内容解读不同"的情况。SAML 规范要求使用排他性规范化(Exclusive C14N),它只包含实际被使用的命名空间声明,避免祖先节点的无关声明污染规范化结果,这也是修复这类漏洞时必须严格遵循的细节。
XPath 与命名空间是解析歧义的高发区。在 XPath 1.0 中,不带前缀的元素名会匹配无命名空间的元素,而非默认命名空间中的元素,这与大多数开发者的直觉相反。若身份提取代码写作 /Response/Assertion/Subject/NameID,而文档中这些元素实际位于 urn:oasis:names:tc:SAML:2.0:assertion 命名空间下,该表达式将匹配不到任何节点或匹配到攻击者注入的伪造节点。此外,// 这类后代轴选择、通配符 *、以及 local-name() 的宽松匹配,都可能让提取器选中与验签器不同的节点。防御实践中应使用绑定到明确命名空间前缀的绝对路径,并校验解析器报告的命名空间 URI 而非仅比对元素本地名。
四个漏洞,一个根因
这次披露的四个漏洞全部可以归类为认证绕过,且都源于同一类解析歧义。它们不需要破解加密算法,也不需要窃取私钥,只需要理解解析器之间的行为差异即可构造利用载荷。
从漏洞分类看,这类缺陷通常被归入 CWE-436(解释冲突) 与 CWE-347(签名验证不当) 的交集。与之同源的著名历史案例包括 2018 年披露的 Duo Labs SAML 漏洞(涉及 XML 注释与命名空间混淆)、GitHub Enterprise 的 SAML 绕过,以及更早的 XML 签名包装攻击(XML Signature Wrapping, XSW)。XSW 的核心手法是保留合法的已签名节点,同时插入一个结构相似、位置不同的伪造节点,诱导业务代码读取后者。理解 XSW 的多种变体——如将签名元素复制到伪造断言内部、利用 ID 属性重复、借助 ds:Reference 的 URI 指向歧义——是评估自身实现是否安全的必要背景。
从报告到修复:响应过程
发现与确认
漏洞报告于 2026 年 9 月下旬完成修复。团队在确认阶段重点做了两件事:一是复现每种解析差异,二是评估哪些下游业务系统实际依赖了不安全的解析路径。
修复策略
根治思路是消除双解析器:签名验证和身份提取必须基于同一份经过规范化处理的 XML 树。任何对原始字节的二次解析都是潜在风险。
给开发者的实践建议
处理签名 XML 的硬性规则
- 禁止使用多个解析器处理同一份安全敏感的 XML 文档
- 在签名验证前对 XML 做规范化(C14N),并确保身份提取基于规范化后的结果
- 严格校验命名空间,不要依赖默认命名空间的隐式行为
- 对 XPath 查询使用绝对路径,避免模糊匹配
在工程落地上,应优先选用成熟库并遵循其安全指引:Java 生态中的 OpenSAML、Spring Security SAML,.NET 中的 ITfoxtec 或 Sustainsys.Saml2,均内置了针对 XSW 的防护。若必须自研,务必关闭外部实体解析(XXE) 与 DTD 处理,使用带命名空间感知的解析器(如 Java 的 DocumentBuilderFactory.setNamespaceAware(true)),并在验签时校验 Reference 的 URI 指向文档中唯一的断言 ID。同时应拒绝重复 ID、带注释的 ID 以及 ID、Id、id 属性大小写混用的情况,因为这些正是解析器产生分歧的常见触发点。
测试中应该覆盖的场景
安全测试不能只测"签名无效时是否拒绝",还要测"签名有效但解析结果存在歧义时行为是否一致"。可以构造包含重复节点、嵌套命名空间、注释干扰的 XML 样本,观察验证与提取是否指向同一逻辑节点。
更广泛的启示
SAML 的这类问题并非孤例。任何"先验签、后解析"的协议(包括部分 JWT 和 WS-Security 实现)都存在类似的解析器不一致风险。防御的核心原则很简单:安全决策和业务逻辑必须基于同一份数据视图。当两者出现分叉时,攻击面就随之出现。
对于使用 SAML SSO 的团队,建议立刻审计自研或第三方库中签名验证与身份提取的代码路径,确认它们是否共享同一个解析结果。如果答案是否定的,那就应该把这四个漏洞当作一个警示:下一个绕过可能就藏在你自己的代码里。
相关推荐

uGAP:统一100+非洲地理数据集的AI平台
uGAP是开普敦大学团队开发的非洲地理空间AI平台,统一120余个非洲数据集并提供Python SDK,支持数据发现、处理与模型训练一站式工作流,已用于气旋洪水制图等实战场景。

Cursor能控制你的电脑了:AI代理可驱动桌面应用测试
Cursor 新增桌面控制能力,AI 代理可驱动 iOS 模拟器等桌面应用测试自己构建的功能。本文分析这一更新对开发工作流的影响、技术实现可能路径及可靠性考量。

Vibecoding自研推理引擎:理想丰满,现实骨感
Reddit开发者分享Vibecoding自研推理引擎的真实经历:用WebGL2和GLSL在浏览器跑GGUF Q4模型,却陷入tokenizer调试地狱。本文分析浏览器端LLM推理的工程难点,以及为何直接clone llama.cpp是更理性的选择。