CVE-2026-33419:LDAP STS 用户枚举与限流链

从统一认证失败,到修正成功退款、代理来源与账户锁定:一次经历两轮反向修复的 LDAP STS 加固。

状态: 已发布,经历两轮后续修正
首个包含版本: RELEASE.2026-04-17T00-00-00Z
完整修正版本: RELEASE.2026-06-18T00-00-00Z
GitHub Issue: pgsty/minio#23

核心漏洞很直接:LDAP STS 对“用户不存在”和“密码错误”返回不同结果,形成 username oracle。第一版修复统一外部错误,并增加 source IP 与 username 双重限流;连续复核却发现,成功退款、可伪造来源 header、reservation accounting 和共享 username bucket 都可能让安全控制本身成为新的攻击面。

六月的最终方案删除了会造成精确账户锁定的 username bucket,只保留 source IP bucket,并把代理来源识别写成明确的部署契约。

初始威胁模型

入口是 AssumeRoleWithLDAPIdentity。攻击者不需要已有 MinIO 账号,只要能够访问 LDAP STS endpoint,就可以比较 unknown user 与 wrong password 的 code、status 或 message,逐步枚举有效用户名,再结合 password spraying、组织结构猜测或社工攻击。

修复也不能简单把所有错误都伪装成“密码错”。LDAP connection、lookup bind 或目录服务故障必须继续表现为基础设施错误,否则运维会失去诊断能力。

第一轮:统一响应并增加 limiter

2026-04-15 的初始修复做了三件事:

  • unknown user 与 bad password 对外返回同一 STS auth error;
  • LDAP infrastructure error 仍返回 500,并在 server log 保留真实原因;
  • 新增 in-memory limiter,最初同时按 source IP 与 normalized username 分桶。

这一版关闭了内容侧信道,也给暴力尝试增加了成本,但 limiter 的状态机与来源识别随后暴露出更多问题。

第二轮:成功、来源与会计

4 月 16 日的连续修正处理了三类缺陷:

  1. 成功认证不应消耗失败额度,reserve/commit/cancel/refund 生命周期必须明确;
  2. 默认只能使用 socket peer,不能直接信任 X-Forwarded-ForX-Real-IPForwarded
  3. refund 与 capacity 必须有边界,避免 cancel 逻辑凭空增发 token。

trusted proxy 需要显式 allowlist,而不是因为请求带着“真实 IP” header 就自动获得信任。

第三轮:删掉 username bucket

六月的对抗性复核推翻了“source + username 一定比 source-only 更强”的直觉。共享 username bucket 可以被任意来源持续耗尽,攻击者只需要低频请求就能在合法用户真正执行 LDAP bind 之前,精确锁死一个目标账户。

最终修复因此:

  • 删除 per-username bucket;
  • XFF 从右向左剥离 trusted hops,取第一个非可信地址;
  • 拒绝 0.0.0.0/0::/0 这类 trusted-proxy footgun;
  • Forwarded 不再用于安全敏感分桶;
  • X-Real-IP 只在代理覆盖而非透传客户端输入的契约下使用。

这次转折说明,安全控制必须拥有自己的威胁模型。限制更多维度,不等于更安全。

被否决的方案

方案否决原因
为未知用户执行 dummy bind放大 LDAP 压力并引入易错的第二条认证路径;内容侧信道已经关闭
IPv6 统一按 /64 分桶会让同一站点或运营商前缀下的合法用户互相误伤
XFF 直接取最左值客户端可伪造
XFF 与 X-Real-IP 不一致就回退 peer攻击者可故意制造不一致,把代理后的所有用户压入同一 bucket
完整支持 RFC 7239 Forwarded安全解析复杂度高,现实收益不足

验证与发布

历史记录覆盖 limiter reserve/commit/cancel/refund、并发、success、infra failure、unknown user/bad password 外部等价,以及 RemoteAddr、spoofed header、trusted proxy、多 hop 与 catch-all CIDR。focused package test 与 build 均有记录。

LDAP security e2e 在缺少 _MINIO_LDAP_TEST_SERVER 时会 skip,所以外层 ok 不能冒充真实 LDAP 全场景证明。

初始公开修复提交为 6619d0c,后续修正包括 c55b52c817a457084a1545e40665

最终代价与残余风险

  • limiter 最终只按 source IP,放弃跨来源的单账号 hard throttle;
  • limiter 是 per-node、in-memory,不是集群全局密码防护;
  • botnet、分布式来源、IPv6 地址轮换与 LDAP bind timing 仍然存在;
  • trusted proxy 配置错误仍会破坏来源归属;
  • Forwarded-only 部署会退化为 peer bucket,粒度更粗。

限流只能降低单一来源的尝试速率。真正隐藏 username existence 的,是统一的外部认证响应。

最后修改 August 2, 2026: init commit (8338d5b)