同一个URL,两种不同的理解——CVE-2026-42882s3-proxy认证绕过的三条路径

admin 2026-05-19 05:26:04 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: CVE-2026-42882披露了s3-proxy认证绕过漏洞(CVSS9.4),根源在于认证层与存储层对URL路径解析不一致。攻击者通过通配符跨段匹配、百分号编码斜杠注入、点段路径遍历三种技术无需凭证即可访问受保护S3对象。官方在v5.0.0中统一路径解析逻辑并修复glob语义,建议用户立即升级并检查配置中通配符使用。 综合评分: 89 文章分类: 漏洞分析,WEB安全,解决方案,安全工具,云安全


cover_image

同一个 URL,两种不同的理解——CVE-2026-42882 s3-proxy 认证绕过的三条路径

原创

CVE-SEC CVE-SEC

CVE-SEC

2026年5月12日 12:00 新疆

在小说阅读器读本章

去阅读

同一个 URL,两种不同的理解——CVE-2026-42882 s3-proxy 认证绕过的三条路径

CVE-2026-42882 | CVSS 9.4 | 严重


前言

安全代理的核心承诺是:我来做认证决策,你只需要告诉我请求该不该通过。这个承诺成立的前提是,做出决策的那一层和执行操作的那一层,对同一个请求”看到的是同一件事”。

CVE-2026-42882 击穿的正是这个前提。

oxyno-zeta/s3-proxy 是一个用 Go 编写的 AWS S3 反向代理,它的认证中间件和存储处理器对同一个请求 URL 使用了不同的内部表示。攻击者可以构造出一个 URL,让认证层认为它属于开放路由,让存储层实际操作受保护的 S3 对象——不需要任何凭据,不需要任何账户,只需要知道目标路径的命名规律,加上几个特殊字符。

这个漏洞包含三种独立的绕过技术,每一种对应 URL 处理的一个不同层面,CVSS 评分 9.4,研究人员 argos83 发现并报告,2026 年 5 月修复。


s3-proxy 是什么,它的认证模型怎么工作

s3-proxy 的设计目标是为 AWS S3 存储桶提供访问控制层。在没有它的情况下,直接暴露 S3 存储桶意味着要么完全公开,要么依赖 AWS IAM 策略做细粒度控制。s3-proxy 充当中间层,允许管理员用更直观的配置文件为不同的路径前缀配置不同的访问策略:

targets:
  - name: my-bucket
    resources:
      - path: /public/**
        whiteList: true         # 无需任何认证

      - path: /internal/**
        basic:
          realm: "Internal"
          credentials:
            - user: alice
              password: secret  # 需要 Basic 认证

认证逻辑在中间件层实现:HTTP 请求进来后,中间件提取请求路径,与配置的资源路径模式做 glob 匹配,决定这个请求落在哪个策略下,是否需要认证。如果匹配到 whiteList: true 的路径,请求直接放行;如果匹配到需要认证的路径,验证凭据。

通过了认证层,请求才到达存储处理器,由处理器根据请求路径构建 S3 对象键,调用 AWS S3 API 执行实际操作。

问题就在这两个层之间。


Go 的 URL 解析与安全裂缝

理解这个漏洞,需要先了解 Go 的 net/http 包如何处理请求 URL。

当 HTTP 请求到达 Go 服务器时,请求的 URL 信息被解析并存储在 r.URL 结构体中。这个结构体有几个不同的字段,对同一个 URL 有不同的表示:

  • r.URL.Path:已将 %2F 解码为 /,并对 ../ 等点段进行了路径归一化,是”干净”的路径
  • r.URL.RawPath:保留原始编码形式,%2F 仍为 %2F../ 仍为 ../
  • r.URL.RequestURI():返回编码形式,接近 RawPath

s3-proxy 的认证中间件使用 r.URL.RequestURI() 获取路径进行 glob 匹配,而存储处理器使用 r.URL.Path 构建 S3 对象键。

一个在 RequestURI() 看来属于 /public/foo 的路径,在 r.URL.Path 看来可能是 /internal/secret

这就是漏洞的根基。


三种绕过技术

技术一:通配符跨段匹配

第一个问题来自 glob 库的调用方式。s3-proxy 使用 github.com/gobwas/glob 库进行路径模式匹配,但调用时没有传入路径分隔符参数:

// 漏洞代码
g, err := glob.Compile(res.Path)  // 没有 '/' 分隔符

gobwas/glob 库在没有分隔符参数的情况下,通配符 * 等价于”任意字符序列”,包括路径分隔符 /。这意味着模式 /upload/*/drafts/ 中的 * 不只匹配单个路径段,而可以匹配 foo/drafts/../restricted 这整个字符串。

