可信发布:提升软件包安全性的新标准

本文深入解析PyPI引入的可信发布机制,通过OpenID Connect实现无密钥认证,有效防范供应链攻击和凭证泄露,提升软件包发布流程的安全性和便捷性。

可信发布:提升软件包安全性的新标准

可信发布:入门指南

可信发布本质上是一种认证机制。与密码或长期API令牌类似,它向索引提供身份证明和权限声明,索引验证通过后允许执行相应操作。其独特之处在于无需预共享密钥即可完成认证。

OpenID Connect与“环境”凭证

可信发布基于OpenID Connect(OIDC)构建,这是一个基于OAuth2的开放身份验证标准。OIDC允许身份提供商(IdP)生成可公开验证的凭证(实际为JWT令牌),证明特定身份(如GitHub仓库或CI运行实例)。关键突破在于:OIDC身份不仅限于人类用户,可以是机器标识、源码仓库或特定CI运行实例,且凭证可通过“环境”方式提供(仅目标身份可访问)。

主流CI平台已支持此功能:

  • GitHub Actions于2021年底添加环境OIDC凭证支持
  • GitLab于近期添加相同功能

通过OIDC令牌,可精确验证身份信息(包括GitHub仓库、工作流名称、触发用户等),这些信息可成为认证系统的约束条件。

信任是一切

OIDC提供验证身份证明的机制,第三方服务(如PyPI)可接受OIDC令牌并基于其分配权限。由于OIDC令牌与IdP公钥加密绑定,攻击者无法伪造令牌。

关键问题:如何将OIDC身份映射到特定PyPI项目?这需要信任设置:

  1. 用户在PyPI上配置项目与发布者(OIDC身份)的信任关系
  2. 配置仅需一次,且仅涉及一方(无需向CI提供商共享令牌)
  3. 信任设置包含完全公开的信息(声明值集合)

以GitHub Actions发布到PyPI为例,信任设置包括:

  • GitHub用户/仓库标识
  • 发布工作流文件名(如release.yml)
  • (可选)GitHub Actions环境名称

看,没有密钥!

完整发布流程(GitHub示例):

  1. 开发者触发GitHub Actions发布工作流
  2. 执行正常构建过程
  3. 自动化获取当前工作流的OIDC令牌(通过GitHub Actions OIDC IdP)
  4. 向PyPI发送OIDC令牌
  5. PyPI验证令牌并交换为短期API令牌(仅限信任该声明的项目)
  6. 返回短期API令牌
  7. 工作流使用短期令牌执行正常发布步骤

99%的发布者无需关注步骤3-7:官方PyPA GitHub Action已封装这些细节。

为什么需要关注?

即使您已遵循最佳实践(使用最小权限令牌、存储为工作流密钥、审核发布流程),传统方法仍存在缺陷:

可用性问题

  • 手动管理API令牌繁琐(特别是单仓库多包场景)
  • 工程师时间可更有效利用

预入侵安全

  • 长期令牌对所有获取访问权的攻击者均等脆弱
  • 可信发布减少攻击面:仅特定环境/步骤无法生成OIDC凭证

入侵后恢复

  • 长期凭证回收缓慢且易出错
  • 可信发布凭证仅存活数分钟,丢失访问权即自动隔离

安全与威胁模型考量

可信出版需针对威胁模型设计,既要解决现有认证方法的不足,也要应对新暴露的攻击场景。

现有威胁:账户接管和供应链攻击

账户接管(ATO)是包装生态中的已知问题。可信发布可减少ATO范围:未来包索引允许包选择仅可信发布时,包索引本身的ATO不会允许攻击者上传恶意版本。

供应链安全方面:无可信发布时,GitHub Actions需信任所有执行的第三方操作(它们均可读取配置密钥)。可信发布正针对此关键攻击模型进行防护。

新威胁:“账户复活”和恶意提交者

账户复活攻击

  • 用户更改用户名后,攻击者可能接管旧用户名
  • PyPI项目可能突然开始信任攻击者控制的身份
  • 解决方案:GitHub添加稳定用户ID声明,PyPI据此拒绝攻击者令牌

信任模型分化

  • 是否信任所有项目成员作为发布者?
  • 许多项目有低活跃度成员(可能未遵循安全最佳实践)
  • PyPI实现支持可选GitHub Actions环境,为提交者与发布者不完全重叠的社区提供额外限制

即将来到您附近的包索引

PyPI是目前唯一提供可信发布的包索引,但该技术可轻松适配其他生态(如Rust的Crates、Ruby的RubyGems、JavaScript的NPM等)。我们相信,如同2019年的双因素认证,可信发布方案将成为开源包装安全模型的关键组成部分,并为后续改进(如生成PyPI版本源自特定源工件的加密证明)奠定基础。

如果您或您的公司对此感兴趣,欢迎联系我们!我们在开源生态系统安全功能方面拥有多年经验,始终寻找为关键开源项目和服务贡献的更多方式。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计