Following system colour scheme - Python 增强提案 Selected dark colour scheme - Python 增强提案 Selected light colour scheme - Python 增强提案

Python 增强提案

PEP 458 – 使用签名存储库元数据保护 PyPI 下载

作者:
Trishank Karthik Kuppusamy <karthik at trishank.com>, Vladimir Diaz <vladimir.diaz at nyu.edu>, Marina Moore <mm9693 at nyu.edu>, Lukas Puehringer <lukas.puehringer at nyu.edu>, Joshua Lock <jlock at vmware.com>, Lois Anne DeLong <lad278 at nyu.edu>, Justin Cappos <jcappos at nyu.edu>
赞助商:
Alyssa Coghlan <ncoghlan at gmail.com>
BDFL 代表:
Donald Stufft <donald at stufft.io>
讨论列表:
Discourse 帖子
状态:
已接受
类型:
标准跟踪
主题:
打包
创建日期:
2013 年 9 月 27 日
修订历史:
2019 年 1 月 6 日,2019 年 11 月 13 日
决议:
Discourse 消息

目录

摘要

本 PEP 描述了 PyPI 基础设施所需的更改,以确保用户从 PyPI 获取有效软件包。这些更改对生态系统的其他部分的影响应该很小。PEP 重点关注 PyPI 和用户之间的通信,因此不需要软件包开发者执行任何操作。开发者将使用当前流程上传软件包,PyPI 将自动为这些软件包生成签名的存储库元数据。

为了使安全机制有效,PyPI 消费者(如 pip)需要进行额外的工作来验证 PyPI 提供的签名和元数据。此验证对用户来说可以是透明的(除非失败),并提供自动安全机制。TUF 存储库中有关于如何使用 TUF 元数据的文档。但是,对 PyPI 消费者的更改不是发布 PyPI 元数据的先决条件,可以根据各个项目的进度和优先级进行。

提议的 TUF 集成

本 PEP 提出如何将更新框架 [2]TUF)与 Python 包索引 (PyPI [1]) 集成。TUF 旨在成为软件更新程序或包管理器的灵活安全附加组件。框架的完整实现集成了最佳安全实践,例如分离角色职责、采用多人规则签名软件包、使签名密钥保持离线状态以及撤销过期或已泄露的签名密钥。因此,攻击者需要窃取多个独立存储的签名密钥才能破坏负责指定存储库可用文件的角色。或者,负责指示存储库最新快照的角色也可能需要被破坏。

本 PEP 中提出的初始集成将允许现代包管理器,例如 pip [3],更好地抵御对 PyPI 镜像和 PyPI 自身内容分发网络的攻击,并更好地保护用户免受此类攻击。具体来说,本 PEP 描述了如何调整 PyPI 流程以生成和合并 TUF 元数据(即最小安全模型)。此最小安全模型支持验证使用存储在 PyPI 上的密钥签名的 PyPI 分发。由开发者上传的分发由 PyPI 签名,无需开发者执行任何操作(除了上传分发),并且可以立即下载。最小安全模型还通过自动化大部分签名过程来最大程度地减少 PyPI 管理员的责任。

本 PEP 中**没有**讨论对由开发者签名的项目分发(最大安全模型)的支持。这种可能的未来扩展在 PEP 480 中详细介绍。最大安全模型需要更多的 PyPI 管理工作(尽管客户端没有增加工作),并且还提出了一个易于使用的开发者/发布者密钥管理解决方案,关于如何与 PyPI 基础设施上潜在的未来构建场的接口的想法,以及端到端签名的可行性。

虽然本 PEP 提供了实现建议,但它并没有规定包管理器(如 pip)如何准确地适应从具有 TUF 元数据的 PyPI 安装或更新项目。有兴趣在客户端采用 TUF 的包管理器可以查阅其 库文档,该文档为此目的而创建。

非目标

本 PEP 不会消除 PyPI 中的任何现有功能。特别是,它不会替换对 OpenPGP 签名的现有支持。开发者可以继续与分发一起上传分离的 OpenPGP 签名。将来,PEP 480 可能会允许开发者使用其 OpenPGP 密钥直接签名 TUF 元数据。

PEP 状态

由于实施本 PEP 需要大量工作,因此在 2019 年初,它被推迟,直到获得合适的资金来实施 PEP。Python 软件基金会获得了这笔资金 [22],新的 PEP 合著者重新启动了 PEP 讨论

动机

软件存储库攻击很常见,即使在具有非常好的安全性的组织中也是如此 实践。由此产生的存储库泄露允许攻击者编辑存储在存储库中的所有文件,并使用存储在存储库中的任何密钥(在线密钥)对这些文件进行签名。在许多签名方案(如 TLS)中,此访问权限允许攻击者替换存储库中的文件,并使其看起来像是来自 PyPI 的文件。如果没有一种撤销和替换受信任私钥的方法,那么从存储库泄露中恢复起来非常困难。除了存储库泄露的危险之外,软件存储库还容易受到网络上的攻击者 (MITM) 拦截和更改文件的攻击。这些和其他软件存储库攻击的详细信息在此处

本 PEP 以及 PEP 480 中的后续提案旨在保护 PyPI 用户免受 PyPI 软件包的完整性、一致性和新鲜度属性泄露的影响,并通过降低密钥风险并提供从 PyPI 或其签名密钥泄露中恢复的机制来增强泄露恢复能力。

2013 年 1 月 5 日,Python 软件基金会 (PSF) 宣布 [4] Python 和 Jython 的 python.org wiki 发生了安全漏洞。结果,所有 wiki 数据都被销毁。幸运的是,PyPI 基础设施不受此漏洞的影响。但是,此事件提醒我们,PyPI 需要采取防御措施,以最大程度地保护用户免受泄露的影响。软件存储库攻击一直在发生 [5]。PSF 必须接受安全漏洞的可能性,并相应地准备 PyPI,因为它是一个被数千甚至数百万用户使用的宝贵资源。

在 wiki 攻击之前,PyPI 使用 MD5 哈希来告知包管理器(如 pip)分发文件在传输过程中是否已损坏。但是,缺少 SSL 使包管理器难以验证到 PyPI 的传输完整性。因此,很容易在 pip 和 PyPI 之间发起中间人攻击,并任意更改分发的内容。结果,用户可能会被诱骗安装恶意分发。在 wiki 攻击之后,提出了几个步骤(其中一些已实施)以提供比以前更高的安全级别。这些步骤包括要求使用 SSL 与 PyPI 通信 [6]、限制项目名称 [7] 以及从 MD5 迁移到 SHA-2 哈希 [8]

