忘机山人
在第四章,我们已经澄清了一件非常重要的事:
懒猫 ID Token 不是加密的。
它是一组“被懒猫 SSO 签名的声明”。
这句话看起来很简单,但它隐含了一个巨大的问题:
如果任何人都能看到
groups: ["admin"],
ENV 查看器又凭什么相信这些声明是真的?
换句话说:
签名到底在“证明”什么?
这一章,我们就只回答这一件事。
在很多讨论中,你可能见过这样一句话:
“懒猫 SSO 用私钥加密,Client 用公钥解密。”
这句话在懒猫 SSO / OIDC 语境下是错误的。
它把两件完全不同的事情混在了一起:
如果你不在这里把这两个概念彻底分开,后面所有关于 JWT、JWKS(/sys/oauth/keys)、ID Token 校验逻辑的理解都会偏掉。
我们先用最严格、最不含糊的方式区分这两件事。
目标只有一个:
让别人看不到内容
典型模型是:
这是 保密性(Confidentiality)。
目标完全不同:
证明“这是谁发的”,以及“中途有没有被改”
典型模型是:
这是 真实性(Authenticity)+ 完整性(Integrity)。
只用签名。
懒猫 SSO 在 discovery 里写得明明白白:
"id_token_signing_alg_values_supported": ["RS256"]
没有 alg_values_supported 里的加密算法字段,也没有 JWE 相关的任何东西。
懒猫的设计从一开始就不试图隐藏内容。
它只试图证明一件事:
“这组声明,确实是由
https://alice.heiyu.space/sys/oauth这个懒猫 SSO 发出的,而且没有被修改。”
站在 ENV 查看器的角度,签名必须同时解决三个问题:
这些声明是不是这台盒子的 懒猫 SSO 发的?(不是别的盒子、不是自建的假 IdP)
中途有没有人把
groups: ["family"]改成groups: ["admin"]?
攻击者能不能自己造一个“看起来合法”的 token,直接塞给 ENV 查看器?
如果签名无法同时解决这三个问题,那整个懒猫 SSO 的安全模型就会崩塌——
毕竟所有 App 都信懒猫,懒猫只要一处可伪造,全盒子的应用都可以被绕过。
我们来看一个懒猫 ID Token 的真实签名结构(RS256):
header.payload.signature
其中:
header.payload 是完全可读的signature 是唯一的安全锚点签名不是“把 payload 加密一下”,
而是一个数学等式的结果。
我们用最直白、但不偷懒的方式,把懒猫 ID Token 的签名过程拆开。
在 JWT 中,被签名的数据是:
base64url(header) + "." + base64url(payload)
注意三点:
RS256 里的 256 对应 SHA-256。
对这段字符串做一次哈希运算:
hash = SHA256(data)
哈希的意义只有一个:
把任意长度的数据,映射成一个固定长度、不可逆、对变化极其敏感的摘要。
只要原始数据有 1 bit 变化,hash 就完全不同。
这一步才是真正的“签名”:
signature = RSA-Sign(hash, sso_private_key)
这里的关键点是:
懒猫官方会在升级、Key Rotation 的时候轮换这把 key,但不会把它泄漏给任何 App。
如果你在 App 里“需要懒猫 SSO 的私钥”,那你已经做错了一件事。
ENV 查看器拿到 token 后,会做对称的操作:
hash_client = SHA256(base64url(header) + "." + base64url(payload))https://alice.heiyu.space/sys/oauth/keys 拉到的 JWKS 里,找到 header.kid 对应的公钥signature 是否对应这个 hash如果验证通过,数学上意味着一件事:
这个 signature 只能来自对应的私钥,
而这个私钥只在盒子里的身份服务 手里。
这是整个懒猫 SSO 信任链的核心。
攻击者即使:
RS256)/sys/oauth/keys 对全世界公开)他依然做不到一件事:
生成一个能通过验证的 signature
因为 RSA 签名算法的安全性,建立在一个非常强的前提上:
从公钥推导私钥,在计算上是不可行的。
这不是工程约定,而是现代密码学的基础假设。
这是懒猫 ID Token 安全性的第二个关键点。
如果攻击者尝试修改 payload 中的任何字段,比如把:
"preferred_username": "alice",
"groups": ["family"]
改成:
"preferred_username": "alice",
"groups": ["admin"]
会发生什么?
payload 改变base64url(header) + "." + base64url(payload) 改变hash 改变signature 没变(攻击者没有私钥重签)结果只有一个:
签名验证失败。
这保证了:
懒猫 SSO 声明一旦被签名,就不可被悄悄篡改。
这也意味着:你可以、并且应该信任 groups 字段。只要签名验证通过,它就是懒猫原始发出的样子。

到这里,我们必须再次强调签名的边界。
签名能证明:
但它不能证明:
xu.deploy.env 的(那是 aud)exp)nonce)iss)换句话说:
签名只能回答“这是真的吗”,
不能回答“这该不该信”。
很多懒猫 App 里会出现这种错误逻辑:
“既然签名验证通过了,那 token 就是安全的,我就可以直接读
preferred_username登录用户了。”
这是不成立的。
在懒猫 SSO 里:
你可以把它理解成:
签名只是“验明正身”,
而不是“授权使用”。
我们用几条不可模糊的结论结束这一章:
RS256),而不是加密/sys/oauth/keys)决定“谁能验证”签名证明“这些声明只能来自这台盒子的懒猫 SSO”,
但不证明“你现在就该相信它们”。
评论
0暂无评论