假设配置如下:

- path: /upload/*/drafts/    # 无需认证
- path: /upload/*/restricted/ # 需要认证

攻击者发送:

PUT /upload/foo/drafts/../restricted/secret.txt

认证中间件用无分隔符的 glob 进行匹配,* 匹配了 foo/drafts/../restricted 整段,模式 /upload/*/drafts/ 命中,判断无需认证,请求放行。存储处理器拿到 r.URL.Path,此时 Go 已将路径归一化为 /upload/foo/restricted/secret.txt,文件被写入受保护的命名空间。

技术二:百分号编码斜杠注入

即使第一个问题被修复了(glob.Compile(res.Path, '/') 添加分隔符,限制 * 只匹配单段),第二个问题仍然独立存在。

考虑请求路径 /upload/foo%2Frestricted/drafts/,认证中间件和存储处理器对它的”理解”截然不同:

| 处理层 | 看到的路径 | 路径段 | | — | — | — | | 认证中间件(RequestURI) | /upload/foo%2Frestricted/drafts/ | uploadfoo%2Frestricted / drafts | | 存储处理器(r.URL.Path) | /upload/foo/restricted/drafts/ | uploadfoo / restricted / drafts |

%2F 是斜杠 / 的百分号编码形式。在认证中间件看来,它是一个包含字面百分号的路径段的一部分;在存储处理器看来,Go 已将它解码为 /,变成了一个真实的路径分隔符。

结果:认证中间件将路径匹配到开放的 /upload/*/drafts/ 路由,认为无需认证;存储处理器实际操作的是 /upload/foo/restricted/drafts/...,命中了受保护的命名空间。

RFC 3986 §2.2 明确规定 / 和 %2F 在 URI 路径中语义不同——/ 是段分隔符,%2F 是段内数据。Go 的 r.URL.Path 在解码时将两者混同,是这个问题的技术背景。

技术三:点-点段路径遍历

第三个绕过最简单也最直接。

假设配置:

