跳转到内容

三密钥模型

查看 Markdown

三密钥模型是 Sudomimus 浏览器流程会话安全的核心。每一次经过 Connect 的身份认证往返都会在不同时刻签发三把彼此独立的密钥,分别由不同的当事方持有,防御不同类型的攻击。一次成功的 /redeem 必须同时出示这三把密钥。

本页讲的不是 Sudomimus 用来签令牌的长期密钥(那部分见 令牌与验证)。本页讲的是一次浏览器登录如何证明自己的合法性。

密钥创建者持有方可见范围
exposureKey/establish应用后端 → 浏览器浏览器、URL、via.sudomimus.com
hiddenKey/establish仅应用后端后端
confirmationKey用户完成认证后由 via.sudomimus.com 签发应用后端(通过回调)浏览器、URL

exposureKeyhiddenKey 是同一次 /establish 调用成对签发的。它们属于唯一的一个会话,也只属于那个会话。

每把密钥都带有角色专属的前缀,便于在请求边界直接拒绝错位的密钥:

  • exp_ + 32 位小写 hex
  • hid_ + 32 位小写 hex
  • cnf_ + 32 位小写 hex

如果仅凭一个不透明的会话引用就能换取令牌,那么任何得到该引用的攻击者都可以冒充用户完成兑换。将证明拆成三部分后,攻击者必须同时突破三个不同的信任边界

  • 没有 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 的 authorization-code 流程,大致的对应关系是:

SudomimusOAuth 2.0
exposureKeystate 参数(大致对应)
confirmationKeyauthorization 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 与应用之间的通道;三把会话密钥认证的是一次登录。完整细节见 令牌与验证