SAML:一个坏设计的分形
SAML: A Fractal of Bad Design

SAML 协议诞生于学术界,在 IT 部门中茁壮成长,如今却因过度复杂而难以为继。从 XML 的底层缺陷到 Canonicalization 和 Enveloped signatures 的设计硬伤,SAML 暴露了“委员会设计”的致命弱点。随着 OpenID Connect (OIDC) 等现代协议的兴起,SAML 正面临被弃用的命运。本文深入剖析 SAML 的五大致命缺陷,揭示其为何成为安全研究的靶子,并呼吁行业转向更简洁、更安全的身份验证方案。
SAML 的阴险之处在于它其实大多通俗易懂,但它建立在流沙、骨粉和灰烬之上;只要假设 XML 签名验证是可靠的,它就能工作。但 XML 签名验证是深受诅咒的,且如此复杂,以至于大多数部署的 SAML 实现都在封装 libxmlsec,这是一个没人去读的令人头疼的 C 代码库。
HN 评论区
177- bawolff
我最喜欢的 SAML 恐怖故事是:默认情况下,xmlsig 的主要 C 语言实现不仅会用指定的公钥验证签名,还会:
- 用攻击者控制的文档中指定的密码,通过 HMAC 进行验证。
- 使用 Web PKI 验证签名(因此攻击者可以用自己个人域名的 TLS 密钥签署 SAML 文档,系统会始终认为它是有效的)。
老实说,我真不知道为什么用 SAML 的网站没有被频繁黑掉。比那些糟糕透顶的标准更糟糕的,是那些糟糕透顶的实现。
- HelloNurse
"... 这不是委员会的错。当时他们只有 XML,大家也都在用。JSON 直到 2001 年才‘被发现’..."
委员会至少还有 ASN.1 可用。虽然不是文本,但任何数字签名方案都必须是机器可读的,而不是给人看的。
- jmbwell
这完全是那种'哇!标记语言!我们能用标记语言解决什么问题!'的产物。而认证根本就不是那种需要被标记的文档或数据流。
文章正确地将其与 XML 联系起来,XML 在当时确实是那把万能锤子。
不过,我觉得这个问题我们还没彻底解决。OIDC 为了迎合 Google 等公司,做出了很多假设。而文中提到的 Tailscale,尽管号称'坚守阵地',但在遇到像 GitHub 账户需要区别对待这类情况时,已经露出了裂痕。
我们缺少的是一种独立于提供商的解决方案。我应该能够创建一个账户,并使用我自己控制的后台,几乎在任何地方登录。这完全是可以做到的,只是用我们现在的东西还做不到。
- cameronh90
SAML 很烂,但它针对其特定的、狭窄的企业级 SSO 用例,仍拥有一堆 OIDC 所缺乏的功能——最显著的就是 IdP 发起的流程(IdP-initiated flow)。OIDC 是一组规范,不同产品对其支持程度不一致;而 SAML 中那些被广泛实现的子集,其平庸程度反而相对稳定。
OIDC 最终会取代 SAML,但如果你面向企业销售,真的应该同时支持两者。不管怎样,你在处理不同 IdP 之间 SCIM 不一致性上所花的时间,会让这两者都相形见绌。
- tehnoslow
对这篇文章一个公正的批评是:它列出了 SAML 的漏洞,却没有对 OIDC 做同样的对比。OIDC 也有自己的问题:JWT 算法混淆、none 算法攻击、缺失受众(audience)检查,以及 JOSE 库中的 bug。
- rhdunn
当我在 Java/JVM 应用中通过 SAML、OAuth、JWT 及其他认证机制集成 SSO 时,我的首选是 pac4j(https://github.com/pac4j/pac4j)。它提供了与 Spring 和 Scala Play 等各种 Web 框架的集成和演示。它在将 SSO 集成到应用程序方面承担了大量繁重工作。
- ratiolat
OIDC 基于 OAuth2。OAuth 中的 'auth' 代表授权(authorization),而非认证(authentication),这也引出了我对 OIDC 的问题所在——即 OIDC 是关于授予第三方访问你数据的权限。你可以通过使用像 Okta 这样的东西来稍微缓解这个问题,因为它本身并没有这些数据;但假设你没有 Okta,只有 Google Workspace 呢?
- arpinum
SAML 甚至比文章描述的还要糟糕,比如需要检查签名实际签的是什么这类问题。但我对未来的前景持乐观态度:与其依赖那些功能繁多(比如通用 XML 解析)的库,我们可以只支持 SAML 的一个子集,以及前 ~10 大提供商的方言。极小众的提供商可以按需临时添加,前提是该交易规模值得这样做。