securitynpmpackage-managers

What are the differences between and purposes of the NPM shasum, integrity, and signatures fields?


An example NPM package metadata JSON looks like this (with dist moved toward the top):

{
  "name": "lodash",
  "version": "4.17.21",
  "description": "Lodash modular utilities.",
  "dist": {
    "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
    "shasum": "679591c564c3bffaae8454cf0b3df370c3d6911c",
    "tarball": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
    "fileCount": 1054,
    "unpackedSize": 1412415,
    "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgMS3ZCRA9TVsSAnZWagAA8+4P/jx+SJ6Ue5oAJjz0L7gw\nLDD5YvP8aoliFq4GYkwUXfVQvOwomIPfa+U5Kao/hDfuwFQ/Bq5D5nSsl2bj\nrjJgvlKXna0SId8AgDgY2fB7zSfninuJvalY4iTWMN8DFSpG0XE2QFfoKpd3\njDmuzcNtgr79QV6DgjOVkHiP1IGNDlLTc1QEKiwo/5CdGQi1q/iCj6dViQMJ\nByuuuV2Qzi3f/FI25cG797WZar1MHhhlcnB50HiVBGp54IZOyuqdqWPduZQo\nvhONtonxPGBm3/J+uAkeUSSyL3Ud+FzLvdg8WEI9gDL0yvU4k0FcsnOONEYn\nngLaKEsw2xAnPBYW3Lf73Jnpwx6FAT3k49kgzxiNYSxEo7x4wiuNtBoDMyNw\nEKj6SZ0bUNmaJgiMfDnnDjCKjI3JrO1hho8z6CkwuvxuWLlW9wSsVayggzAI\nEhfeTeISugVHh332oDY2MI/Ysu8MnVN8fGmqeYQBBFj3aWatuA2NvVjACnX/\n54G7FtCU8TxZpm9shFRSopBx8PeI3r+icx1CT8YVFypY416PLnidHyqtME1G\neuRd1nWEz18hvVUAEHmuvHo+EPP3tITmTTUPQcZGMdBcZC+4UBmPMWX466HE\nbHw4aOnUWMa0sWfsERC5xzRZAb4lgMPEoTOnZyN4usMy7x9TzGZKZvU24HUE\nmpae\r\n=NOmG\r\n-----END PGP SIGNATURE-----\r\n",
    "signatures": [
      {
        "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA",
        "sig": "MEUCIF3Yithbtmy1aEBNlfNWbLswAfPIyQUuNUGARD3Ex2t4AiEA6TlN2ZKJCUpS/Sf2Z6MduF1BNSvayHIpu5wAcICcKXw="
      }
    ]
  },
  "keywords": [
    "modules",
    "stdlib",
    "util"
  ],
  "homepage": "https://lodash.com/",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/lodash/lodash.git"
  },
  "icon": "https://lodash.com/icon.svg",
  "license": "MIT",
  "main": "lodash.js",
  "author": {
    "name": "John-David Dalton",
    "email": "john.david.dalton@gmail.com"
  },
  "contributors": [
    {
      "name": "John-David Dalton",
      "email": "john.david.dalton@gmail.com"
    },
    {
      "name": "Mathias Bynens",
      "email": "mathias@qiwi.be"
    }
  ],
  "scripts": {
    "test": "echo \"See https://travis-ci.org/lodash-archive/lodash-cli for testing details.\""
  },
  "gitHead": "c6e281b878b315c7a10d90f9c2af4cdb112d9625",
  "bugs": {
    "url": "https://github.com/lodash/lodash/issues"
  },
  "_id": "lodash@4.17.21",
  "_nodeVersion": "14.15.5",
  "_npmVersion": "6.14.11",
  "_npmUser": {
    "name": "bnjmnt4n",
    "email": "benjamin@dev.ofcr.se"
  },
  "directories": {

  },
  "maintainers": [
    {
      "name": "mathias",
      "email": "mathias@qiwi.be"
    },
    {
      "name": "jdalton",
      "email": "john.david.dalton@gmail.com"
    },
    {
      "name": "bnjmnt4n",
      "email": "benjamin@dev.ofcr.se"
    }
  ],
  "_npmOperationalInternal": {
    "host": "s3://npm-registry-packages",
    "tmp": "tmp/lodash_4.17.21_1613835736675_0.01913912595366596"
  },
  "_hasShrinkwrap": false
}

Here are my questions related to the 3 fields:

Since we're here, too, how does dist.npm-signature relate to the 3 things above?


Solution

  • https://blog.npmjs.org/post/172999548390/new-pgp-machinery seems to have the answers you are looking for, in particular

    The shasum is a SHA-1 sum of the file. We’ve supplemented this to the side with an integrity field, based on the subresource integrity specification, to allow us to migrate to different hashing algorithms

    and

    The shasums above […] do not, however, protect against man-in-the-middle attacks. […] We offer you a way to detect this kind of tampering by signing package integrity fields along with some data that uniquely identifies the package-version. […] The registry signs the following data for each new package-version published: <package>@<version>:<integrity>. […] The detached signature is stored in the npm-signature field in dist.

    then https://docs.npmjs.com/about-registry-signatures says

    The public npm registry is migrating away from the existing PGP signatures [which were deprecated on April 25th 2023] to ECDSA signatures that are more compact and can be verified without extra dependencies in the npm CLI. […] Signatures are provided in the package's packument in each published version within the dist object.

    See also How does npm’s ECDSA signing system improve security?.