模块验证
当 go
命令下载模块 zip 文件或 go.mod
文件进入 module 缓存,它计算加密哈希并将其与比较已知的值以验证文件未在首次下载以来未更改。如果下载的文件没有正确的哈希,则 go
命令报告安全错误。
对于 go.mod
文件,go
命令计算文件内容中的哈希值。对于模块 zip 文件,go
命令以确定性顺序计算档案中档案中文件的名称和内容的哈希。哈希不受文件订单,压缩,对齐和其他元数据的影响。请参阅 golang.org/x/mod/sumdb/dirhash
用于哈希实现细节。
go
命令将每个哈希与主模块的 go.sum
文件进行比较。如果哈希与 go.sum
中的散列不同,则 go
命令报告安全错误,并删除下载的文件,而无需将其添加到模块缓存中。
如果不存在 go.sum
文件,或者如果它不包含下载文件的哈希值,则 go
命令可以使用 checksum 数据库验证哈希是公开的模块的全球散列来源。验证哈希后,go
命令将其添加到 go.sum
并在模块缓存中添加下载的文件。如果模块是私有的 (由 GOPRIVATE
或 GONOSUMDB
环境变量) 或禁用 (通过设置 GOSUMDB=off
),go
命令接受哈希并将文件添加到模块缓存,而无需验证它。
模块缓存通常由系统上的所有 Go 项目共享,每个模块都可能拥有自己的 go.sum
文件,具有潜在的不同的哈希。为避免需要信任其他模块,请使用主模块的 go.sum
验证哈希验证哈希值,只要它访问模块缓存中的文件。 zip 文件哈希花费昂贵,因此 go
命令检查与 zip 文件一起存储的预计算机哈希,而不是重新散列文件。 go mod verify
命令可以用于检查 zip 文件并提取的目录尚未修改以来添加到模块缓存中。
go.sum 文件#
模块可以在其根目录中具有名为 go.sum
的文本文件,以及其 go.mod
文件。go.sum
文件包含模块直接和间接依赖项的加密散列。当 go
命令下载模块.mod
或.zip
文件到 module 缓存,它计算哈希并检查哈希匹配主模块的 go.sum
文件中的相应散列。go.sum
如果模块没有依赖关系,或者如果使用 replace
指令。
在 go.sum
中的每一行有三个字段由空格分隔:模块路径,一个版本 (可能以 /go.mod
) 和哈希。
- 模块路径是哈希属于的模块的名称。
- 版本是哈希属于模块的版本。如果版本以
/go.mod
结尾,则散列仅用于模块的go.mod
文件;否则,散列是模块的.zip
文件中的文件。 - 散列列由算法名称 (如
h1
) 和由冒号分开的 Base64 编码的加密散列 (:
)。目前,SHA-256 (H1
) 是唯一受支持的散列算法。如果在将来发现了 SHA-256 中的漏洞,将为另一种算法添加支持 (名为H2
等)。
go.sum
文件可以包含模块的多个版本的哈希。go
命令可能需要从多个版本的依赖关系加载 go.mod
文件以执行最小版本选择。go.sum
也可以包含不再需要的模块版本的哈希 (例如,升级后)。 go mod tidy
将添加缺少哈希物,并将从 go.sum
中删除不必要的哈希。
Checksum 数据库#
校验和数据库是 go.sum
行的全局源。go
命令可以在许多情况下使用它来通过代理或原点服务器来检测不当行为。
校验和数据库允许所有公开可用的模块版本的全局一致性和可靠性。它可以使不受信任的代理可以在没有被忽视的情况下为错误的代码提供服务。它还确保与特定版本关联的位不会从一天到下一个日期更改,即使模块的作者随后在其存储库中改变标记。
校验和数据库由 sum.golang.org 提供服务,由谷歌运行。它是 go.sum
行哈希的透明日志 (或「Merkle Tree」),由 trillian 支持的行哈希值。 Merkle 树的主要优点是独立审计员可以验证它没有被篡改,所以它比简单的数据库更值得信任。
go
命令在提议:安全公共 GO Module 生态系统中配合检验和数据库使用最初概述的协议。
下表指定了校验和数据库必须响应的查询。对于每个路径,$base
是校验和数据库 URL 的路径部分,$module
是一个模块路径,而 $version
是一个版本。例如,如果校验和数据库 URL 是 https://sum.golang.org
,并且客户端正在请求模块 golang.org/x/text
的记录 v0.3.2
,客户端将向 https://sum.golang.org/lookup/golang.org/x/text@v0.3.2
发送 GET
请求。
为了避免在不敏感的文件系统服务时避免歧义,$module
和 $version
元素是案例编码通过用感叹号替换每个大写字母,然后替换相应的小写字母。这允许模块 example.com/m
和 example.com/m
两者都存储在磁盘上,因为前者被编码为 example.com/!m
。
由方括号围绕的路径的部分,如 [.p/$W]
表示可选值。
路径 | 描述 |
---|---|
$base/latest |
返回最新日志的已签名的编码树描述。此签名的描述是一种注意的形式,该文本是由一个或多个服务器密钥签名的文本可以使用服务器的公钥验证。树描述提供树的大小和树头的哈希。此编码在 [golang.org/x/mod/sumdb/tlog#FormatTree](https://pkg.go.dev/golang.org/x/mod/sumdb/tlog#FormatTree) |
$base/lookup/$module@$version |
返回关于 $module 在 $version 的条目的日志记录编号,然后是记录的数据 (即,go.sum 行 $module 在 $version 上,包含记录的符号编码树描述。 |
$base/tile/$H/$L/$K[.p/$W] |
返回日志标题,这是一组构成日志部分的哈希值。每个瓦片在瓷砖级别 $L , $K th 的二维坐标,左侧,带有瓷砖高度 $H 。可选的.p/$W 后缀表示一个只有 $W 哈希值的部分日志图块。如果找不到部分磁贴,则客户端必须重新返回以获取全部磁贴。 |
$base/tile/$H/data/$K[.p/$W] |
返回 /tile/$H/0/$K[.p/$W] 中叶窝的记录数据 (有文字 data 路径元素)。 |
如果 go
命令查询校验和数据库,则第一步是通过 /lookup
端点检索记录数据。如果在日志中尚未记录模块版本,则校验和数据库将尝试在回复之前从原始服务器获取它。这 /lookup
数据为此模块版本提供了总和,以及其在日志中的位置,这通知客户端应该获取哪个举证以执行证明。go
命令执行「包含」证明 (在日志中存在特定的记录) 和「一致性」证明 (在添加新的 Go.Sum
之前,树尚未篡改) 主模块的 go.sum
文件。重要的是,来自 /lookup
的数据应该永远不应该使用,而无需先对符号树哈希验证并对客户端的签名树哈希的时间表进行身份验证签名的树哈希。
托管箱数据库服务的符号树哈希和新块存储在模块缓存中,因此 go
命令只需要获取丢失的图块。
go
命令不需要直接连接到校验和数据库。它可以通过镜像校验和数据库 来请求模块副本支持上面的协议。这对于私人的公司代理特别有帮助,该公司代理阻止组织外部的请求。
GOSUMDB
环境变量标识要使用和可选的公钥和 URL 的校验和数据库的名称,如下所示:
GOSUMDB="sum.golang.org"
GOSUMDB="sum.golang.org+<publickey>"
GOSUMDB="sum.golang.org+<publickey> https://sum.golang.org"
go
命令知道 sum.golang.org
的公钥,也是名称 sum.golang.google.cn
(在中国大陆内提供) 连接到 sum.golang.org
校验和数据库;使用任何其他数据库需要明确给出公钥。 URL 默认为 https://
后跟数据库名称。
GOSUMDB
默认为 sum.golang.org
,Google 运行的 Go Checksum 数据库。查看 sum.golang.org/privacy 为服务的隐私政策。
如果将 GOSUMDB
设置为 off
,或者使用 -insecure
标志调用 go get
,则不会查阅校验和数据库,所有无法识别的模块都被接受,以提供所有模块的已验证可重复下载的安全保证。一种更好的方法来绕过特定模块的校验和数据库是使用 GOPRIVATE
或 GOSUMDB
环境变量。有关详细信息,请参阅 Private Modules。
go env -w
命令可以用于设置这些变量备份 go
命令调用。
本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
推荐文章: