安全审计修复:cabotage
这是三部分系列文章的第三部分。请参见 此处的第一部分 和 此处第二部分.
这篇文章深入探讨了 cabotage 安全审计发现的修复措施,cabotage 是 代码库,它部署了 PyPI 及其支持服务,如 conveyor、camo 和 inspector。
相对于 warehouse 代码库,它是 PyPI,cabotage 并不那么广为人知。cabotage 的目标是提供一种无缝且安全的方式,将任意服务以“十二要素”风格部署到 Kubernetes 集群中。cabotage 中还有一些固定的意见,这些意见提供了端到端的 TLS、防止通过 Web UI 恢复密钥以及集群内租户之间的隔离。
cabotage 最初是在 2018 年开发的,作为 Mozilla 开源支持奖 的一部分,该奖项使 Python 软件基金会 (PSF) 能够为一个由合同开发人员和项目经理组成的团队提供资金,以完成 warehouse 的开发和部署,并使 原始 PyPI 代码库 停止使用。
cabotage 的主要目标是减少 PSF 基础设施对运行 PyPI 的特定提供商的依赖,同时为项目管理员提供配置自助服务以及完全自动化的部署。它实际上是一个“平台即服务”,将应用程序部署到标准的 Kubernetes 集群中,无需 YAML。
迄今为止,自 2018 年以来,cabotage 已向 PyPI 部署了 3,901 个版本,在其当前服务的“舰队”中总共部署了 7,377 个版本。
审计报告可以在这里找到 此处。在深入研究之前阅读这些内容将提供最完整的背景信息。
发现
审计发现了 11 个发现,以及 12 个代码质量建议。本文将重点介绍这些发现及其修复。一些代码质量建议已实施,另一些则被推迟。
以下表格列出了与 cabotage 相关的项目及其状态
ID | 标题 | 严重性 | 难度 | 状态 |
---|---|---|---|---|
TOB-PYPI-3 | cabotage 中的漏洞依赖项 | 未确定 | 低 | 已修复 |
TOB-PYPI-17 | 在子进程中使用 shell=True | 中等 | 中等 | 已修复 |
TOB-PYPI-18 | 使用 HMAC 与 SHA1 进行 GitHub Webhook 负载验证 | 低 | 高 | 已修复 |
TOB-PYPI-19 | 通过恶意 Procfile 潜在的容器镜像操作 | 中等 | 高 | 已修复 |
TOB-PYPI-20 | 镜像构建期间的仓库混淆 | 中等 | 中等 | 已修复 |
TOB-PYPI-21 | 脆弱的 X.509 证书重写 | 信息 | 未确定 | 已接受 |
TOB-PYPI-22 | cabotage 中未使用的依赖项 | 信息 | 未确定 | 已修复 |
TOB-PYPI-24 | 缺少第三方资源的资源完整性检查 | 信息 | 高 | 已修复 |
TOB-PYPI-25 | 日志中脆弱的秘密过滤 | 中等 | 低 | 已修复 |
TOB-PYPI-26 | 路由缺少访问控制 | 低 | 高 | 已修复 |
TOB-PYPI-28 | 由于临时文件导致的部署挂钩容易受到竞争条件的影响 | 信息 | 高 | 已修复 1、2 |
ID 不连续,因为审计报告还包含了 Warehouse 的发现。
细节
TOB-PYPI-3:cabotage 中的漏洞依赖项
cabotage 的维护主要是由对新功能的需求或解决已提出的问题驱动的。因此,依赖项管理和升级通常作为其他更改的副产品完成。
在审查期间,发现了一些具有已知漏洞的依赖项。在记录的九个漏洞中,只有 GHSA-cg8c-gc2j-2wf7 被确定为会影响 cabotage,并通过迁移到维护的 flask-security 分支的最新版本 flask-security-too (差异) 来修复。
为了避免在这一类维护中落后,我们添加了自动化依赖项管理以及对所有已知漏洞依赖项的更新 (差异)。
TOB-PYPI-17:使用 shell=True
在子进程中
在开发模式下运行容器构建时,cabotage 调用 buildctl
的方式中发现了一种攻击载体。一个精心制作的用户输入能够在应用程序主机上运行任意 shell 命令。
最终,这被确定为在 cabotage 的生产实例中不可利用,因为 shell 命令仅在本地开发模式下构建容器时使用。尽管如此,还是出于卫生原因删除了 shell=True
的使用 (差异)。
TOB-PYPI-18:使用 HMAC 与 SHA1 进行 GitHub Webhook 负载验证
与 warehouse 中 TOB-PYPI-2 中的 SNS 验证发现类似,接收来自 GitHub 的用于自动部署的 webhook 负载的端点使用 SHA1 HMAC 签名来验证真实性,而 SHA256 HMAC 签名是可用的。
此发现的修复比 SNS 发现更加直接,因为 GitHub 开始在标头中发送 SHA256 签名,无需对 webhook 配置进行任何更改,并且使用 Python 标准库支持的标准 HMAC 签名 (差异)。
TOB-PYPI-19:通过恶意 Procfile 潜在的容器镜像操作
与 TOB-PYPI-17 一样,一些用户提供的 value 能够改变 cabotage 控制的 Dockerfile,该 Dockerfile 指定了如何构建版本容器,这些内容不应该可修改。通过在 Procfile 中精心制作的进程名称,用户可以通过注入新行来更改生成的 Dockerfile。
通过添加对用户提供进程名称的额外验证来进行修复 (差异)。
TOB-PYPI-20:镜像构建期间的仓库混淆
由于 GitHub API 中用于获取引用的一个怪癖,给定引用可能会返回一个具体的 SHA/提交,该 SHA/提交属于 API 调用中指定的仓库以外的仓库。在这种情况下,通过提供一个解析到配置仓库的分支的提交的引用,cabotage 的用户能够有意地(或错误地)配置 cabotage 部署来自定义仓库以外的仓库的代码。
通过添加受 Chainguard 的 clank 工具启发的额外验证,cabotage 现在会验证给定引用的生成的 SHA 是否属于配置的仓库 (差异)。
TOB-PYPI-21:脆弱的 X.509 证书重写
所有由 cabotage 构建和部署的容器都是使用内部部署的 Docker registry 实例的短期身份验证令牌完成的。cabotage 应用程序本身提供此身份验证,并且必须发布一个公钥,以便 registry 可以使用该公钥验证令牌。
为了避免在应用程序中处理私钥资料,cabotage 严重依赖于 Hashicorp Vault。Vault 的 transit 后端 在 2018 年 cabotage 最初开发时不支持发布 Docker registry 所需的 X.509 证书,因此采用了一些巧妙的 cryptography 库使用方式来创建必要的文件 引用。
在审计中,我们发现此变通办法在攻击者能够改变签名长度的情况下很脆弱,从而导致无效的 X.509 证书和 registry 客户端的身份验证失败。
在实际操作中,在它投入生产的五年半时间里,并没有观察到这种情况,并且成功攻击的结果只会导致部署停止。因此,我们暂时接受了这一发现,并将调查 vault 1.15 中新发布的 X.509 支持,并在可能的情况下采用它 (问题)。
TOB-PYPI-22:cabotage 中未使用的依赖项
与 TOB-PYPI-3 类似,cabotage 的依赖项管理存在缺陷。这导致安装了一些可能导致更多漏洞或攻击的依赖项。
通过采用 pip-tools
来编译和固定依赖项,只安装了必要的项目 (差异)。
TOB-PYPI-24:缺少第三方资源的资源完整性检查
在添加对新功能的支持时,添加了第三方 JavaScript,但没有添加子资源完整性信息。此添加可以防止恶意替换 JavaScript,并且在加载任何第三方代码时都是最佳实践。
修复很简单,只需要确保所有 CDN 加载的 JavaScript 都设置了正确的值 (差异)。
TOB-PYPI-25:日志中脆弱的秘密过滤
有一段时间,cabotage 支持从私有 GitHub 仓库构建,这需要过滤构建日志并删除明文身份验证令牌。
这种过滤很天真,但现在不再需要。修复是删除过滤代码,以及一个注释,指示未来的开发人员在未来提供构建所需的身份验证的正确方法,如果需要从私有 GitHub 仓库构建 (差异)。
TOB-PYPI-26:路由缺少访问控制
审计中还发现,另一个允许构建容器所需的构建上下文的部分代码在攻击者获得对 cabotage 应用程序用于临时文件的系统文件的访问权限的情况下,可能导致潜在的非公开信息泄漏。如果猜测或推断出版本 ID (UUIDv4),则可能会发生这种情况。
此路由未经身份验证,作为一种快捷方式,而不是在 cabotage 本身添加新的身份验证方法。
当 cabotage 开始从直接从 GitHub 拉取并通过 Kubernetes 机密提供的上下文构建时,此代码失效了。修复再次是简单地删除代码 (差异)。
TOB-PYPI-28:由于临时文件导致的部署挂钩容易受到竞争条件的影响
审计中还发现,另一部分代码被标记为需要从 GitHub 中获取和重新打包源代码以进行部署。如果攻击者获得对 cabotage 应用程序用于临时文件的系统文件的访问权限,那么这在最坏的情况下可能存在可利用性。
当 cabotage 开始从直接从 GitHub 拉取的上下文构建时,此代码也失效了。修复是最终简单地删除代码 (差异-0),以及重构创建和打开临时文件的方式 (差异-1)。
摘要
除了具体发现外,Trail of Bits 团队还提出了一些“代码质量建议”,并分析了代码库的整体成熟度。报告的这些部分突出了我对 cabotage 的两个主题之一。
-
总体而言,cabotage 的开发体验和持续集成环境有所欠缺。
-
在编写安全代码时,需要考虑无数的细节。
最终,没有发现任何阻止性或易于利用的安全问题,这让人松了一口气!许多最有趣的安全发现只有在恶意内部人员已经拥有 cabotage 中的配置权限,并且首先在那里部署他们的应用程序,或者可以访问底层系统的情况下才能利用。
作为 cabotage 的唯一作者和维护者,我得出的结论非常响亮,并涵盖了报告中的两个主题。
由单一维护者维护的项目无法从协作开发带来的问责制中获益,容易将开发人员体验和测试的重大改进降级,并且没有额外的眼睛来帮助发现小错误或不当处理安全敏感软件。
因此,如果您对基础设施和项目感兴趣,这些项目使安全可靠地部署软件变得更加直接,我很乐意与您进一步交流。请访问 cabotage 仓库,并考虑帮助构建用于部署 PyPI 的软件,该软件很快将部署越来越多的 Python 软件基金会 的基础设施,因为我们正在从之前的免费 PaaS 托管提供商迁移。