忘机山人
在第五章,我们已经确认了一件事:
只要 ENV 查看器能拿到懒猫 SSO 的公钥,
并成功验证签名,
那它就可以确信:
这些声明只能来自懒猫 SSO。
但这句话里,隐藏着一个极其危险的前提:
ENV 查看器拿到的“那把公钥”,
真的是懒猫 SSO 的公钥。
如果这一点站不住脚,
前一章所有关于签名、私钥、不可伪造的结论,都会瞬间失效。
于是,一个新的问题出现了:
ENV 查看器从哪里拿到公钥?
又凭什么相信这把公钥是对的?
这正是 JWKS 存在的原因,也是懒猫 SSO 为你暴露 https://alice.heiyu.space/sys/oauth/keys 的意义。
在最早期的懒猫玩法(以及很多自建 OIDC 的教程)里,你可能见过这样一种做法:
“把懒猫 SSO 的公钥下载下来,写在应用的配置文件里。”
从功能上看,这当然可行。
但从系统设计上看,这是一个不可接受的方案。
原因并不复杂。
懒猫官方会定期做 Key Rotation:
如果 ENV 查看器把公钥写死:
这在工程上是不可接受的。
在真实的懒猫 SSO 实现中,签名者往往会:
RS256,但未来可能变)ENV 查看器如果只“认一把”,
就会在合法场景下误判 token 为非法。
最根本的问题在于:
公钥不是一个静态参数,
而是懒猫 SSO 对外发布的一部分“信任接口”。
它应该:
iss)这三点,单靠配置文件是做不到的。
JWKS(JSON Web Key Set)并不神秘。
它只是一个 JSON 格式的公钥集合,
通过 HTTPS 对外发布。
懒猫 SSO 的 JWKS 地址是:
https://alice.heiyu.space/sys/oauth/keys
这个地址不是猜出来的,它由 discovery 返回的 jwks_uri 字段决定:
{
"issuer": "https://alice.heiyu.space/sys/oauth",
"jwks_uri": "https://alice.heiyu.space/sys/oauth/keys",
...
}
一个典型的返回看起来像这样:
{
"keys": [
{
"kty": "RSA",
"kid": "3e7f...",
"use": "sig",
"alg": "RS256",
"n": "…",
"e": "AQAB"
}
]
}
每一项,描述的都是一把 可用于验签的公钥。
ENV 查看器不需要提前知道公钥内容。
它只需要知道:
“去哪里拿。”
这个“哪里”,不是随意指定的 URL,
而是通过 OIDC Discovery 机制获得的:
GET https://alice.heiyu.space/sys/oauth/.well-known/openid-configuration
在这里,懒猫 SSO 明确告诉 ENV 查看器:
issuer)token_endpoint)jwks_uri)而这个 issuer 的值,又由你容器里的 LAZYCAT_AUTH_OIDC_ISSUER_URI 环境变量决定——
懒猫注入的这个变量,就是整个信任链的起点。
JWT 的 header 中,有一个非常重要的字段:
{ "alg": "RS256", "kid": "3e7f..." }
kid 的含义只有一个:
“这个 token 是用哪一把 key 签的。”
ENV 查看器在拿到的 JWKS 里:
kid 对应的 key这使得:
JWKS 是一个可随时间变化的集合:
实现层面的建议(用主流 OIDC 库几乎都自带):
kid,主动刷新一次这让“长期运行的信任关系”成为可能——
你的 App 写好一次,懒猫这边换多少次 key 都不用动它。
现在我们把 JWKS 放回到实际流程中。
当 ENV 查看器拿到一个 ID Token 时,它会:
alg(必须是 RS256)、kidhttps://alice.heiyu.space/sys/oauth/keys注意这个结论:
“找不到对应公钥”
本身就是一个拒绝信号。
如果你的 App 在这里写了 fallback(“找不到就跳过签名验证”),
那整个懒猫 SSO 的安全模型在你这里就破了。
这是一个经常被提出、也非常值得认真回答的问题:
“如果有人在家庭网络里拦截到
/sys/oauth/keys的请求,
返回一套伪造的公钥,会怎样?”
这个攻击模型并不成立,原因不在于 JWKS 本身,而在于:
JWKS 从来不是“裸奔”的。
JWKS 是通过 HTTPS 获取的,而且 heiyu.space 的证书是懒猫官方签发的可信证书。
这意味着:
要成功伪造 JWKS,中间人必须:
*.heiyu.space 证书这已经超出了懒猫 SSO 的威胁模型。
⚠️ 例外:如果你手贱在 App 里关掉了 TLS 验证(比如用自签证书做开发调试),这条就不成立了。别在生产配置里关 TLS 验证。
ENV 查看器并不是“随便拉一个 JWKS”。
它的逻辑是:
“这个 JWKS 属于
https://alice.heiyu.space/sys/oauth这个 issuer。”
而 issuer 本身,已经在 discovery 阶段被固定(来自 LAZYCAT_AUTH_OIDC_ISSUER_URI)。
攻击者即使伪造一套 JWKS,也无法绕过:
iss 校验aud 校验
这是整个模型中最容易被忽略的一点:
安全性不来自“公钥保密”,
而来自“私钥不可得”。
攻击者可以:
但只要他没有懒猫 SSO 的私钥:
就无法生成任何能通过验签的 token。
ENV 查看器在实现 JWKS 支持时,必须遵守一个原则:
永远不要从 token 本身“学会”信任来源。
具体来说:
jkux5ujwks_uri 做成“App 用户可配置的”(这是一个经典反面教材)JWKS 的来源,必须是:
懒猫注入的
LAZYCAT_AUTH_OIDC_ISSUER_URI→ discovery →jwks_uri
这是防止 Key Injection 的关键。
在本章结束时,ENV 查看器已经具备了三项能力:
这意味着:
ENV 查看器已经能确认:
“这组声明确实来自这台盒子的懒猫 SSO,且没有被篡改。”
但请注意:
我们仍然没有回答一个更关键的问题。
一个 token 可以:
但仍然可能:
aud 是 some.other.app)也就是说:
“来源可信”
≠
“现在就该信任并使用这些声明”。
我们可以把这一章的结论总结为:
https://<盒子>.heiyu.space/sys/oauth/keys 发布LAZYCAT_AUTH_OIDC_ISSUER_URI 绑定
JWKS 让“数学可信”变成了“懒猫 App 可用的可信”。
评论
0暂无评论