尽管这些步骤是必要的,但它们不足以保护分发,因为仍然可以通过其他途径进行攻击。例如,公共镜像被信任可以诚实地镜像 PyPI,但某些镜像可能会出现故障行为,无论是意外还是恶意干预。像 pip 这样的包管理器应该使用来自 PyPI 的签名来验证从 公共镜像 下载的分发文件,但据了解,实际上没有一个包管理器这样做 [10]。因此,明智的做法是增加更多安全措施来检测来自公共镜像或内容分发网络 [11] (CDN) 的攻击。

即使官方镜像已被 PyPI 弃用,包管理器仍然存在各种其他攻击媒介 [13]。这些攻击可能会导致客户端系统崩溃、安装过时的分发,甚至允许攻击者执行任意代码。在 2013 年 9 月,Distutils 邮件列表中发布了一篇帖子,表明当时最新版本的 pip 容易受到此类攻击,以及 TUF 如何保护用户免受此类攻击 [14]。具体来说,进行了测试以查看 pip 在有和没有 TUF 的情况下对这些攻击的响应。测试的攻击包括重放和冻结、任意安装、缓慢检索和无限数据。该帖子还演示了如果 PyPI 被泄露,pip 将如何响应。

为了提供对 PyPI 的泄露恢复保护,本 PEP 提出使用更新框架 [2] (TUF)。TUF 提供了对各种软件更新系统攻击的保护,同时还提供了从存储库泄露中恢复的机制。TUF 已被许多组织用于生产环境,包括用于 Cloud Native Computing Foundation 的 Notary 服务,该服务为 Docker Registry 中的容器镜像签名提供基础设施。TUF 规范已成为三个独立安全 审核 的主题。

本 PEP 的范围是保护用户免受 PyPI 镜像和 PyPI 自身的 TLS 终止和内容分发基础设施泄露的影响。对 PyPI 本身的泄露保护在 PEP 480 中进行了讨论。

威胁模型

威胁模型假设以下情况

  • 离线密钥安全且安全地存储。
  • 攻击者无法泄露 PyPI 在线存储的受信密钥。
  • 攻击者可以响应客户端请求。

如果攻击者能够导致客户端安装(或保持安装)软件分发文件的非最新版本,则认为攻击成功。如果攻击者阻止安装更新,他们不希望客户端意识到有任何问题。

此威胁模型描述了最低安全模型。PEP 480中描述的最大安全模型还假设攻击者可以泄露 PyPI 的在线密钥。

定义

本文档中“MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、“MAY”和“OPTIONAL”等关键词的解释方式,请参见RFC 2119

本 PEP 仅关注将 TUF 集成到 PyPI 中。但是,鼓励读者查看 TUF 设计原则 [2],并且**应该**熟悉 TUF 规范 [16]

本 PEP 中使用的以下术语在 Python 打包术语表 [17]中定义:项目版本分发

本 PEP 中使用的其他术语定义如下

  • 角色:TUF 指定了一个角色和多个其他角色,角色直接或间接地将职责委派给这些角色。术语顶级角色指的是角色和角色直接指定的任何角色,即时间戳快照目标角色。每个角色都有一个唯一的元数据文件,该文件被信任可以提供。
  • 分发文件:一个包含 Python 包、模块和其他用于分发版本的资源文件的版本化归档文件。术语分发文件分发包 [17]或简称为分发在本 PEP 中可以互换使用。
  • 简单索引:包含到分发文件内部链接的 HTML 页面。
  • 目标文件:根据经验,目标文件是 PyPI 上所有应使用 TUF 保证其完整性的文件。通常,这包括分发文件和 PyPI 元数据,例如简单索引。
  • 元数据:元数据是签名的文件,描述角色、其他元数据和目标文件。如果未另行指定,元数据表示 TUF 特定的元数据。
  • 存储库:存储库是命名元数据和目标文件的来源。客户端请求存储在存储库中的元数据和目标文件。
  • 一致快照:一组捕获 PyPI 上所有项目在某个固定时间点存在状态的完整 TUF 元数据和目标文件。
  • 开发者:项目的拥有者或维护者,他们被允许更新 TUF 元数据以及项目的目标文件。
  • 在线密钥:必须存储在 PyPI 服务器基础设施上的私有加密密钥。这通常是为了允许使用密钥进行自动签名。但是,如果攻击者泄露了 PyPI 基础设施,则能够读取这些密钥。
  • 离线密钥:必须独立于 PyPI 服务器基础设施存储的私有加密密钥。这可以防止使用密钥进行自动签名。攻击者泄露 PyPI 基础设施将无法立即读取这些密钥。
  • 阈值签名方案:角色可以通过指定至少 t 个中的 n 个密钥**必须**对其元数据进行签名来提高其对密钥泄露的弹性。泄露 t-1 个密钥不足以泄露角色本身。说角色需要 (t, n) 个密钥表示阈值签名属性。

TUF 概述

在最高级别,TUF 为应用程序提供了一种安全的方法来了解和获取文件的最新版本。从表面上看,这一切听起来都很简单。更新应用程序的基本步骤是

  • 知道存在更新。
  • 下载更新文件的最新版本的正确副本。

问题在于,只有在没有恶意活动的情况下,更新应用程序才简单。如果攻击者试图干扰这些看似简单的步骤,他们可以做很多事情。

假设软件更新程序采用大多数系统(至少是那些试图保持安全性的系统)的方法。它同时下载它想要的文件以及该文件的加密签名。软件更新程序已经知道它信任哪个密钥来生成签名。它检查签名是否正确,以及是否由该受信密钥生成。不幸的是,软件更新程序仍然面临多种风险,包括以下场景

  • 攻击者不断向软件更新程序提供相同的更新文件,因此它永远不会意识到有更新。
  • 攻击者向软件更新程序提供了一个它已经拥有的旧的、不安全的版本的的文件,因此它下载了该文件并盲目地使用它,认为它是更新的。
  • 攻击者向软件更新程序提供了一个较新版本的的文件,但不是最新的文件。该文件对于软件更新程序来说是更新的,但它可能是不安全的,并且可能被攻击者利用。
  • 攻击者泄露了用于签署这些文件的密钥,现在软件更新程序下载了一个正确签名的恶意文件。

TUF 旨在通过向存储库添加签名的元数据(描述存储库文件的文本文件)并在更新过程中引用元数据文件来解决这些攻击和其他攻击。在将存储库文件传递给软件更新系统之前,会根据元数据中包含的信息验证这些文件。该框架还提供多签名信任、加密密钥的显式和隐式撤销、元数据的责任分离以及密钥风险最小化。有关 TUF 解决的存储库攻击和软件更新程序弱点的完整列表和概述,请参见附录 A。

