三密钥模型
三密钥模型是 Sudomimus 浏览器流程会话安全的核心。每一次经过 Connect 的身份认证往返都会在不同时刻签发三把彼此独立的密钥,分别由不同的当事方持有,防御不同类型的攻击。一次成功的 /redeem 必须同时出示这三把密钥。
本页讲的不是 Sudomimus 用来签令牌的长期密钥(那部分见 令牌与验证)。本页讲的是一次浏览器登录如何证明自己的合法性。
| 密钥 | 创建者 | 持有方 | 可见范围 |
|---|---|---|---|
| exposureKey | /establish | 应用后端 → 浏览器 | 浏览器、URL、via.sudomimus.com |
| hiddenKey | /establish | 仅应用后端 | 后端 |
| confirmationKey | 用户完成认证后由 via.sudomimus.com 签发 | 应用后端(通过回调) | 浏览器、URL |
exposureKey 和 hiddenKey 是同一次 /establish 调用成对签发的。它们属于唯一的一个会话,也只属于那个会话。
每把密钥都带有角色专属的前缀,便于在请求边界直接拒绝错位的密钥:
exp_+ 32 位小写 hexhid_+ 32 位小写 hexcnf_+ 32 位小写 hex
为什么是三把而不是一把
Section titled “为什么是三把而不是一把”如果仅凭一个不透明的会话引用就能换取令牌,那么任何得到该引用的攻击者都可以冒充用户完成兑换。将证明拆成三部分后,攻击者必须同时突破三个不同的信任边界:
- 没有
hiddenKey—— 即使攻击者窃取了用户正在访问的 URL,也无法兑换令牌。hiddenKey永远不会离开应用服务器。 - 没有
exposureKey—— 即使攻击者攻破了应用服务器,也无法兑换其他用户的会话,因为每个待处理会话的exposureKey只会发送给对应的浏览器。 - 没有
confirmationKey—— 任何一方都无法兑换用户尚未完成的会话。只有用户在via.sudomimus.com上通过通行密钥或验证码挑战后,平台才会签发confirmationKey。
/establish ────► exposureKey + hiddenKey │ │ ▼ ▼ 发给浏览器 留在后端 │ ▼ via.sudomimus.com ──► 用户通过挑战 │ ▼ confirmationKey ──► 回到你的回调 │ ▼/redeem ◄──── exposureKey + hiddenKey + confirmationKey │ ▼ accessToken + refreshToken/redeem 成功之后,这三把密钥都会被消费掉,不能再次使用。即使应用重复发送同一组三元组,第二次也会失败。
与 OAuth 2.0 的对照
Section titled “与 OAuth 2.0 的对照”如果你熟悉 OAuth 的 authorization-code 流程,大致的对应关系是:
| Sudomimus | OAuth 2.0 |
|---|---|
exposureKey | state 参数(大致对应) |
confirmationKey | authorization code |
hiddenKey | 没有直接对应物 |
OAuth 使用长期存在的 client_secret 验证令牌交换请求。Sudomimus 则在每次 /establish 时生成新的 hiddenKey。某次会话的 hiddenKey 泄露只会影响这一次兑换,不会影响应用过去或未来的其他兑换。
这与「持有证明(proof-of-possession)令牌」的思路一致:短期、范围明确的密钥优于长期、被广泛共享的密钥。
如果需要标准的 OAuth/OIDC 语义,可以使用部署在 oidc.sudomimus.com 的标准 OIDC 提供方。三密钥模型用于底层 Connect 协议,通过 OIDC 接入的应用不会直接接触它。
除了上述三把会话密钥,每个应用还有两对长期 RSA-2048 密钥对:
- Token-signing 密钥对 —— Sudomimus 用私钥半边签 access / refresh JWT;应用通过
POST /info拿到公钥半边验证签名。 - Client-auth 密钥对 —— 应用用私钥半边(在应用创建和每次轮换时一次性下发)签每一次
/establish请求;Sudomimus 用存储的公钥半边校验。
这两对都不属于「三密钥」模型。它们认证的是 Sudomimus 与应用之间的通道;三把会话密钥认证的是一次登录。完整细节见 令牌与验证。