如何解码 SAML 消息
- 粘贴你手头的内容。以下几种都可以:
- 单独的
SAMLResponse或SAMLRequest值,URL 编码与否都行 SAMLRequest=…,带不带RelayState、SigAlg和Signature都行- 从地址栏复制的完整 Redirect URL
- 带隐藏
SAMLResponse输入框的自动提交 HTML 表单 - 原始 XML
- 单独的
- 解码器会识别绑定方式:纯 Base64 表示 HTTP-POST,经 deflate 压缩的数据表示 HTTP-Redirect。
- 先看摘要,再看下方格式化后的 XML。XML 只以文本形式显示,绝不会被渲染。
编码 方向则相反:粘贴一个 AuthnRequest,得到 Redirect 值、SAMLRequest= 参数,或根据 Destination 属性拼出的完整 URL。测试服务提供方时,用它重放请求很方便。
Redirect 绑定与 POST 绑定
| HTTP-Redirect | HTTP-POST | |
|---|---|---|
| 传输方式 | GET 请求的查询字符串 | 隐藏表单字段,自动提交 |
| 编码 | 原始 DEFLATE,再 Base64,再 URL 编码 | 仅 Base64 |
| 典型消息 | AuthnRequest、LogoutRequest | 带断言的 Response |
| 签名 | 单独的 SigAlg 和 Signature 参数 | 消息内部的 XML 签名 |
| 识别特征 | 没有固定前缀,Base64 解码后是二进制 | PHNhbWxwOl(<samlp:)、PHNhbWwycDp(<saml2p:)、PD94bWwg(<?xml ) |
Redirect 使用压缩,是因为 URL 在实际中有长度限制。以本页使用的示例来说,一个 464 字符的 AuthnRequest 压缩后是 273 字节,传输时是 364 个 Base64 字符。响应中带有签名和证书,放进 URL 太大,所以通过 POST 发送。解码器也接受 zlib 封装的数据,有些服务提供方在 Redirect 中发送的是这种格式,而不是原始 deflate。
SSO 失败时该检查什么
摘要会提取出导致大多数登录失败的字段:
- Status(状态):任何不是
urn:oasis:names:tc:SAML:2.0:status:Success的值。AuthnFailed、InvalidNameIDPolicy或RequestDenied这样的子代码会说明原因,StatusMessage常常还有更多细节。 - Destination 与 ACS URL:必须与服务提供方配置的端点完全一致,包括
https和末尾的斜杠。 - Audience(受众):必须等于 SP 的实体 ID。应用改名后,这里不一致是常见的配置错误。
- Conditions(条件):
NotBefore和NotOnOrAfter会和你的时钟比较。刚登录就显示“已过期”或“尚未生效”,说明 IdP 和 SP 之间存在时钟偏差。 - InResponseTo:应等于
AuthnRequest的ID。不一致说明响应是过期的或被重放的。IdP 发起的登录中没有这个属性,有些服务提供方会因此拒绝。 - NameID 与 Format:SP 用来匹配用户的标识符,例如
emailAddress还是persistent。 - 属性:每个属性及其所有值,用来确认 IdP 发送了 SP 所映射的组或邮箱。
在 Python 中解码 SAML
import base64, zlib
from urllib.parse import unquote
def decode_post(value):
return base64.b64decode(value).decode()
def decode_redirect(value):
raw = base64.b64decode(unquote(value))
return zlib.decompress(raw, -15).decode()
-15 告诉 zlib 预期的是不带头部的原始 deflate。只对从 URL 中复制的值调用 unquote;来自 POST 表单的值已经是纯 Base64,对它做 URL 解码可能会把 + 变成空格。更多内容见 Python 中的 Base64,压缩部分的原理见 原始 deflate 和 zlib 页面。
SAML 断言的隐私
断言中包含姓名、邮箱地址、组成员关系,有时还有更多个人数据;一个有效且未过期的断言可以当作登录令牌使用。本页面在本地解码,无法把它发送到任何地方。尽管如此,把断言贴到工单或聊天之前请先脱敏,并且在 NotOnOrAfter 过去之前,把抓到的响应当作会话 Cookie 一样对待。
常见问题
如何在浏览器中抓取 SAML 响应?
打开开发者工具,在“网络”标签页勾选 保留日志(Preserve log),然后登录。找到发往服务提供方 ACS URL 的 POST 请求,从它的载荷中复制 SAMLResponse 表单字段,粘贴到这里。
为什么普通的 Base64 解码器解不开我的 SAMLRequest?
在 HTTP-Redirect 绑定中,XML 会先经过原始 deflate 压缩,再做 Base64 和 URL 编码。普通解码器只会显示一堆二进制乱码。这个工具会一次完成 URL 解码、Base64 解码和解压。
解码器会验证 SAML 签名吗?
不会。它会告诉你消息、断言或查询字符串是否已签名,但不会用 IdP 证书校验签名。签名验证应该由服务提供方完成。
能解密 EncryptedAssertion 吗?
不能。加密断言需要服务提供方的私钥。解码器会统计它们的数量,并照常显示未加密的外层信息:状态、签发方和目标地址。