将 PyPI 与 TUF 集成

软件更新系统必须完成两个主要任务才能与 TUF 集成。首先,**必须**修改服务器端的存储库以提供签名的 TUF 元数据。本 PEP 关注集成的第一部分,以及 PyPI 上支持使用 TUF 进行软件更新所需的更改。

其次,它必须将框架添加到更新系统的客户端。例如,TUF**可以**与 pip 包管理器集成。因此,未来 pip 的新版本**应该**默认使用 TUF 从 PyPI 下载和验证分发文件,然后再安装它们。但是,可能会出现一些无法预见的问题,这些问题可能会阻止用户通过 TUF 安装或更新分发文件(包括 pip 本身)。因此,pip**应该**提供一个选项,例如 --unsafely-disable-package-verification,以便在解决这些问题之前解决此类问题。请注意,建议的选项名称故意很长,因为必须帮助用户理解该操作是不安全的,并且通常不建议使用。

我们假设 pip 将使用 TUF 验证仅从 PyPI 下载的分发文件。pip**可以**支持 TAP 4,以便使用 TUF 也验证从其他地方下载的分发文件。

PyPI 上需要哪些其他存储库文件?

为了使像 pip 这样的包管理器能够使用 TUF 下载和验证分发文件,**必须**向 PyPI 添加一些额外的文件。这些额外的存储库文件称为 TUF 元数据,它们包含诸如哪些密钥可以信任、文件的加密哈希、签名、元数据版本号以及元数据应被视为过期后的日期等信息。

当包管理器想要检查更新时,它会要求 TUF 执行此操作。也就是说,包管理器永远不必处理这些额外的元数据或了解底层发生了什么。如果 TUF 报告回存在可用的更新,则包管理器可以要求 TUF 从 PyPI 下载这些文件。TUF 下载它们并根据它也从存储库下载的 TUF 元数据检查它们。如果下载的目标文件值得信赖,则 TUF 将它们传递给包管理器。

TUF 规范的文档格式部分提供了有关每种类型的必需元数据及其预期内容的信息。下一节介绍了**推荐**用于 PyPI 的不同类型的元数据。

此外,所有目标文件**应该**至少在磁盘上保存两次。一次使用其原始文件名,以提供向后兼容性,另一次在其文件名中包含其 SHA-512 哈希。这是生成一致快照所必需的。

根据使用的文件系统,**可以**使用不同的数据重复数据删除机制来避免目标文件硬盘副本导致存储空间增加。

PyPI 和 TUF 元数据

TUF 元数据提供客户端可用于做出更新决策的信息。例如,目标元数据列出了 PyPI 上可用的目标文件,并包含每个文件的必需签名、加密哈希和文件大小。不同的元数据文件提供不同的信息,这些信息由不同的角色签名。角色指示每个角色属于哪个元数据。角色的概念允许 TUF 将职责委派给多个角色,从而最大程度地减少任何一个泄露的角色的影响。

TUF 需要四个顶级角色。它们是时间戳快照目标角色指定顶级角色(包括其自身)的公钥加密密钥。时间戳角色引用最新的快照,并可以表示存储库的新快照何时可用。快照角色指示所有 TUF 元数据文件(时间戳除外)的最新版本。目标角色列出可用目标文件的路径及其加密哈希。文件路径必须相对于基本 URL 指定。这允许实际的目标文件从任何地方提供服务,只要客户端可以访问基本 URL 即可。每个顶级角色都将无一例外地履行其职责。表 1 提供了 TUF 中使用的角色概述。

角色和职责
根角色是整个存储库的信任中心。根角色签署 root.json 元数据文件。此文件指示哪些密钥被授权用于每个顶级角色,包括根角色本身。必须指定角色“根”、“快照”、“时间戳”和“目标”,并且每个角色都有一组公钥。
目标 目标角色负责指示存储库中有哪些目标文件可用。更准确地说,它共享提供有关更新内容信息的责任。目标角色签署 targets.json 元数据,并且可以将存储库文件的信任委派给其他角色(委派角色)。
委派角色 如果顶级目标角色执行委派,则生成的委派角色随后可以提供自己的元数据文件。委派目标角色提供的元数据文件的格式与 targets.json 的格式相同。与 targets.json 一样,属于委派角色的元数据文件的最新版本在快照角色的元数据中进行了描述。
快照

快照角色负责确保客户端看到一致的存储库状态。它通过在 snapshot.json 中指示存储库中顶级目标和委托目标元数据文件的最新版本来提供存储库状态信息。root 和 timestamp 未列在 snapshot.json 中,因为 timestamp 用于表示其新鲜度,在创建 snapshot.json 后,而 root 包含所有顶级密钥,需要提前才能信任任何顶级角色。
时间戳 时间戳角色负责提供有关可用更新及时性的信息。通过频繁签名具有较短过期时间的新 timestamp.json 文件来提供及时性信息。此文件指示 snapshot.json 的最新版本。

表 1:TUF 角色概述。

除非另有说明,否则本 PEP **建议**每个元数据或目标文件都使用 SHA-2 系列的 SHA2-512 函数进行哈希计算。SHA-2 具有原生且经过良好测试的 Python 2 和 3 支持(允许在没有其他非 Python 依赖项的情况下验证这些哈希值)。如果需要更强的安全保障,则可以使用 SHA2-256 和 SHA2-512 或 SHA2-256 和 SHA3-256。SHA2-256 和 SHA3-256 基于彼此截然不同的设计,提供了针对 碰撞攻击 的额外保护。但是,SHA-3 需要为 Python 2 安装额外的非 Python 依赖项。

签名元数据和存储库管理

顶级 root 角色为顶级 timestampsnapshottargetsroot 角色的密钥签名。timestamp 角色为存储库元数据的每个新快照签名。snapshot 角色为 roottargets 和所有委托目标角色签名。委托目标角色 bins 进一步委托给 bin-n 角色,后者为属于已注册 PyPI 项目的所有分发文件签名。

图 1 提供了 PyPI 中可用角色的概述,其中包括顶级角色和 targets 委托的角色。该图还指示了用于为每个角色签名的密钥类型,以及哪些角色被信任为 PyPI 上可用的文件签名。接下来的两节将详细介绍签名存储库文件和每个角色使用的密钥类型。

../_images/pep-0458-1.png

图 1:PyPI 上可用的角色元数据概述。

