go.sum工作机制
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go.sum工作机制相关的知识,希望对你有一定的参考价值。
参考技术A为了确保一致性构建,Go引入了go.mod文件来标记每个依赖包的版本,在构建过程中go命令会下载go.mod中的依赖包,下载的依赖包会缓存在本地,以便下次构建。 考虑到下载的依赖包有可能是被黑客恶意篡改的,以及缓存在本地的依赖包也有被篡改的可能,单单一个go.mod文件并不能保证一致性构建。
为了解决Go module的这一安全隐患,Go开发团队在引入go.mod的同时也引入了go.sum文件,用于记录每个依赖包的哈希值,在构建时,如果本地的依赖包hash值与go.sum文件中记录得不一致,则会拒绝构建。
go.sum文件记录
go.sum文件中每行记录由module名、版本和哈希组成,并由空格分开:
比如,某个go.sum文件中记录了github.com/google/uuid 这个依赖包的v1.1.2版本的哈希值:
正常情况下,每个依赖包版本会包含两条记录,第一条记录为该依赖包版本整体(所有文件)的哈希值,第二条记录表示该依赖包版本中go.mod文件的哈希值,如果该依赖包版本没有go.mod文件,则只有第一条记录。如上面的例子中,v1.1.2表示该依赖包版本整体,而v1.1.2/go.mod表示该依赖包版本中go.mod文件。
依赖包版本中任何一个文件(包括go.mod)改动,都会改变其整体哈希值,此处再额外记录依赖包版本的go.mod文件主要用于计算依赖树时不必下载完整的依赖包版本,只根据go.mod即可计算依赖树。
每条记录中的哈希值前均有一个表示哈希算法的h1:,表示后面的哈希值是由算法SHA-256计算出来的
go.sum文件中记录的依赖包版本数量往往比go.mod文件中要多,这是因为二者记录的粒度不同导致的。go.mod只需要记录直接依赖的依赖包版本,只在依赖包版本不包含go.mod文件时候才会记录间接依赖包版本,而go.sum则是要记录构建用到的所有依赖包版本。
生成
当我们在GOMODULE模式下引入一个新的依赖时,通常会使用go get命令获取该依赖,比如:
go get命令首先会将该依赖包下载到本地缓存目录$GOPATH/pkg/mod/cache/download,该依赖包为一个后缀为.zip的压缩包,如v1.0.0.zip。go get下载完成后会对该.zip包做哈希运算,并将结果存放在后缀为.ziphash的文件中,如v1.0.0.ziphash。如果在项目的根目录中执行go get命令的话,go get会同步更新go.mod和go.sum文件,go.mod中记录的是依赖名及其版本,如:
go.sum文件中则会记录依赖包的哈希值(同时还有依赖包中go.mod的哈希值),如:
在更新go.sum之前,为了确保下载的依赖包是真实可靠的,go命令在下载完依赖包后还会查询GOSUMDB环境变量所指示的服务器,以得到一个权威的依赖包版本哈希值。如果go命令计算出的依赖包版本哈希值与GOSUMDB服务器给出的哈希值不一致,go命令将拒绝向下执行,也不会更新go.sum文件。
go.sum存在的意义在于,希望别人或者在别的环境中构建当前项目时所使用依赖包跟go.sum中记录的是完全一致的,从而达到一致构建的目的。
校验
假设我们拿到某项目的源代码并尝试在本地构建,go命令会从本地缓存中查找所有go.mod中记录的依赖包,并计算本地依赖包的哈希值,然后与go.sum中的记录进行对比,即检测本地缓存中使用的依赖包版本是否满足项目go.sum文件的期望。
如果校验失败,说明本地缓存目录中依赖包版本的哈希值和项目中go.sum中记录的哈希值不一致,go命令将拒绝构建。 这就是go.sum存在的意义,即如果不使用期望的版本,就不能构建。
校验和数据库
环境变量GOSUMDB标识一个checksum database,即校验和数据库,实际上是一个web服务器,该服务器提供查询依赖包版本哈希值的服务。
该数据库中记录了很多依赖包版本的哈希值,比如Google官方的sum.golang.org则记录了所有的可公开获得的依赖包版本。除了使用官方的数据库,还可以指定自行搭建的数据库,甚至干脆禁用它(export GOSUMDB=off)。
如果系统配置了GOSUMDB,在依赖包版本被写入go.sum之前会向该数据库查询该依赖包版本的哈希值进行二次校验,校验无误后再写入go.sum。
如果系统禁用了GOSUMDB,在依赖包版本被写入go.sum之前则不会进行二次校验,go命令会相信所有下载到的依赖包,并把其哈希值记录到go.sum中。
GoCenter 的“火眼金睛” ——检测报告并减少Go Module的安全漏洞
一、背景
Golang开发者非常关心开发应用的安全性。随着Go Module应用越来越广泛,Golang开发者需要更多的方式来确保这些公共共享文件的安全。Golang1.13版本在创建Go Module时,通过增加go.sum文件来验证之后从GOPROXY再次访问到的该Module是否曾被篡改。这个机制有助于保证Module的完整性。但是,当初次创建并提交Go Module时,如果原始文件中被引入了恶意代码,这种安全漏洞还是不能被发现和预警的。
Go Module的安全漏洞影响了很多项目和Go开发者。随着CI/CD流程中“左移”实践的推广,对于Go开发者来说,尽早跟踪和报告Go Module之中的安全漏洞变得越来越重要。幸运的是,GoCenter(https://search.gocenter.io)作为Golang的中央仓库,为Go开发者提供大量公共共享Go Module的同时,也通过集成JFrog Xray安全扫描的能力,帮助Go开发者检测、跟踪并报告仓库中Go Module包含的安全漏洞。
二、报告安全漏洞
任何应用系统,在其开发的生命周期中,都应该持续监视安全漏洞,任何人发现了安全漏洞都应及时报告,以便其修复措施能够被更多的组织和开发者分享与跟踪。已知安全漏洞通常利用CVE(Common Vulnerability and Exposures, 常见漏洞及披露)来分类和跟踪,这是一个用于公开披露安全漏洞信息的列表。每个CVE信息包含一个标准标识序号(CVE ID)、一个状态指示器、对该漏洞的简短描述,以及与漏洞报告及建议相关的索引。
CVE不是漏洞数据库。相反,CVE旨在允许漏洞数据库和其他工具链接在一起,并促进安全工具和服务之间的比较。美国国家漏洞数据库(NVD,National Vulnerability Database)是一个免费的、公开的漏洞数据库,它使用CVE列表的标识序号,并包含漏洞的修复程序、漏洞级别评分,以及其他和每个漏洞相关的信息。
每一个被检测到的安全漏洞都必须报告给CVE编号颁发机构(CNA,CVE Numbering
Authorities),并附上详细的文档解释该漏洞的影响,以及至少一个受影响的代码库,然后才能将其识别为已知漏洞并分配一个CVE ID。作为参考,CVE ID的格式通常为:CVE前缀 + 年 + 任意数字。以下是CVE ID的示例:
三、保护Go Module安全的数据复杂性
确保Go Mudule的安全可能是一项棘手的任务,特别是由于Go Module和Go Package之间的关系。一旦收到Go Module的安全数据,就很难将该数据与特定的Module版本相关联。这是因为安全漏洞存在于Package级别,但是却报告在Module级别上。这可能会给人留下整个Module都容易受到攻击的印象。但事实并非如此,除非您使用易受攻击的Package数据,否则Module将保持安全。
让我们以上图中的CVE-2020-10660 为例。以下是1.3.4版变更日志的摘录,详细介绍了此漏洞的影响:
gopkg.in/hashicorp/vault.v0和github.com/hashicorp/vault都受到了HashiCorp Vault和Vault Enterprise0.9.0到1.3.3版本中的CVE-2020-10660的影响。在使用这些Package时,在某些情况下,它们可能使实体的组成员无意间包含了该实体不再具有权限的组。Vault Enterprise中发现的另一个漏洞是,在某些情况下,现有的嵌套路径策略可能会提供对事后创建的命名空间的访问权限。幸运的是,在版本1.3.4中对这些漏洞进行了修复。
如上例所示,修复是在github.com/hashicorp/vault内进行的。Module
istio.io/istio在其go.mod文件里记录了对github.com/hashicorp/vault的依赖。通常,您会认为istio.io/istio的安全性也会受到威胁。但是它仅仅使用了package github.com/hasicorp/vault/api,因此其代码是不受此漏洞的影响的。请参考下面的源代码:
四、减少软件的安全漏洞
现在您已经了解了如何报告Go
Module安全漏洞的过程,以及有关安全数据复杂性的一些详细信息,让我们看看如何在将来的开发中减少这些威胁。
首先,让我们看一下GoCenter中的Go Module:github/hashicorp/vault。
根据CVE数据,JFrog Xray能够扫描一个go.mod文件里包含的所有在GoCenter中保存的依赖,并识别其中包含的每个安全漏洞。GoCenter在“依赖关系”选项卡上显示这些Xray数据,并提供依赖关系树上各个级别里易受攻击Module的详细信息。您会在每个易受攻击的Module旁边看到一个警示的三角形。然后,您可以单击这些易受攻击的Module并跳转到安全页面。在这里,查看“版本”选项卡可以查找该模块的安全版本,以便您可以在go.mod文件中对其进行升级。
一旦确定了所有组件和依赖项,它们的信息就会与其他漏洞源和数据库进行交叉引用,以提醒您任何潜在的威胁。GoCenter上提供了免费的针对Go Module的基本Xray漏洞扫描,如“安全性”选项卡所示:
五、GoCenter助力Go开发者保持应用安全
GoCenter是公共GOPROXY和中央仓库,具有70万+的Go Module版本。将GoCenter用作GOPROXY时,可以确保下载的代码版本是来自正确源代码的正确版本。GoCenter作为您的GOPROXY可与Go命令无缝协作,并具有安全、快速、可用和存储高效的优势。
许多Golang开发者还可以使用VS Code的免费JFrog扩展,将GoCenter的漏洞信息直接引入其IDE中。
随着CI/CD流程中“左移”实践的推广与落地,GoCenter的安全功能可以帮助您确定要导?的公共Go Module版本中是否存在易受攻击的依赖项,进而帮助您保持开发应用的安全性。
更多技术分享可以关注我们在新课堂
关注微信公众号:JFrog杰蛙DevOps,获取课程通知
以上是关于go.sum工作机制的主要内容,如果未能解决你的问题,请参考以下文章
zookeeper学习03(定义,工作机制,功能,数据结构,应用场景,选举机制)