CVE-2026-33322:OIDC JWT 算法混淆
状态: 已发布
首个包含版本: RELEASE.2026-04-17T00-00-00Z
影响入口: AssumeRoleWithWebIdentity、AssumeRoleWithClientGrants
GitHub Issue: pgsty/minio#22
旧实现把 OIDC client secret 放进 JWT verifier keyring,同时允许 HMAC signing method。知道 client secret 的攻击者因此可以自行签发 HS token,再通过 STS 换取临时权限。最终修复恢复了 JWKS-only 非对称验证:宁可明确打破 HS256/384/512 兼容,也不保留一个会重新混淆信任语义的开关。
漏洞不在“有没有验签”
表面上看,旧代码确实执行了 JWT signature verification。真正失效的边界是:verifier 接受了哪一种 key,以及 token header 是否能选择与该 key 不匹配的算法语义。
攻击链需要满足几个条件:
- 攻击者获得 OIDC client secret;
- 攻击者构造 HMAC-signed ID token;
- verifier 把 client secret 当作 HMAC signing key;
- token 进入 WebIdentity 或 ClientGrants STS flow,换取临时凭据。
client secret 泄露本身当然严重,但它原本不应该自动获得“签发任意用户 ID Token”的权限。把两种能力混在同一个 keyring 中,才是算法混淆的核心。
兼容路径写出来了,又被主动删除
修复过程中曾经实现过 allow_hmac 一类兼容路径。它看起来很合理:默认安全,确有需要的用户可以显式打开。但继续把 shared secret 放进通用 verifier keyring,意味着管理员需要理解这个配置实际上扩大了整个 STS 信任边界;未来 method allowlist 只要发生漂移,漏洞就可能重现。
几种方案的取舍最终非常清楚:
| 方案 | 收益 | 风险 | 结论 |
|---|---|---|---|
| 保留 secret keyring,只限制部分算法 | 改动小,兼容 HMAC IdP | keyring 仍混合两种信任语义 | 否决 |
增加 allow_hmac 配置 | 兼容性显式 | 配置本身难以正确理解,测试面扩大 | 实现后回滚 |
| JWKS-only | 边界清晰,刷新与重试共用同一 parser | HS 用户必须迁移 | 接受 |
这次最重要的决策不是“新增了哪些代码”,而是主动删除了已经完成的兼容实现。
最终不变量
修复集中在 OIDC JWT 验证路径,并固定了四条规则:
- verifier key 只来自 IdP JWKS;
- OIDC client secret 不进入 JWT verification keyring;
- HS256、HS384、HS512 一律拒绝;
- 正常 RS256 流程以及 JWKS refresh/retry 使用同一 method allowlist。
修复没有借 CVE 顺手扩展 JOSE 功能。PS256 与 EdDSA 不在这次事件的支持范围内。
验证与发布
开发记录包含 HS256 rejection、RS256 acceptance、JWKS refresh/retry regression tests,以及 focused go test ./internal/config/identity/openid。临时兼容 helper、配置与测试在最终 diff 中全部删除。
公开发布 lineage 中的修复提交为 f1f2239,并随 SILO 2026-04-17 发布。这篇文章记录历史验证,不代表本次博客整理重新执行了测试。
兼容性代价
这是明确的 breaking change。仍签发 HS256/384/512 token 的 IdP 必须先迁移到 JWKS-backed RSA/ECDSA,再升级 SILO。这里选择的是更窄、更容易解释的信任模型,而不是让旧配置继续工作。