哈希证明的是字节,而非来源

Lobsters Hottest 工具

摘要

Collider 1.3.0 为仓库索引添加了路径遍历保护,并在跨域重定向时移除 Bearer 令牌,以防止安全漏洞。

<p><a href="https://lobste.rs/s/oi9vkz/hash_proves_bytes_not_source">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/06/28 20:02

# 哈希证明的是字节,而非来源 来源:https://collider.ee/blog/2026-06-28-1500_a_hash_proves_the_bytes_not_the_source/ [第一篇博文](https://collider.ee/blog/2026-03-09-2328_building_a_package_manager/) 介绍了 Collider 如何验证依赖关系: `collider lock` 会记录每个 wrap 的 SHA-256 哈希,Collider 在安装时检查该哈希,Meson 在解压时检查归档文件的哈希,并且每个锁定的包都固定到其解析来源的 `origin`。这覆盖了内容层面:Collider 构建的字节与锁文件记录的字节一致。但它没有涵盖 Collider 如何决定获取哪些字节,以及如何获取这些字节。选择包的名字、定位包的 URL 以及传递包的跳转,这些都发生在有东西可哈希之前。 Collider 1.3.0 修复了两个地方,在这些地方,不可信输入越过了那条线。 ## 将仓库索引视为不可信输入 ¶ (https://collider.ee/blog/2026-06-28-1500_a_hash_proves_the_bytes_not_the_source/#treating-the-repository-index-as-untrusted-input) 兼容 WrapDB 的仓库提供一个 `releases.json` 索引:包名称映射到版本。Collider 读取它来了解仓库提供哪些包。名称和版本不仅是标签;它们变成了路径: - `subprojects/` - `.wrap` - `~/.config/collider/cache/wraps/` - `_` - `.wrap` - `~/.config/collider/cache/archives/` - `-` 一个名为 `../../../../etc/cron.d/x` 的 `releases.json` 条目是一个相对路径,会逃逸出缓存目录,而 Collider 会将其用作文件名。版本字符串也存在同样的问题。这些值来自仓库 URL 指向的任何服务器,对于公共镜像或同事的主机来说,这并不是 Collider 控制的服务器。在每个使用点(缓存文件前、wrap 前、归档前)进行清理是打地鼠游戏:每一个将名字转换成路径的新地方,都是一个新的容易遗漏的地方。 `packages_from_releases` 是将索引解析为包条目的唯一函数,因此检查放在那里。它会在条目存在之前,拒绝任何不是安全单路径段的名称或版本。`is_safe_path_segment` 拒绝空字符串、`.` 和 `..`、任何包含路径分隔符或空字节的内容,以及 `Path(value).name` 不能保持不变的内容。 读取和写入对被拒绝的段有不同的反应。写入会引发异常:缓存或发布一个遍历名称是一种需要停止的损坏行为。读取则跳过并以 debug 级别记录日志:别人 `releases.json` 中的格式错误条目不应该导致 `collider pkg search` 崩溃。每个路径构建调用处的接收端检查仍作为纵深防御保留,同时也在那里验证 `source_hash`,因为该值通过 wrap 文件而非索引到达。 归档内容也受到同样处理。wrap 指向的归档文件也是不可信输入,一个名为 `../../x` 的成员是另一种逃离目录的方式。当 Collider 解压归档以扫描其 `meson.build` 时,它使用 Python 的 tar 数据过滤器和 zip 模块的路径清理机制,因此精心构造的成员要么落在解压目录内,要么扫描失败。构建时解压到你的项目中是由 Meson 负责的,受归档哈希保护。 ## 跨来源重定向时剥离 bearer token ¶ (https://collider.ee/blog/2026-06-28-1500_a_hash_proves_the_bytes_not_the_source/#stripping-the-bearer-token-on-cross-origin-redirects) `collider publish` 和 `collider unpublish` 会向仓库的写 API 发送一个 bearer token,其命名空间为 `_collider/v1/`。Python 默认的 `urllib` opener 会在重定向时重新发送请求的头信息,其中包括 `Authorization`。一个对推送响应 `302 Location: https://another-host/...` 的仓库会在下一次请求中收到该 token。明文跳转上的中间人攻击者也能收到,因为重定向目标是由攻击者选择的。 经过身份验证的调用会通过 `safe_urlopen`,该函数安装了一个重定向处理器,当重定向改变来源时会丢弃该头信息: ```python def redirect_request(self, req, fp, code, msg, headers, newurl): new_req = super().redirect_request(req, fp, code, msg, headers, newurl) if new_req is None or _origin(req.full_url) == _origin(newurl): return new_req new_req.headers = {k: v for k, v in new_req.headers.items() if k.lower() != 'authorization'} return new_req ``` `_origin` 比较 scheme、主机和端口,默认端口会被规范化,因此 `https://h` 和 `https://h:443` 视为同一来源。同源重定向保留 token;其他情况则丢弃,因此重定向后的请求不带凭证到达,写端点会拒绝它。这是预期的结果。 这并不能保证 token 在传输过程中的安全。`collider serve` 没有 TLS,静态 bearer token 的保密性取决于所在通道;生产部署必须在前面放置一个 TLS 终止的反向代理。重定向修复的范围更窄:它阻止 Collider 将 token 发送给并非其最初认证的主机。 ## 来源证明与签名 ¶ (https://collider.ee/blog/2026-06-28-1500_a_hash_proves_the_bytes_not_the_source/#provenance-and-signing) 经过验证的哈希证明字节与锁文件记录的一致。但它不能证明是谁产生的这些字节。来源固定缩小了范围:锁定的包只从锁定时的仓库 URL 安装,这防止了基本的依赖混淆攻击——用公共包替换私有名称。但来源是一个 URL。它记录的是包从何处获取的,而非谁发布了它。如果该 URL 处的仓库被攻破,或者锁文件是根据被污染索引生成的,哈希仍然会对上。当离线安装回退到缓存时,来源丢失了:正如第一篇博文提到的,缓存无法区分一个 wrap 来自哪个仓库,因此只有内容哈希在那里起作用。 签名是路线图上的下一个项目:发布者签署 wrap 和归档文件,消费者根据一个已信任的密钥验证签名。这将包绑定到可信签名密钥的持有者,而哈希无法做到这一点。 1.3.0 的其他功能(使用 `collider check` 进行漂移检测、预发布版本解析、更严格的发布归档)可在[发布说明](https://github.com/MaxandreOgeret/collider/releases/tag/1.3.0)中找到。 --- 有任何问题?意见?反馈?加入 [GitHub](https://github.com/MaxandreOgeret/collider/discussions) 上的讨论。 \- MOG

相似文章

Exif Smuggling

Hacker News Top

Exif Smuggling 是一种概念验证攻击,它将可执行载荷隐藏在 JPG 的 Exif 数据中,从而通过浏览器图像缓存实现被动下载,无需额外的网络请求。

探究加密推理块

Hacker News Top

作者探究了来自OpenAI和Anthropic的LLM API中的加密推理块,讨论了链式思考数据如何被加密和签名,以及篡改这些块的安全影响。

Referer 的现实困境

Hacker News Top

文章探讨了依赖 Referrer 头来追踪流量来源的局限性,指出许多现代应用程序不再发送此头信息。文章提倡使用自定义查询字符串作为一种数字礼仪,以确保链接归属在不同平台间依然清晰可辨。

在 Transformers.js 中尝试提议的跨源存储 API

Hugging Face Blog

这篇客座文章探讨了提议的跨源存储API,用于改进Transformers.js中AI模型资源的缓存,从而实现跨源的高效复用,同时保持浏览器内推理的隐私和完整性。