写点什么

Go 如何减少供应链攻击?

  • 2022-04-26
  • 本文字数:2599 字

    阅读完需:约 9 分钟

Go 如何减少供应链攻击?

现代软件工程是协作性的,并且基于对开源软件的重用。这就使目标暴露在供应链攻击之下,而软件项目则会因为其依赖性被破坏而遭到攻击。


无论采用何种过程或技术手段,每个依赖性都必然存在着相互信任的关系。但是,Go 的工具和设计帮助降低了所有阶段的风险。

所有构建都已“锁定”


外部世界的变化,例如发布依赖性的新版本,并不会影响 Go 的构建。


与大多数软件包管理器文件不同,Go 模块没有单独的约束列表和锁文件,但是它锁定了某个特定的版本。任何 Go 构建的每个依赖性的版本完全取决于主模块的 go.mod 文件。


从 Go 1.16 开始,这种决定论就会强制执行,并且在 go.mod 不完整的情况下,构建命令(gobuild、gotest、goinstall、gorun……)将会失败。唯一会改变 go.mod(因此也会改变构建)的命令是 goget 和 gomodtidy。这些命令不会被自动或在 CI 中运行,所以对依赖树的改变必须是故意的,并且有机会通过代码审查。


这对安全非常重要,因为当 CI 系统或新机器运行时,签入 (checked-in) 的源码是最终的和完整的,代码将说明什么会被构建,第三方没有办法影响它。


此外,当用 goget 添加依赖性时,由于最小版本的选择,它的交叉依赖会按照依赖的 go.mod 文件中指定的版本添加,而不是按照最新版本。同样的情况也发生在调用 goinstallexample.com/cmd/devtoolx@latest 的情况下,在某些生态系统中,它的等价物会绕过 pinning。在 Go 中,example.com/cmd/devtoolx 的最新版本将被获取,但所有的依赖性将由其 go.mod 文件设置。


如果一个模块被破坏,新的恶意版本被发布,在它们明确更新该依赖性之前,不会受到任何影响,这就提供了审查更改的机会,并让生态系统有了足够的时间来检测事件。

版本内容永远不会改变


确保第三方不能影响构建的另一个关键属性是,模块版本的内容是不可改变的。如果攻击者破坏了依赖性,可以重新上传现有的版本,他们就可以自动破坏所有依赖它的项目。


这就是 go.sum 文件的作用。它包含构建所需的每个依赖项的加密哈希列表。同样,一个不完整的 go.sum 会导致错误,而且只有 goget 和 gomod tidy 才会修改它,所以任何对它的修改都会伴随着故意的依赖性改变。其他的构建被保证有一套完整的校验和。


这是大多数锁文件的一个共同特征。Go 通过 Checksum Database(简称 sumdb)超越了它,它是一个全局性的、仅可附加的加密验证的 go.sum 条目列表。当 goget 需要在 go.sum 文件中添加一个条目时,它从 sumdb 中获取该条目,并对 sumdb 的完整性进行加密证明。这不仅确保了某一模块的每一次构建都使用相同的依赖内容,而且确保了每一个模块都使用相同的依赖内容。


sumdb 使得被破坏的依赖内容,甚至谷歌运营的 Go 基础设施不可能用修改过的(例如 backdoored)源代码来针对特定的依赖内容。保证你使用的代码与其他使用例如 example.com/modulex 的 v1.9.2 的人所使用的代码完全一样,并且已通过审查。


最后,我最喜欢 sumdb 的特性是:它不需要模块作者的任何密钥管理,并且可以无缝地与 Go 模块的去中心化特性配合使用。

VCS 是真理的源泉


大多数项目是通过某种版本控制系统(VCS)开发的,然后在其他生态系统中,上传到包存储库。这意味着有两个账户可能被入侵,即 VCS 主机和包存储库,后者使用得更少,更容易被忽视。这也意味着在上传到存储库的版本中更容易隐藏恶意代码,尤其是在上传过程中经常修改源代码的情况下,比如说将其最小化。


在 Go 中,不存在包存储库账户这样的东西。包的导入路径嵌入了 gomoddownload 所需要的信息,以便直接从 VCS 中获取其模块,其中标签定义了版本。


我们确实有 Go Module Mirror,但那只是一个代理。模块作者不需要注册账户,也不需要向代理上传版本。代理使用与 go 工具相同的逻辑(事实上,代理运行 gomoddownload)来获取和缓存版本。由于校验数据库保证给定的模块版本只能有一个源树,每个使用代理的人都会看到与绕过代理直接从 VCS 获取的结果相同。(如果该版本在 VCS 中不再可用,或者其内容发生了变化,直接获取将导致错误,而从代理获取可能仍然有效,提高了可用性并保护生态系统免受 “左键”问题的影响)。


在客户端运行 VCS 工具会暴露出一个相当大的攻击面。这也是 Go Module Mirror 的另一个作用:代理上的 Go 工具在一个强大的沙盒内运行,并被配置为支持所有的 VCS 工具,而默认的是只支持两个主要的 VCS 系统(git 和 Mercurial)。任何使用代理的人仍然可以获取使用非默认的 VCS 系统发布的代码,但攻击者在大多数安装中无法接触到这些代码。

仅构建代码,但不会执行它