变化最频繁的角色是 timestampsnapshotbins 委托的角色(即 bin-n)。每当 roottargets 或委托元数据更新时,**必须**更新 timestampsnapshot 元数据。但是,请注意,roottargets 元数据不太可能像委托元数据那样频繁更新。类似地,只有在添加、更新或删除 bin-n 角色时,才会更新 bins 角色。因此,由于委托元数据为了支持项目的持续交付而频繁更新,timestampsnapshotbin-n 元数据很可能被频繁更新(可能每分钟更新一次)。持续交付是 PyPI 用于生成可以安全共存并独立于其他快照删除的快照的一组流程 [18]

每年,PyPI 管理员**应该**为 roottargets 角色密钥签名。自动化将持续为所有项目的带时间戳的快照签名。有一个可用的存储库 元数据 API,可用于 管理 TUF 存储库

在标准操作中,随着新分发文件上传到 PyPI,bin-n 元数据将被更新和签名。但是,还需要一个一次性的在线初始化机制,以便每次重新初始化 PyPI 时,为 PyPI 存储库中所有现有的分发文件创建和签名 bin-n 元数据。

如何建立对 PyPI 根密钥的初始信任?

像 pip 这样的包管理器**必须**将 root 元数据文件与用户最初下载的安装文件一起交付。这包括有关所有顶级角色(包括 root 密钥本身)的可信密钥的信息。包管理器还必须捆绑一个 TUF 客户端库。TUF 客户端库可能下载的 root 元数据的任何新版本都将根据最初与包管理器捆绑的 root 密钥进行验证。如果一个 root 密钥被泄露,但仍有足够数量的密钥是安全的,那么 PyPI 管理员**必须**推送新的 root 元数据,撤销对泄露密钥的信任。如果超过阈值的 root 密钥被泄露,则**必须**通过带外方式更新 root 元数据。(但是,应选择 root 密钥阈值,以使此事件极不可能发生。)如果在包管理器的新的版本之间撤销或添加了 root 密钥,则包管理器不需要立即更新,因为 TUF 更新过程会自动处理以前 root 密钥中的阈值数量为新的 root 密钥签名的情况(假设使用的 TUF 规范没有向后不兼容性)。因此,例如,如果一个包管理器最初附带了版本 1 的 root 元数据,并且版本 1 中的 root 密钥阈值数量为版本 2 的 root 元数据签名,并且版本 2 中的 root 密钥阈值数量为版本 3 的 root 元数据签名,那么该包管理器应该能够使用其 TUF 客户端库将其 root 元数据的副本从版本 1 透明地更新到版本 3。

因此,重申一遍,**必须**在与 CPython 一起发布的 pip 的任何新版本中(通过 ensurepip)包含 root 元数据的最新良好副本和 TUF 客户端库。包管理器中的 TUF 客户端库然后加载 root 元数据并下载其余的角色,包括在 root 元数据发生更改时更新它。有一个可用的 更新流程概述

最小安全模型

在将 TUF 集成到 PyPI 时,需要考虑两种安全模型。本 PEP 中提出的模型是最小安全模型,它支持验证使用存储在 PyPI 上的私有加密密钥签名的 PyPI 分发文件。开发人员上传的分发文件由 PyPI 签名,并立即提供下载。本 PEP 的一个可能的未来扩展(在 PEP 480 中讨论)提出了最大安全模型,并允许开发人员为其项目签名。开发人员密钥不会在线存储:因此,项目可以免受 PyPI 泄露的影响。

最小安全模型不需要开发人员采取任何操作,并且可以防止恶意 CDN [19] 和公共镜像。为了支持上传分发文件的持续交付,PyPI 使用在线密钥为项目签名。此安全级别可以防止镜像或 CDN 意外或故意篡改项目,因为它们都没有为项目签名所需的任何密钥。但是,它无法保护项目免受已泄露 PyPI 的攻击者的攻击,因为他们可以使用在线存储的密钥操纵 TUF 元数据。

本 PEP 建议 bin-n 角色使用在线密钥为所有 PyPI 项目签名。这些 bin-n 角色**必须**全部由上层 bins 角色委托,后者使用离线密钥签名,并且依次**必须**由顶级 targets 角色委托,后者也使用离线密钥签名。这意味着当像 pip(即使用 TUF)这样的包管理器从 PyPI 上的项目下载分发文件时,它将查询 targets 角色以获取该分发文件的 TUF 元数据。如果最终 targets 通过 bins 委托的 bin-n 角色均未指定分发文件,则认为该分发文件在 PyPI 上不存在。

请注意,targets 不直接委托给 bin-n,而是使用中间 bins 角色的原因是,可以轻松地添加或删除其他委托,而不会影响 binsbin-n 的映射。这对于 PEP 480 的实现至关重要。

元数据过期时间

roottargetsbins 角色的元数据**应该**分别过期一年,因为预计这些元数据文件很少更改。

timestampsnapshotbin-n 元数据**应该**分别过期一天,因为 CDN 或镜像**应该**每天与 PyPI 同步。此外,这个宽松的时间范围也考虑了高度偏差或漂移的客户端时钟。

元数据可扩展性

随着存储库中项目和分发文件数量的增长,TUF 元数据也需要相应地增长。例如,考虑 bins 角色。在 2013 年 8 月,发现如果 bins 角色本身为大约 220K 个 PyPI 目标(它们是简单的索引和分发文件)签名,则 bins 元数据的大小约为 42MB。本 PEP 不会深入探讨细节,但 TUF 具有一个所谓的 “哈希 bin 委托” 方案,该方案将大型目标元数据文件拆分为许多较小的文件。这允许 TUF 客户端更新程序智能地仅下载少量 TUF 元数据文件,以便更新 bins 角色签名的任何项目。例如,将此方案应用于以前的存储库后,pip 下载了 1.3KB 到 111KB 之间的数据以通过 TUF 安装或升级 PyPI 项目。

根据我们在更新此文档以进行实施时(2019 年 11 月 7 日)的发现,如表 2-3 中总结的那样,PyPI **应该**通过将其委托给 16,384 个 bin-n 角色来拆分 bins 角色中的所有目标(请参阅表 2 中的 C10)。每个 bin-n 角色将为其 SHA2-512 哈希值落入该 bin 的 PyPI 目标签名(请参阅图 1 和 一致快照)。发现这个数量的 bin 将导致返回用户的元数据开销为 5-9%(相对于下载的分发文件的平均大小;请参阅表 3 中的 V13 和 V15),而首次安装 pip 的新用户的元数据开销为 69%(请参阅表 3 中的 V17)。

计算这些元数据开销百分比时使用的一些假设

  1. 我们忽略了 root、timestamp 和顶级目标元数据。
  2. pip 将始终与所有角色的元数据的最新良好副本捆绑在一起。
