谷歌的依赖管理最佳实践


本文介绍了一组用于管理应用程序依赖项的最佳实践,包括漏洞监控、工件验证以及减少依赖项足迹并使其可重现的步骤。
这些实践中的每一个的具体情况可能会因您的语言生态系统和您使用的工具的具体情况而异,但一般原则适用。
 
版本锁定
简而言之,版本锁定意味着将应用程序依赖项的版本限制为非常特定的版本——理想情况下是单个版本。
为您的依赖项固定版本具有及时冻结您的应用程序的副作用。虽然这是可重复性的良好实践,但它的缺点是阻止您在依赖项发布新版本时接收更新,无论是用于安全修复、错误修复还是一般改进。
这可以通过将自动依赖管理工具应用于您的源代码控制存储库来缓解。这些工具会监控您对新版本的依赖关系,并根据需要更新您的需求文件以将您升级到这些新版本,通常包括更改日志信息或其他详细信息。
 
签名和哈希验证
为了确保包的给定版本的给定工件实际上是您打算安装的,有许多方法允许您以不同的安全级别验证工件的真实性。
哈希验证允许您将给定工件的哈希与工件存储库提供的已知哈希进行比较。启用哈希验证可确保您的依赖项不会被不同的文件偷偷替换,无论是通过中间人攻击还是破坏工件存储库。这需要相信您在验证时(或在第一次检索时)从工件存储库收到的哈希值也不会受到损害。
签名验证为验证过程增加了额外的安全性。工件可以由工件存储库、软件维护者或两者签名。诸如sigstore 之类的新服务旨在使维护者能够轻松地签署软件工件,并使消费者能够轻松地验证这些签名。
 
锁定文件和编译的依赖项
锁定文件是完全解析的需求文件,准确指定应为应用程序安装哪个版本的依赖项。通常由安装工具自动生成,锁定文件将版本锁定和签名或哈希验证与应用程序的完整依赖树相结合。
完整的依赖树是通过“编译”或完全解析将为您的顶级依赖项安装的所有依赖项生成的。完整的依赖树意味着您的应用程序的所有依赖项,包括所有子依赖项、它们的依赖项以及向下堆栈,都包含在您的锁定文件中。这也意味着只能安装这些依赖项,因此可以认为构建在多次安装之间更具可重复性和一致性。 
 
混合私有和公共依赖项
现代云原生应用程序通常既依赖于开源的第三方代码,也依赖于闭源的内部库。如果您需要在多个应用程序之间共享您的业务逻辑,并且当您想要重用相同的工具来安装外部和内部库时,后者可能特别有用,使用像Artifact Registry这样的私有存储库可以很容易。
但是,在混合私有和公共依赖项时,请注意“依赖项混淆”攻击:通过将与内部项目同名的项目发布到开源存储库,攻击者可能会利用错误配置的安装程序偷偷安装他们的内部包上的恶意库。
为了避免“依赖混淆”攻击,你可以采取一些步骤:

  • 通过将依赖项包含在锁定文件中来验证依赖项的签名或哈希值
  • 将第三方依赖和内部依赖的安装分为两个不同的步骤
  • 手动或使用直通代理将您需要的第三方依赖项显式镜像到您的私有存储库中

 
删除未使用的依赖项
重构发生了:有时您一天需要的依赖项在第二天就不再需要了。在不再使用依赖项时继续将它们与您的应用程序一起安装会增加您的依赖项足迹以及您被这些依赖项中的漏洞危害的可能性。
通常的做法是让您的应用程序在本地工作,将您在开发过程中安装的每个依赖项复制到您的应用程序的需求文件中,然后部署它。它保证可以工作,但也可能会引入生产中不需要的依赖项。
通常,在向应用程序添加新依赖项时要小心:每个依赖项都有可能引入更多您无法完全控制的代码。使用工具审核您的需求文件以确定您的依赖项是否正在实际使用或导入,允许您将其集成到您的常规 linting 和测试管道中。
 
漏洞扫描
如果在您的依赖项之一中发现漏洞,您将如何收到通知?很有可能,您没有主动监控您所依赖的第三方软件的所有漏洞数据库,而且很可能您根本无法可靠地审核您所依赖的第三方软件。
漏洞扫描允许您自动且一致地评估您的依赖项是否将漏洞引入您的应用程序。漏洞扫描工具使用锁定文件来准确确定您所依赖的工件,并在新漏洞出现时通知您,有时甚至提供建议的升级路径。
Container Analysis 之类的工具可以为容器映像以及Java 包扫描等语言工件提供广泛的漏洞扫描。启用后,此功能可识别容器映像中的包漏洞。图像在上传到 Artifact Registry 时会被扫描,并在推送图像后长达 30 天内持续监控数据以发现新漏洞。