2025年3月,Python软件包索引(PyPI)官方博客发布了一项重要安全变更:自即日起,任何已发布的软件版本在14天后将不再接受新文件的上传。这意味着,当开发者将一个版本(如1.2.3)推送到PyPI后,仅有14天的窗口期用于替换或补充该版本的安装文件(如.whl、.tar.gz等)。超过期限,该版本将被“冻结”,所有文件内容不可更改。这一改动旨在从源头上阻断恶意软件通过“后门文件替换”手段入侵开源生态。
背景:为何是14天?
PyPI是Python生态中最为核心的包分发平台,每天处理数百万次下载。然而,随着供应链攻击日益猖獗,PyPI也曾多次爆出恶意包事件。攻击者常用的一种手法是:先上传一个看似正常的包版本,经过一段时间(甚至等到该包被大量用户采纳后),再悄悄上传一个带有恶意载荷的新文件到同一版本下。由于PyPI之前允许随时覆盖或追加文件,受害者通过pip install package==1.2.3总能获取到最新上传的那个文件,而无法知晓内容已被篡改。
这种“迟发型投毒”极难防范:用户检查了早期版本的哈希值,但后续下载到的却是另一份文件。安全研究人员将其视为“软版本锁定漏洞”。PyPI官方在博客中坦言,这是长期存在的设计缺陷,也是社区反馈最强烈的安全问题之一。
新规细则:14天窗口期如何运作?
根据PyPI博客的说明,新规则适用于所有通过pypi.org上传的发布版本:
- 新版本发布后,维护者有14天时间向该版本添加新文件或替换已有文件。所有文件的上传时间戳均被记录。
- 14天期满后,该版本的“文件上传”功能自动关闭。任何尝试通过API或Web界面上传文件的操作都会返回错误。
- 该版本本身不会被删除或锁定。用户仍可下载之前的文件,但内容已不可变更。
- 如果必须修复紧急问题,维护者应发布一个新的版本号(如从1.2.3升级到1.2.4),新版本将获得新的14天窗口。
这项变更立即生效,但PyPI对历史版本也做了回溯处理:此前已发布超过14天的版本,从公告之日起就视为已冻结。
对开发者和用户的影响
对于绝大多数合规的开源维护者,14天窗口足够进行快速迭代。常见的场景包括:发布后修复打包错误(如遗漏某依赖)、更新文档字符串、或替换被签名的二进制文件。但若遇到需要长期修补的情况(如安全热修复未及时准备),则必须遵循语义化版本规范,发布修订版本。
对于包的使用者,变化无疑是积极的。因为一旦你指定安装某个版本,即使过了几天,获取到的文件哈希值与官方签名的记录完全一致。PyPI同时计划在项目页面上显示“文件冻结时间戳”,帮助用户判断该版本是否已处于不可变状态。
不过,该政策也带来新的挑战:跨平台的构建可能因CI/CD流水线延迟而错过14天窗口。例如,某维护者在发布当天仅上传了纯Python的wheel,但随后又花费3天来构建Windows和macOS的二进制wheel——如果整个过程超过14天,那么后续的二进制文件将无法添加到同一版本。建议维护者提前在预发布阶段准备好所有平台的构件,或采用自动化脚本在发布后尽快上传。
生态对齐:PyPI与业界安全趋势
此次更新并非孤例。npm早在2021年就实施了“发布锁定”,禁止在版本创建后修改tarball内容;RubyGems也限制了对已有版本gem的替换。PyPI的14天窗口期比npm的24小时更为宽松,兼顾了Python生态中大量使用多平台轮子的现实。同时也保留了严格的不可变记录,与Maven Central的“一旦发布不可撤改”原则逐步看齐。
PyPI安全团队表示,未来还将进一步缩短窗口时间,但目前14天是权衡了各方意见后的起点。此外,PyPI已强制要求关键项目使用双因素认证,并开始实施“包名混淆检测”机制,此次文件锁定是保障供应链安全的又一关键拼图。
社区反馈与下一步
公告发布后,PyPI官方博客留言区和Reddit的r/Python板块讨论热烈。多数开发者表示支持,但也有维护者担心“14天不够应对复杂的跨架构测试”。对此,PyPI鼓励维护者使用预发布版本(如1.2.3.dev1)进行前期验证,正式版本则集中快速上传。另外,PyPI正在开发“延迟上传预约”API,允许维护者在发布时预先提交所有文件,从而规避时间压力。
总结而言,14天文件冻结规则是PyPI在可信分发道路上迈出的坚实一步。它直接消除了版本内文件被篡改的风险,让“版本号即不可变标识”不再是一句空话。对于每个依赖PyPI的开发者而言,值得立即检查自己的发布流程,确保在14天内完成所有文件的同步上传,否则就必须用新版本重新“计时”。在开源供应链安全日益受到关注的今天,这一改变将极大提升用户对Python软件包的可信度。