名称 描述
C1 SHA2-512 十六进制摘要中的字节数 128
C2 SHA2-512 公钥 ID 的字节数 64
C3 Ed25519 签名的字节数 128
C4 Ed25519 公钥的字节数 64
C5 目标相对文件路径的字节数 256
C6 编码目标文件大小的字节数 7
C7 编码版本号的字节数 6
C8 目标数量(简单的索引和分发文件) 2,273,539
C9 下载分发文件的平均字节数 2,184,393
C10 bin 的数量 16,384

C8 通过查询发布文件数量计算得出。C9 通过取过去 31 天下载的发布文件平均大小(1,628,321 字节)和磁盘上发布文件平均大小(2,740,465 字节)之间的平均值得出。Ee Durbin 在 2019 年 11 月 7 日提供了这些数字。

表 2:用于计算元数据开销的常量列表。

名称 描述 公式
V1 路径哈希前缀的长度 math.ceil(math.log(C10, 16)) 4
V2 路径哈希前缀的总数 16**V1 65,536
V3 每个 bin 的平均目标数 math.ceil(C8/C10) 139
V4 每个 bin 的 SHA-512 哈希值的平均大小 V3*C1 17,792
V5 每个 bin 的目标路径的平均大小 V3*C5 35,584
V6 每个 bin 的长度的平均大小 V3*C6 973
V7 bin-n 元数据的平均大小(字节) V4+V5+V6 54,349
V8 bin 中公钥 ID 的总大小 C10*C2 1,048,576
V9 存储桶中路径哈希前缀的总大小 V1*V2 262,144
V10 存储桶元数据估计大小(字节) V8+V9 1,310,720
V11 快照元数据估计大小(字节) C10*C7 98,304
V12 每个分发版每个回访用户(相同快照)的元数据开销估计大小 2*V7 108,698
V13 每个分发版每个回访用户(相同快照)的元数据开销估计大小 round((V12/C9)*100) 5%
V14 每个分发版每个回访用户(不同快照)的元数据开销估计大小 V12+V11 207,002
V15 每个分发版每个回访用户(不同快照)的元数据开销估计大小 round((V14/C9)*100) 9%
V16 每个分发版每个新用户的元数据开销估计大小 V14+V10 1,517,722
V17 每个分发版每个新用户的元数据开销估计大小 round((V16/C9)*100) 69%

表 3:新用户和回访用户的元数据开销估计。

感兴趣的读者可以在这里找到元数据开销计算器的交互式版本 here

当回访用户的元数据开销超过 50% 时,存储桶的数量 SHOULD 增加。目前,当目标数量至少增加 10 倍,从超过 200 万个增加到超过 2200 万个时,SHOULD 发生这种情况,此时回访用户和新用户的元数据开销分别约为 50-54% 和 114%,假设存储桶数量保持不变。如果增加存储桶数量,则所有用户的成本将有效地成为新用户的成本,因为他们的成本将主要由下载 bins 元数据中大量委派(偶尔发生)的成本决定。如果新用户的成本被证明过高,主要是由于下载 bins 元数据的开销,则在发生这种情况之前,SHOULD 重新审视此问题。

请注意,服务器上存储桶数量的更改对客户端是透明的。包管理器将需要下载一组新的元数据,就像新用户一样,但此操作不需要任何显式的代码逻辑或用户交互即可执行。

可以通过以二进制格式表示 TUF 元数据而不是 JSON 文本格式来使 TUF 元数据更紧凑。然而,大量的项目和分发版将在某个时刻带来可扩展性挑战,因此 bins 角色仍然需要委派(如 图 1 中所述)才能解决该问题。JSON 格式是用于数据交换的开放且众所周知的标准,TUF 参考实现已支持该格式,因此本 PEP 建议使用该数据格式。但是,由于委派数量众多,SHOULD 也通过现有的 HTTP 压缩仓库机制向客户端提供所有元数据的压缩版本。此外,可以在将 JSON 元数据发送到客户端之前对其进行压缩。TUF 参考实现目前不支持下载压缩的 JSON 元数据,但可以添加此功能以减小元数据大小。

PyPI 和密钥要求

在本节中,将检查为 PyPI 上的 TUF 角色签名所需的密钥类型。TUF 对于数字签名算法的选择是不可知的。但是,本 PEP RECOMMEND 所有数字签名均使用 Ed25519 算法生成 [15]。Ed25519 具有原生且经过良好测试的 Python 支持(允许在没有其他非 Python 依赖项的情况下验证签名),使用小密钥,并受现代 HSM 和身份验证令牌硬件支持。

管理在线密钥

timestampsnapshot 和所有 bin-n 角色共享的在线密钥 MAY 存储在 Python 基础设施上,加密或不加密。例如,密钥 MAY 保存在自托管密钥管理服务(例如 Hashicorp Vault)或第三方密钥管理服务(例如 AWS KMS、Google Cloud KMS 或 Azure Key Vault)上。

其中一些密钥管理服务允许将密钥存储在硬件安全模块 (HSM) 上(例如,Hashicorp Vault、AWS CloudHSM、Google Cloud HSM 或 Azure Key Vault)。这可以防止攻击者泄露在线私钥(尽管无法阻止他们使用它,但他们的操作现在可能是加密可审计的)。但是,这需要修改 TUF 参考实现以支持 HSM (WIP)。

无论此在线密钥存储在哪里以及如何存储,SHOULD 仔细记录、监控和审核其使用情况,理想情况下,以一种攻击者泄露 PyPI 也无法立即关闭此记录、监控和审核的方式。

管理离线密钥

如上一节所述,roottargetsbins 角色密钥 MUST 脱机以获得最大安全性。这些密钥将脱机,因为它们的私钥 MUST NOT 存储在 PyPI 上,尽管其中一些密钥 MAY 在线存在于项目的私有基础设施中。

SHOULD 举行一次脱机密钥仪式来生成、备份和存储这些密钥,以便只有在必要时(例如,轮换顶级 TUF 角色的密钥时),Python 管理员才能读取私钥。因此,SHOULD 生成密钥,最好在不受旁道 攻击 影响的物理位置,使用

  1. 一台受信任的、隔离 的计算机,配备真正的随机数 生成器,并且仪式结束后不会保留任何数据
  2. 一个受信任的操作系统
  3. 一组受信任的第三方软件包(例如,加密库的更新版本或 TUF 参考实现,如果受信任的操作系统提供的版本不够新)