Go 工具链的一个清晰的安全设计目标是,即使代码是不可信和恶意的,也不能获取或构建代码来执行该代码。这与大多数生态系统不同,其中许多生态系统对在获取包时运行代码提供了一流的支持。这些“安装后”的钩子在在过去被用作一种最方便的攻击方式:通过受到攻击的依赖攻击开发者的机器,并通过 module 作者进行蠕虫攻击。


公平地说,如果你要获取一些代码,往往会在不久之后执行,要么作为开发者机器上测试的一部分,要么作为生产中二进制文件的一部分,所以缺乏安装后钩子只会减缓攻击者。(在构建过程中没有安全边界:任何有助于构建的软件包都可以定义一个初始函数)。然而,这也是一种有意义的风险缓解,因为你可能在执行一个二进制文件或测试一个包时,只使用了模块依赖的一个子集。例如,如果你在 macOS 上构建并执行 example.com/cmd/devtoolx,那么只有 Windows 的依赖或 example.com/cmd/othertool 的依赖就不可能危害到你的机器。


在 Go 中,不为特定构建提供代码的模块对其没有安全影响。

“一点复制比一点依赖要好”


在 Go 生态系统中,最后一个也许也是最重要的软件供应链风险缓解措施是最没有技术含量的一个:Go 有一种拒绝大型依赖树的文化,宁愿复制一下也不愿意添加新的依赖。这可以追溯到 Go 的一个谚语:“一点复制比一点依赖要好”。高质量的可重用 Go 模块自豪地戴上了 “零依赖” 的标签。如果你发现自己需要一个库,你很可能会发现它不会导致你依赖其他作者和所有者的几十个模块。


丰富的标准库和其他模块(golang.org/x/……的模块)也支持这一点,这些模块提供了常用的高级构建模块,如 HTTP 栈、TLS 库、JSON 编码等。


所有这些意味着只需少量的依赖性就可以建立丰富、复杂的应用程序。无论工具有多好,它都不能消除重复使用代码的风险,所以最有力的缓解措施永远是一个小的依赖树。


原文链接:


https://go.dev/blog/supply-chain

2022-04-26 14:0712644

评论

发布
暂无评论
发现更多内容

极客训练营知识点思维导图

jorden wang

[5/28]产品运维保障体系的质量实践

L3C老司机

解读容器的 2020:寻找云原生的下一站

阿里巴巴云原生

Docker 云计算 Serverless 容器 云原生

一文带你学会AQS和并发工具类的关系

伯阳

AQS java 并发 ReentrantLock 多线程高并发 lock锁

超越身边80%的人,其实没有你想象的那么难

架构精进之路

认知提升 成长笔记 七日更 28天写作

百度面试被算法血虐,闭关29天肝完445页算法神仙笔记成功入职字节跳动!

Java架构之路

Java 程序员 架构 面试 编程语言

矿机挖矿软件系统开发|矿机挖矿APP开发

系统开发

架构师第八周总结

Geek_xq

使用 kubectl-rabbitmq 部署和运维 K8S 上的 RabbitMQ 集群

郭旭东

RabbitMQ kubectl kubectl plugin

从姚安娜出道说起

三只猫

28天写作 社交泛娱乐

2021字节、华为、滴滴Java内部面试题(含答案),新鲜出炉!

比伯

Java 编程 架构 面试 程序人生

APICloud AVM多端开发 |《生鲜电商app开发》项目源码教程

YonBuilder低代码开发平台

大前端 移动开发 APP开发 APICloud

智能量化对冲搬砖套利交易软件APP系统开发

系统开发

Java 程序经验小结:剖析@SuppressWarinings注解

后台技术汇

28天写作

架构师训练营第十三周笔记

李日盛

笔记

华云大咖说|企业混合云构建之道

华云数据

云计算 桌面云

安卓开发实战!闭关在家37天“吃透”这份345页PDF,成功定级腾讯T3-2

欢喜学安卓

android 程序员 面试 移动开发

架构师第8周作业

Geek_xq

电商网站商品管理(二)多种搜索方式

escray

elasticsearch elastic 28天写作 死磕Elasticsearch 60天通过Elastic认证考试

Soul 网关源码阅读(三)请求处理概览

Java 源码阅读 网关

Nginx 的负载均衡模式有哪些?它的实现原理是什么?

李尚智

nginx 架构 微服务

2021年,字节/百度/阿里相继发布50W+优质Java岗(含内部面试真题及答案)

996小迁

Java 程序员 架构 面试

PHP转JAVA开发30分钟实战攻略

dothetrick

Java php

训练营第十三周作业

大脸猫

在GitHub中向开源项目提交PR的过程

worry

GitHub pull request

Soul 网关源码阅读(二)代码初步运行

Java 源码阅读 网关

GitHub标星150K的神仙笔记,3个月肝完成功面进美团定级3-2

Java架构之路

Java 程序员 架构 面试 编程语言

Soul 网关源码阅读(四)Dubbo请求概览

Java 源码阅读 网关

技术人员如何写好周报

猿话

技术创新是PC市场发展基石,英特尔占据明显领先优势

E科讯

二本学渣考研失败,为什么Android要采用Binder作为IPC机制?已开源

欢喜学安卓

android 程序员 面试 移动开发

Go 如何减少供应链攻击?_文化 & 方法_Filippo Valsorda_InfoQ精选文章