SN-2026-023:已认证 STREAMING-UNSIGNED-PAYLOAD-TRAILER 无限期重放窗口与 SigV4 条件键缺失
发布状态: 主干已修复(14ecb222e、296c9710b),将随 20261109 之后的下一版 Server 发布
安全编号: SN-2026-023(安全公告台账,#338)
严重程度: 高危(High)
影响范围: SILO Server(RELEASE.2026-11-09T00-00-00Z 及更早版本)与自 2023-05-05(76913a9fd)以来的上游原版 MinIO
不受影响组件: silo-console、mcli、silo-pkg 与 kes
在 AWS S3 的 STREAMING-UNSIGNED-PAYLOAD-TRAILER 协议模式中,客户端仅使用 Signature Version 4(Authorization: AWS4-HMAC-SHA256 ...)对初始 HTTP 请求头签名,随后的 aws-chunked 数据块与末尾尾标校验和(Trailer Checksum)均不包含逐块加密签名。由于规范请求(Canonical Request)中绑定的只是固定字符串 "STREAMING-UNSIGNED-PAYLOAD-TRAILER" 而非请求体的 SHA-256 摘要,校验已签名 X-Amz-Date 请求头的 15 分钟有效期窗口(globalMaxSkewTime = 15 分钟)是阻止历史请求头被重放的唯一时间边界。
继承自上游 MinIO 的 setAuthMiddleware(cmd/auth-handler.go)对 authTypeSigned、authTypeStreamingSigned 与 authTypeStreamingSignedTrailer 执行了 parseAmzDateHeader 与 15 分钟时钟偏差检查,却唯独遗漏了 authTypeStreamingUnsignedTrailer。一旦某次已认证上传的请求头在代理日志、调试抓包或明文链路中泄露,只要对应 Access Key 尚未吊销,攻击者就可在数天乃至数月之后重放同一组请求头,并替换为任意等长(X-Amz-Decoded-Content-Length 相同)的恶意载荷覆写目标对象。此外,getConditionValuesWithTags(cmd/bucket-policy.go)在两种尾标流式模式下均未填充 s3:signatureversion 与 s3:authType 策略条件键。
摘要
- 问题本质:
- 无限期请求头重放与等长内容替换:
setAuthMiddleware与doesSignatureMatch(cmd/signature-v4.go)均未对authTypeStreamingUnsignedTrailer检查X-Amz-Date时间偏差。任何携带Authorization的历史上传请求头在超过 15 分钟后依然永久有效,且可搭配全新的任意等长数据块与自算 CRC 尾标覆写同一(bucket, key)(含PutObject、PutObjectPart与PutObjectExtract)。 - 尾标流式请求缺失 SigV4 策略条件键:
getConditionValuesWithTags为早期的authTypeStreamingSigned填入s3:signatureversion = "AWS4-HMAC-SHA256"与s3:authType = "REST-HEADER",却将authTypeStreamingSignedTrailer和已认证authTypeStreamingUnsignedTrailer的两个值留空。要求这些值的Allow会误拒合法尾标上传,要求这些值的Deny则可能无法命中。
- 无限期请求头重放与等长内容替换:
- 上游溯源: 由上游 MinIO 于
2023-05-05合入的提交76913a9fd(minio/minio#16484,“Signed trailers for signature v4”)引入;上游在2025-04-03补加无签名尾标验签的提交8c7097528(minio/minio#21103)仍未补齐时间窗口检查。 - 修复方式: 提交
14ecb222e与296c9710b在setAuthMiddleware中对所有携带Authorization请求头的authTypeStreamingUnsignedTrailer请求强制执行 15 分钟X-Amz-Date偏差校验(同时保留公开桶匿名流式上传),补齐请求头签名与流式种子签名的checkUnsignedHeaders校验,并为两种尾标流式模式填入与 AWS S3 规范一致的s3:signatureversion与s3:authType条件值。
一、上游溯源与根因分析
为什么 authTypeStreamingUnsignedTrailer 漏掉了时间窗口校验
在 SILO 及上游 MinIO 的 SigV4 验证分层中,签名校验与时间戳新鲜度校验分属两处:
doesSignatureMatch(cmd/signature-v4.go): 仅解析X-Amz-Date(或Date)用于派生YYYYMMDD签名密钥作用域并核对规范请求 HMAC,本身不检查时间戳是否超出globalMaxSkewTime(15 * time.Minute),默认前置 HTTP 中间件已完成拦截。setAuthMiddleware(cmd/auth-handler.go): 调用parseAmzDateHeader(r),拒绝与服务端当前UTCNow()相差超过 15 分钟的请求(返回ErrRequestTimeTooSkewed)。
当上游在 76913a9fd(2023-05-05)中引入尾标流式模式时,getRequestAuthType 将所有携带 X-Amz-Content-Sha256: STREAMING-UNSIGNED-PAYLOAD-TRAILER 的请求——无论是否携带 Authorization 签名头、还是发往公开可写桶的纯匿名流式上传——统一归类为同一个枚举值 authTypeStreamingUnsignedTrailer。由于匿名请求没有 X-Amz-Date,上游在 setAuthMiddleware 中只把 authTypeStreamingSignedTrailer 加入了分支,漏掉了已认证的 authTypeStreamingUnsignedTrailer:
此后无论是上游 8c7097528(2025-04-03),还是后续针对查询参数认证绕过(CVE-2026-41145)与 Snowball 解包绕过(CVE-2026-40344)的修补,都在 newUnsignedV4ChunkedReader 内调用 reqSignatureV4Verify -> doesSignatureMatch,仅验证了 HMAC 而未检查时钟偏差,导致数月甚至数年前签发的请求头依然能通过验证。
为什么无时间上限在 STREAMING-UNSIGNED-PAYLOAD-TRAILER 下危害尤为突出?如果签名覆盖的 X-Amz-Content-Sha256 包含实际请求体摘要,该摘要会绑定正文内容;规范请求使用无签名载荷标记的模式不具备这项保证。而在 STREAMING-UNSIGNED-PAYLOAD-TRAILER 模式下,签名仅覆盖 Host、X-Amz-Content-Sha256 字面量、X-Amz-Date、X-Amz-Decoded-Content-Length 与 X-Amz-Trailer 尾标名,既不覆盖分块数据,也不覆盖末尾 CRC 校验值本身。攻击者只要拿到一组历史请求头,即可构造任意等长的新内容并自行重算匹配的 CRC 尾标,在未来任意时间静默篡改目标对象。
getConditionValuesWithTags 遗漏尾标流式条件键
在 cmd/bucket-policy.go 的 getConditionValuesWithTags 中,填充 s3:signatureversion 与 s3:authType 的 switch 语句停留在尾标流式出现之前的三种枚举(authTypeSigned、authTypePresigned、authTypeStreamingSigned)。由于当前主流 AWS SDK(Go v2、Java v2、Python boto3、JS v3)在上传对象时默认开启 CRC32 / CRC64NVME 尾标校验,发出的请求普遍采用 authTypeStreamingSignedTrailer 或 authTypeStreamingUnsignedTrailer,导致服务端策略引擎读到的这两个条件键始终为空。
二、影响范围
| 涉及接口 / 策略场景 | 具体影响说明 |
|---|---|
PutObject、PutObjectPart、PutObjectExtract 写入 |
被日志记录或截获的已认证 STREAMING-UNSIGNED-PAYLOAD-TRAILER 请求头在密钥有效期内可被无限期重放,并以等长任意内容覆写目标路径(除非目标受对象锁保护)。 |
使用 s3:signatureversion 或 s3:authType 的访问策略 |
以 AWS4-HMAC-SHA256 / REST-HEADER 为匹配条件的规则,在这些条件值为空时无法匹配尾标流式上传。 |
发往公开桶的纯匿名 aws-chunked 流式上传 |
修复前后均不受影响(匿名请求不携带 Authorization 头)。 |
三、修复方案:设计思考与充分必要性
提交 14ecb222e 与 296c9710b 在认证入口、流式验签与策略上下文构造处精确补齐了协议契约:
setAuthMiddleware按是否携带认证头执行 15 分钟窗口检查(cmd/auth-handler.go): 当aType == authTypeStreamingUnsignedTrailer且r.Header.Get(xhttp.Authorization) != ""时,中间件在进入处理器或分块读取器前执行parseAmzDateHeader(r)与 15 分钟时钟偏差校验。缺失日期返回400 AccessDenied,畸形日期返回400 MalformedDate,超出时间窗返回403 RequestTimeTooSkewed。没有Authorization的请求仍按匿名请求处理,并须通过newUnsignedV4ChunkedReader的桶策略鉴权。getConditionValuesWithTags补齐尾标流式条件键(cmd/bucket-policy.go):authTypeStreamingSignedTrailer:填入s3:signatureversion = "AWS4-HMAC-SHA256"与s3:authType = "REST-HEADER";- 携带
Authorization的authTypeStreamingUnsignedTrailer:填入s3:signatureversion = "AWS4-HMAC-SHA256"与s3:authType = "REST-HEADER"; - 不携带
Authorization的匿名authTypeStreamingUnsignedTrailer:将s3:signatureversion与s3:authType的条件值保持为空,防止匿名请求在策略求值中冒充 SigV4 签名请求。
为什么该修改既必要又充分
- 必要性: 若不区分
Authorization != ""而对全部authTypeStreamingUnsignedTrailer一刀切调用parseAmzDateHeader,会直接破坏向公开可写桶发送的不带X-Amz-Date的合法匿名aws-chunked上传(cmd/streaming-auth-boundary_test.go对此有专门回归覆盖)。而由于STREAMING-UNSIGNED-PAYLOAD-TRAILER搭配 URL 查询参数预签名已在CVE-2026-41145中明令禁止,因此检查Authorization != ""已 100% 覆盖所有持凭据的无签名尾标请求。 - 充分性: 在全局入口中间件
setAuthMiddleware拦截时间偏差,可一次性覆盖PutObjectHandler、PutObjectPartHandler、PutObjectExtractHandler等所有接收流式上传的路由,确保超期请求在读取任何主体字节前即被拒绝。
四、利弊权衡、潜在代价与边界
| 权衡维度 | 工程取舍与残余边界说明 |
|---|---|
| 客户端时钟同步要求 | 使用 STREAMING-UNSIGNED-PAYLOAD-TRAILER 的已认证客户端若本机时钟与服务端 UTC 偏差超过 15 分钟,现在会与普通 SigV4 请求及 AWS S3 一致返回 RequestTimeTooSkewed。 |
显式限定 s3:authType 的策略 |
已认证的带签名尾标与无签名尾标请求均使用 REST-HEADER;已包含该值的白名单无需添加尾标专用值。区分载荷模式应使用 s3:x-amz-content-sha256。 |
| 15 分钟窗口内的明文传输风险 | 无签名尾标模式在合法时间窗内也没有逐块密码学签名,应使用 TLS。若要拒绝此模式,对 s3:PutObject 添加 Deny,以 StringEquals 匹配 s3:x-amz-content-sha256 的 STREAMING-UNSIGNED-PAYLOAD-TRAILER 值。该规则只禁用这一载荷模式,不代表已禁用所有其他无签名载荷模式。 |
升级与加固建议
- 升级 SILO Server 至包含提交
14ecb222e与296c9710b的20261109后续发布版本。 - 强制启用 HTTPS 并脱敏访问日志: 确保 S3 接入层全程使用 TLS,且反向代理与调试日志不落盘明文
Authorization请求头。 - 可选策略加固(禁用无签名尾标载荷): 在 IAM 或桶策略中为
s3:PutObject添加Deny,条件为StringEquals: {"s3:x-amz-content-sha256": "STREAMING-UNSIGNED-PAYLOAD-TRAILER"}。模式标记属于载荷条件值;已认证尾标请求的s3:authType = "REST-HEADER"。请用实际上传客户端验证策略效果。
更多信息请参阅安全公告台账、CVE-2026-41145、CVE-2026-40344 与签名头覆盖设计(SN-2026-011)。