为了避免在仪式结束后除了备份介质之外的其他地方保留敏感数据(例如,私钥),SHOULD 使用强密码加密生成的脱机密钥,方法是在(按信任度从高到低排序):私有 HSM(例如,YubiHSM)、基于云的 HSM(例如,上面列出的那些)、易失性内存(例如,RAM)或非易失性内存(例如,SSD 或 microSD)中进行加密。如果必须在非易失性内存中生成密钥,则在安全地备份密钥后,MUST 不可恢复地销毁此内存。

用于加密密钥的密码 SHOULD 存储在某个持久且可信赖的位置,只有 Python 管理员可以访问该位置。

为了最大程度地减少仪式期间的 OPSEC 错误,SHOULD 为在受信任的密钥生成计算机上执行的脚本编写脚本,以自动化仪式的繁琐步骤,例如

  • 通过 sneakernet 导出生成新密钥和替换旧密钥所需的所有代码和数据(以前的 TUF 元数据和 root 密钥)
  • 加强防火墙,更新整个操作系统以修复安全漏洞,并将计算机与网络隔离
  • 所有新的 TUF 元数据和密钥导出到加密的备份介质。此备份提供了恢复 PyPI TUF 存储库所需数据的完整副本
  • 新的 TUF 元数据和在线密钥导出到加密的备份介质。此备份提供了导入到 PyPI 基础设施中的所有在线数据,例如,当需要从以前的存档状态恢复在线数据时,此备份非常有用
  • 打印并保存新 TUF 元数据的加密哈希。此打印副本提供了额外的脱机纸质备份,可在发生泄露时用作比较

请注意,targetsbins 角色的一次性密钥 MAY 在脱机密钥仪式期间安全地生成、使用和删除。此外,root 密钥 MAY 不在脱机密钥仪式本身生成。相反,如上所述,n 个 Python 管理员中的阈值 t MAY 在用于生成所有其他密钥的脱机密钥仪式之后独立签署 root 元数据。

如何生成元数据?

项目开发者希望他们上传到 PyPI 的分发版能够立即下载。不幸的是,当许多读者和编写者同时访问相同的元数据和目标文件时,会出现问题。也就是说,需要一种方法来确保在多个开发者同时更改这些文件时元数据和目标文件的一致性。在没有 TUF 的情况下,PyPI 上也存在一致性问题,但问题在使用 MUST 实时跟踪 PyPI 上可用文件的签名元数据时更为严重。

假设 PyPI 生成一个快照,该快照指示除timestamp之外的所有元数据的最新版本为版本 1,并且客户端从 PyPI 请求此快照。在客户端忙于下载此快照时,PyPI 然后为新快照(例如,版本 2)设置时间戳。在不确保元数据一致性的情况下,客户端将发现自己拥有与 PyPI 上可用的内容不一致的快照副本。结果将与攻击者注入的任意元数据无法区分。镜像尝试与 PyPI 同步时也会出现此问题。

一致的快照

为了使 PyPI 上的 TUF 元数据与高度易变的目标文件保持一致,SHOULD 使用一致的快照。每个一致的快照捕获给定时间所有已知项目的状态,并且 MAY 安全地与任何其他快照共存,或独立删除,而不会影响任何其他快照。

为了维护一致的快照,所有 TUF 元数据 MUST 在写入磁盘时在其文件名中包含版本号

VERSION_NUMBER.ROLENAME.json,
其中 VERSION_NUMBER 是一个递增的整数,而 ROLENAME 是顶级元数据角色之一——rootsnapshottargets——或委托的目标角色之一——binsbin-n

唯一的例外是timestamp 元数据文件,当客户端执行更新时,其版本无法预先知道。timestamp 元数据列出了snapshot 元数据的版本,而snapshot 元数据又列出了targets 和委托的目标元数据的版本,所有这些都是给定一致快照的一部分。

在正常使用情况下,版本号溢出不太可能发生。例如,一个 8 字节的整数,可以每毫秒递增一次,并且可以持续近 3 亿年。如果攻击者任意增加版本号,存储库可以通过撤销受损密钥并重置版本号来恢复,如 TUF 规范中所述。

targets 或委托的目标元数据引用实际的目标文件,包括如上所述的其加密哈希。因此,要将目标文件标记为一致快照的一部分,它在写入磁盘时**必须**在其文件名中包含其哈希

HASH.FILENAME
其中 HASH 是文件内容哈希的十六进制摘要,FILENAME 是原始文件名。

这意味着每个目标文件**可能**有多个副本,每个副本对应上面指定的加密哈希函数之一。

假设磁盘空间无限、版本号严格递增且没有哈希冲突,客户端可以在 PyPI 生成另一个快照时安全地从一个快照中读取。

使用 TUF 协议的客户端(例如 pip)**必须**修改为下载每个元数据和目标文件,除了timestamp 元数据。这是通过在文件请求中包含文件名中的文件版本(对于元数据)或文件的加密哈希(对于目标文件)来完成的。

通过这种简单而有效的方式,PyPI 能够在给定时间捕获所有项目和关联元数据的一致快照。下一小节提供了此想法的实现细节。

注意:本 PEP 并不禁止使用高级文件系统或工具来生成一致的快照。在本 PEP 中提出简单解决方案有两个重要原因。首先,该解决方案不要求 PyPI 使用任何特定的文件系统或工具。其次,基于通用文件系统的方案允许镜像使用现有的文件传输工具(如 rsync)来有效地从 PyPI 传输一致的快照。

生成一致的快照

当新的分发文件上传到 PyPI 时,PyPI **必须**更新相应的bin-n 元数据。请记住,所有目标文件都按其文件名哈希排序到 bin 中。PyPI **必须**还更新snapshot 以考虑更新的bin-n 元数据,并更新timestamp 以考虑更新的snapshot 元数据。这些更新**应该**由自动化的快照过程处理。

文件上传**可能**并行处理,但是,一致的快照**必须**以严格顺序的方式生成。此外,只要分发文件是自包含的,就可以为每个上传的文件生成一致的快照。为此,上传进程将新的分发文件放入并发安全的 FIFO 队列中,快照进程一次读取一个文件并执行以下任务

首先,它将新文件路径添加到相关的bin-n 元数据中,递增其版本号,使用bin-n 角色密钥对其进行签名,并将其写入VERSION_NUMBER.bin-N.json

然后,它获取最新的snapshot 元数据,更新其bin-n 元数据版本号,递增其自己的版本号,使用snapshot 角色密钥对其进行签名,并将其写入VERSION_NUMBER.snapshot.json

最后,快照进程获取最新的timestamp 元数据,更新其snapshot 元数据哈希和版本号,递增其自己的版本号,设置新的过期时间,使用timestamp 角色密钥对其进行签名,并将其写入timestamp.json

