发布到公共 npm 注册表的包已签名,以便检测包内容是否被篡改。

对已发布包进行签名和验证可以防止攻击者控制注册表镜像或代理,从而拦截和篡改包 tarball 内容。

从 PGP 迁移到 ECDSA 签名

注意: 基于 PGP 的注册表签名于 **2023 年 4 月 25 日** 被弃用,并被 ECDSA 注册表签名取代。

公共 npm 注册表正在从现有的 PGP 签名迁移到 ECDSA 签名,ECDSA 签名更紧凑,可以在没有 npm CLI 中额外依赖的情况下进行验证。

签名验证以前是一个多步骤过程,涉及 Keybase CLI,以及手动从包元数据中检索和解析签名。

了解有关使用 npm CLI迁移和验证签名的更多信息。

支持第三方注册表上的签名

如果遵循以下约定,npm CLI 支持任何注册表提供的注册表签名和签名密钥

1. 签名在包的 packument 中提供,在每个已发布版本内的 dist 对象中

"dist":{
..omitted..,
"signatures": [{
"keyid": "SHA256:{{SHA256_PUBLIC_KEY}}",
"sig": "a312b9c3cb4a1b693e8ebac5ee1ca9cc01f2661c14391917dcb111517f72370809..."
}],

查看来自公共 npm 注册表的已签名包的示例

要生成签名,请对包名称、版本和 tarball sha 完整性进行签名:${package.name}@${package.version}:${package.dist.integrity}

当前最佳实践是使用密钥管理系统,该系统在硬件安全模块 (HSM) 上执行签名操作,以避免直接处理私钥部分,从而减少攻击面。

keyid 必须与以下公共签名密钥之一匹配。

2. 公共签名密钥在 registry-host.tld/-/npm/v1/keys 中以以下格式提供

{
"keys": [{
"expires": null,
"keyid": "SHA256:{{SHA256_PUBLIC_KEY}}",
"keytype": "ecdsa-sha2-nistp256",
"scheme": "ecdsa-sha2-nistp256",
"key": "{{B64_PUBLIC_KEY}}"
}]
}

密钥响应

  • expires: null 或简化的扩展ISO 8601 格式: YYYY-MM-DDTHH:mm:ss.sssZ
  • keyid: 公钥的 sha256 指纹
  • keytype: 当前仅 npm CLI 支持 ecdsa-sha2-nistp256
  • scheme: 当前仅 npm CLI 支持 ecdsa-sha2-nistp256
  • key: base64 编码的公钥

查看来自公共 npm 注册表的示例密钥响应