- path: /open/**       # 无需认证
- path: /restricted/** # 需要认证

攻击者发送:

GET /open/../restricted/secret.json

认证中间件拿到 RequestURI() 的原始路径 /open/../restricted/secret.json,对模式 /restricted/** 尝试匹配——它看到的路径不以 /restricted/ 开头,不匹配;对 /open/** 尝试匹配——** 匹配 ../restricted/secret.json,命中开放路由,放行。

存储处理器拿到 r.URL.Path,Go HTTP 库在解析 URL 时已经完成了点段归一化:/open/../restricted/secret.json 变成了 /restricted/secret.json。S3 API 被调用,操作落在受保护的 restricted/ 命名空间。

这个技术已在 AWS S3 实际环境中验证有效。


三个漏洞的共同根源

三种绕过技术表面上利用的是不同的技术细节,但本质上来自同一个根本问题:认证决策和实际操作使用了对同一请求 URL 的不同表示

安全代理的正确工作模式应当是:你在哪个路径表示上做安全决策,就在同一个路径表示上执行操作。任何允许”安全层看到一个路径,操作层用另一个路径”的设计,都在为这类攻击创造空间。

这类漏洞在代理、网关、中间件类安全组件中有相当高的出现频率。URL 解析在不同库、不同语言实现之间的细微差异,为攻击者提供了丰富的操作空间。


攻击的完整路径

以技术三为例,完整的利用过程如下:

# 验证受保护路径无法直接访问(预期返回 401)
curl -v&nbsp;"http://<target>/restricted/confidential.txt"

# 利用点-点段遍历绕过认证(预期返回 200 及文件内容)
curl -v&nbsp;"http://<target>/open/../restricted/confidential.txt"

# 向受保护路径写入数据
curl -X PUT&nbsp;"http://<target>/open/../restricted/attacker.txt"&nbsp;\
&nbsp; --data&nbsp;"injected content"

# 删除受保护路径的数据
curl -X DELETE&nbsp;"http://<target>/open/../restricted/important.txt"

认证层全程看到的是 /open/...,判断无需认证;S3 实际操作的是 /restricted/...


为什么部署者难以察觉这个问题

s3-proxy 通常作为 Kubernetes 集群内部的服务运行,网络访问已经受到一定限制。但”在内部网络”不等于”没有安全风险”——集群内的任何服务、任何已获得集群网络访问权限的攻击者,都可以利用这个漏洞绕过 s3-proxy 的访问控制。

对于将 s3-proxy 用于保护敏感数据(私钥、用户数据、配置文件、凭据)的部署,这意味着认证机制在实际意义上已经失效。

更令运维人员难以察觉的是,这类绕过请求在 HTTP 访问日志中不会显示为认证失败——它们通过了认证,返回 200 或 204,看起来和正常请求毫无区别。如果没有在 S3 访问日志(CloudTrail 或 MinIO 审计日志)层面进行监控,这类操作几乎不会留下任何可见的异常痕迹。


官方修复

v5.0.0 对三个问题分别实施了针对性修复,整体策略是统一两个处理层对 URL 路径的理解:

修复一(glob 分隔符):

// 修复:传入 '/' 作为路径分隔符
g, err := glob.Compile(res.Path,&nbsp;'/')

* 的语义从”任意字符序列”变更为”单个路径段内的任意字符”,恢复了路径层级的安全边界。

修复二(路径表示统一): 认证中间件和存储处理器统一使用 r.URL.EscapedPath(),遵循 RFC 3986 规范,%2F 不再被解码为 /,两层看到的路径表示一致。

修复三(路径归一化中间件): 在请求进入认证流程前,新增 cleanPathMiddleware,对路径应用 path.Clean() 归一化,消除点段遍历。认证和存储都看到已归一化后的同一条路径。

这三个修复共同确保:在整个请求处理链中,所有层对路径的理解是一致的。

需要注意的破坏性变更: v5.0.0 中 * 的语义发生变化。升级前如果配置中有依赖 * 跨段匹配的路径模式,需要将其更改为 **


检测与缓解

如果无法立即升级,可以在前置代理层过滤可疑请求:

# Nginx 配置示例
if ($request_uri ~* "(%2[Ff]|\.\./|\.\.%2[Ff])") {
&nbsp; &nbsp; return 400;
}

检测是否已遭利用,应在 AWS CloudTrail 或 MinIO 审计日志中检查:

  • 对受保护 S3 前缀的意外访问,尤其是来自 s3-proxy 服务 IP 但对应 s3-proxy 日志中没有认证记录的操作
  • 请求路径中包含 %2F../..%2F 的历史记录

结语

CVE-2026-42882 提出了一个关于安全代理设计的基础问题:当认证层和操作层对同一个输入有不同的理解时,安全保证是脆弱的。这不是一个只影响 s3-proxy 的问题,而是任何在中间件架构中将安全决策和实际操作分层实现的系统都需要认真对待的问题。

三种绕过技术覆盖了 URL 处理的三个不同层面——glob 语义、百分号编码、点段归一化——每一种在历史上都曾在其他系统中被独立利用过。它们同时出现在一个项目中,说明在设计和代码审查阶段,URL 解析的安全含义没有得到足够的重视。

所有 oxyno-zeta/s3-proxy 用户应立即升级至 v5.0.0,并在升级后检查配置文件中使用 * 的路径模式,必要时更新为 **


参考资料

  • GitHub Security Advisory: https://github.com/oxyno-zeta/s3-proxy/security/advisories/GHSA-rfgq-wgg8-662p
  • NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-42882
  • 修复 Commit 1: https://github.com/oxyno-zeta/s3-proxy/commit/1320e4abd46ad18c2851fedde50dbb79df8b7a51
  • 修复 Commit 2: https://github.com/oxyno-zeta/s3-proxy/commit/af5ff57d8c6022459495b8fb50130073bca7b48a

免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:CVE-SEC CVE-SEC CVE-SEC《同一个 URL,两种不同的理解——CVE-2026-42882 s3-proxy 认证绕过的三条路径》

评论:0   参与:  0