更新一致快照的bin-n 元数据时,快照进程**应该**还包括相关bin-n 元数据中任何新的或更新的简单索引页面的哈希。请注意,简单索引页面可能在 API 调用时动态生成,因此重要的是它们在一致快照的有效期内保持稳定。

由于快照进程**必须**以严格顺序的方式生成一致的快照,因此它构成了瓶颈。幸运的是,签名的操作足够快,可以每秒执行一千次或更多次。

此外,PyPI **可能**在生成相应的快照元数据之前向客户端提供分发文件。在这种情况下,客户端软件**应该**通知用户完整 TUF 保护尚未可用,但很快就会可用。

PyPI **应该**使用事务日志来记录上传过程和快照队列以进行审计,并在服务器故障后从错误中恢复。

清理旧元数据

为了避免由于不断生成新的快照而耗尽磁盘空间,PyPI **应该**定期删除旧的快照,即在过去一段时间内(例如 1 小时)被弃用的元数据和目标文件。

为了保留最新的快照,PyPI **可能**使用“标记和清除”算法。也就是说,从最新快照的根目录(即timestamp 通过snapshot 通过targets 和委托的目标)遍历到目标文件,标记所有已访问的文件,并删除所有未标记的文件。最后几个快照可以以类似的方式保留。

删除快照会导致客户端对该快照中任何文件的请求都只看到 HTTP 404 响应。然后,客户端**应该**重试其请求(如前所述)并使用最新的快照。

请注意,即使root 元数据已版本化,它也不是任何快照的一部分。PyPI **不得**删除旧版本的root 元数据。这保证了客户端可以更新到最新的root 角色密钥,无论其本地root 元数据有多旧。

撤销对项目和分发的信任

有时需要撤销项目或分发。要撤销对项目或分发的信任,关联的 bin-n 角色只需删除相应的目标并重新签名 bin-n 元数据即可。此操作仅需要使用在线 bin-n 密钥进行操作。

密钥泄露分析

本 PEP 涵盖了最低安全模型、应添加以支持分发持续交付的 TUF 角色以及如何为每个角色生成和签名元数据。其余部分讨论了 PyPI **应该**如何审核存储库元数据,以及 PyPI 可以用来检测和恢复 PyPI 泄露的方法。

表 4 总结了一些当一组阈值数量的私有加密密钥(属于 PyPI 的任何角色)被泄露时可能发生的攻击。最左边的列列出了已泄露的角色(或角色组合),其右侧的列显示了泄露的角色是否会使客户端容易受到恶意更新、冻结攻击或元数据不一致攻击的影响。请注意,如果 timestamp、snapshot 和 bin-n 角色存储在同一个在线位置,那么一个角色被泄露意味着它们都将被泄露。因此,表将这些角色一起考虑。一个单独考虑这些角色的版本包含在PEP 480中。

角色泄露 恶意更新 冻结攻击 元数据不一致攻击
targets **或** bins 否 timestamp 和 snapshot 需要协作
timestamp **和** snapshot **和** bin-n 是 受最早的 root、targets 或 bins 元数据过期时间的限制

表 4:通过泄露某些角色密钥组合而可能发生的攻击。在2013 年 9 月,有人展示了当时最新版本的 pip 如何容易受到这些攻击以及 TUF 如何保护用户免受这些攻击[14]

请注意,泄露targetsbins 并不会立即允许攻击者提供恶意更新。攻击者还必须泄露timestampsnapshot 角色,这两个角色都是在线的,因此更容易被泄露。这意味着,为了发起任何攻击,不仅必须能够充当中间人,还必须泄露timestamp 密钥(或泄露root 密钥并签名新的timestamp 密钥)。为了发起除冻结攻击之外的任何攻击,还必须泄露snapshot 密钥。在实践中,本 PEP 建议将snapshottimestampbin-n 密钥存储在一起,甚至对所有这些角色使用相同的密钥。因此,攻击者只需要泄露这台服务器即可执行上述任何攻击。请注意,客户端仍然受到非签名基础设施(如 CDN 或镜像)泄露的保护。此外,离线root 密钥将允许存储库通过撤销在线密钥来恢复攻击。

最大安全模型展示了 TUF 如何通过引入端到端签名的额外角色来缓解在线密钥泄露。有关如何生成开发者密钥和签名上传分发的详细信息,请参阅PEP 480

密钥泄露事件

密钥泄露意味着一组阈值数量的密钥(属于 PyPI 上的元数据角色)以及 PyPI 基础设施已被泄露并用于在 PyPI 上签名新的元数据。

如果一组阈值数量的timestampsnapshottargetsbinsbin-n 密钥已被泄露,则 PyPI **必须**采取以下步骤

  1. root 角色中撤销timestampsnapshottargets 角色密钥。这是通过用新发行的密钥替换被泄露的timestampsnapshottargets 密钥来完成的。
  2. 通过用新发行的密钥替换其密钥来从targets 角色中撤销bins 密钥。签名新的targets 角色元数据并丢弃新密钥(因为,如前所述,这提高了targets 元数据的安全性)。
  3. 所有bin-n 角色的目标**应该**与最后一次已知的良好快照进行比较,在该快照中,没有一个timestampsnapshotbinsbin-n 密钥被泄露。在泄露的快照中添加、更新或删除的目标,如果与最后一次已知的良好快照不匹配,**可能**会被恢复到其以前的版本。在确保所有bin-n 目标的完整性后,应在bins 元数据中更新其密钥。
  4. binsbin-n 元数据**必须**递增其版本号、适当地延长过期时间并更新签名。
  5. **必须**发出一个新的带时间戳的一致快照。

遵循这些步骤将先发制人地保护所有这些角色,即使其中只有一个角色可能已被泄露。

如果一组阈值数量的root 密钥已被泄露,则 PyPI **必须**采取上述步骤,并替换root 角色中的所有root 密钥。

也**建议**PyPI 使用安全公告充分记录安全漏洞。当使用带TUF的pip的用户无法安装或更新项目,因为时间戳快照角色的密钥不再有效时,这些安全公告将提供最有用的信息。然后,他们可以访问PyPI网站查看安全公告,以帮助解释他们为什么无法再安装或更新,并据此采取行动。当由于安全漏洞导致未撤销的密钥数量达到阈值时,可以使用阈值数量的现有密钥来签署新元数据的完整性,从而可以安全地更新新的元数据。TUF客户端将能够使用阈值数量的先前已知的密钥来验证新元数据的完整性。这将是常见情况。否则,在最坏的情况下,如果由于安全漏洞导致阈值数量的密钥被撤销,则最终用户可以选择使用带外机制更新新的元数据。

审核快照

如果恶意方破坏了PyPI,他们可以使用任何在线密钥对任意文件进行签名。具有脱机密钥的角色(即目标bin)仍然受到保护。为了安全地从存储库损坏中恢复,应审核快照以确保文件仅还原到受信任的版本。

当检测到存储库损坏时,必须验证三种类型的信息的完整性

  1. 如果存储库的在线密钥遭到破坏,可以通过让目标角色签署将新密钥委托给新密钥的新元数据来撤销它们。
  2. 如果存储库上的角色元数据已更改,这将影响由在线密钥签名的元数据。自上次期间创建的任何角色信息都应丢弃。结果,新项目的开发者需要重新注册他们的项目。
  3. 如果目标文件本身可能被篡改,可以使用上次期间存在的目标文件的存储哈希信息对其进行验证。

为了在发生损坏的情况下安全地恢复快照,PyPI**应该**维护少量自己的镜像,以按照某个时间表复制PyPI快照。镜像协议可以立即用于此目的。镜像必须是安全的和隔离的,以便它们只负责镜像PyPI。可以相互检查镜像以检测意外或恶意的故障。

另一种方法是定期生成快照的加密哈希并发布到推特。也许用户会提供实际的元数据,并且存储库维护者可以验证元数据文件的加密哈希。或者,PyPI可以定期存档其自己的快照版本,而不是依赖于外部提供的元数据。在这种情况下,PyPI**应该**获取存储库上每个目标文件的加密哈希,并将此数据存储在脱机设备上。如果任何目标文件哈希已更改,则表明存在攻击。

至于提供不同版本元数据的攻击,或将发行版的版本冻结在特定版本上,可以使用TUF通过隐式密钥撤销和元数据不匹配检测[2]等技术来处理。

管理更新流程的未来变更

如果对更新过程进行了重大更改,PyPI应在不中断现有客户端的情况下实现这些更改。有关如何执行此操作的一般指南,请参阅TAP存储库中的持续讨论。

请注意,此PEP对PyPI的更改将向后兼容。此PEP中未更改目标文件和简单索引的位置,因此任何现有的PyPI客户端仍然能够使用这些文件执行更新。此PEP增加了客户端使用TUF元数据来提高更新过程安全性的能力。

哈希算法过渡计划

如果用于对目标文件和元数据文件进行哈希计算的算法变得脆弱,则**应该**将其替换为更强大的哈希算法。

TUF元数据格式允许将来自不同哈希算法的摘要一起列出,以及算法标识符,以便客户端可以在算法之间无缝切换。

但是,一旦关闭对旧算法的支持,不支持新算法的客户端将只能通过禁用TUF验证来安装或更新软件包(包括客户端本身)。为了允许客户端过渡而不会暂时失去TUF安全保证,我们建议采用以下步骤。

  1. 在Warehouse中实现新算法。
  2. 重新生成现有的、未过期的TUF元数据,以包含使用旧算法和新算法计算的哈希值。所有新的元数据都将列出这两种哈希算法。请注意,只需要更新列出了目标文件或其他元数据哈希摘要的TUF元数据,即bin-n快照时间戳。因此,只需要在线密钥来签署更新的元数据。
  3. 在高可见度渠道(例如Python Discourse上的打包PyPI更改邮件列表)上宣布过渡。
  4. 让pip和bandersnatch等流行的客户端有机会采用新的哈希算法。
  5. 给最终用户机会更新客户端。
  6. 获得PyPI维护者大致的共识以从PyPI中删除旧的哈希算法。
  7. 删除Warehouse对旧算法的支持,只支持新算法。

附录 A:TUF 防止的存储库攻击

  • 任意软件安装:攻击者在客户端系统上安装任何它想要的软件。也就是说,攻击者可以提供任意文件以响应下载请求,并且这些文件不会被检测为非法。
  • 回滚攻击:攻击者向软件更新系统提供比客户端已看到的更旧的文件。这会导致客户端使用过时的文件。
  • 无限冻结攻击:攻击者继续向软件更新系统提供客户端已看到的相同文件。结果是客户端不知道有新文件可用。
  • 无休止的数据攻击:攻击者以无休止的数据流响应文件下载请求,从而对客户端造成损害(例如,磁盘分区已满或内存耗尽)。
  • 缓慢检索攻击:攻击者以非常缓慢的数据流响应客户端,这实际上会导致客户端永远无法继续更新过程。
  • 额外依赖项攻击:攻击者指示客户端为了安装他们想要的软件,他们还需要安装不相关的软件。此不相关软件可能来自受信任的来源,但可能存在攻击者可利用的已知漏洞。
  • 混合匹配攻击:攻击者向客户端呈现存储库的视图,其中包含在存储库中从未同时存在的文件。这可能导致例如安装过时的依赖项版本。
  • 错误的软件安装:攻击者向客户端提供一个受信任的文件,但这不是客户端想要的文件。
  • 恶意镜像阻止更新:控制一个存储库镜像的攻击者能够阻止用户从其他良好的镜像获取更新。
  • 易受密钥泄露的影响:能够泄露单个密钥或少于给定阈值的密钥的攻击者可以破坏客户端。这包括依赖单个在线密钥,例如仅受SSL保护,或单个脱机密钥,大多数软件更新系统都使用它来签署文件。

参考文献

致谢

本材料基于国家科学基金会第 CNS-1345049 号和 CNS-0959138 号赠款的支持。本材料中表达的任何意见、发现、结论或建议均为作者的意见,不一定反映国家科学基金会的观点。

我们感谢Alyssa Coghlan、Daniel Holth、Donald Stufft以及distutils-sig社区的帮助,他们帮助我们思考如何将TUF实用且高效地与PyPI集成。

Roger Dingledine、Sebastian Hahn、Nick Mathewson、Martin Peck和Justin Samuel帮助我们从其前身Tor项目的Thandy设计了TUF。

我们感谢Konstantin Andrianov、Geremy Condra、Zane Fisher、Justin Samuel、Tian Tian、Santiago Torres、John Ward和Yuyu Zheng在开发TUF方面做出的努力。

Vladimir Diaz、Monzur Muhammad、Sai Teja Peddinti、Sumana Harihareswara、Ee Durbin和Dustin Ingram帮助我们审查了此PEP。

Zane Fisher帮助我们审查和转录此PEP。


来源:https://github.com/python/peps/blob/main/peps/pep-0458.rst

上次修改时间:2023-10-11 12:05:51 GMT