yarnpkg / berry

📦🐈 Active development trunk for Yarn ⚒
https://yarnpkg.com
BSD 2-Clause "Simplified" License
7.42k stars 1.11k forks source link

[Feature] Verifying Yarn release binaries #3636

Open jonahsnider opened 3 years ago

jonahsnider commented 3 years ago

Describe the user story

Without a way to verify release files Yarn users may be vulnerable to PRs which introduce malicious code to the local Yarn binary.

Thankfully, this is not a problem unique to Yarn. In the past this has been solved with release signing (not really possible for Yarn) or by publishing the hashes of release files. Gradle wrappers are susceptible to the same issue.

Describe the solution you'd like

The solution Gradle found was to publish the hashes of release binaries and create CI integrations to help users verify them automatically.

Yarn should publish hashes alongside releases and create tooling for verifying them. If possible something similar should be done for plugins.

Describe the drawbacks of your solution

Including hashes with each release introduces some extra complexity to the release process. It would also require maintaining verification tooling/CI integrations.

arcanis commented 3 years ago

This is intended to be solved in part with Corepack, which will let you avoid having to check-in the Yarn binary into your repository. You can already benefit from it if you upgrade your project to Node 16.9+ and instruct everyone in your team to run corepack enable.

Corepack aside, having a signing and verification infrastructure isn't easy and I'm not sure we'll be able to address that for now. In the meantime you can restrict upgrading the binary to known people.

peey commented 3 years ago

In the meantime you can restrict upgrading the binary to known people.

I think this advisory should be added (along with an explanation of the issue) at https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored

peey commented 3 years ago

This is intended to be solved in part with Corepack, which will let you avoid having to check-in the Yarn binary into your repository. You can already benefit from it if you upgrade your project to Node 16.9+ and instruct everyone in your team to run corepack enable.

I believe there would need to be one more effort on yarn's part to make it true that corepack users should be immune to unverified yarn binaries.

I think currently, irrespective of where the command yarn was installed from, when it runs it looks up yarn-path and delegates all command-running to yarn-path.

I think that yarn would have to detect if it's running under corepack, and if so then use the yarn-path (and any other configuration) to only determine which yarn version is suitable and communicate that to corepack, and then use the corepack installation to continue, without honoring yarn-path.

If this breaks backwards-compatibility, I'd still like to make a case for implementing this under an experimental flag. The case being that it may help early adopters check out corepack+yarn, which could provide feedback to both the projects and help them both work better together in the future.

peey commented 2 years ago

I also noticed that similar security concerns are present in yarn pnp https://github.com/yarnpkg/berry/blob/8afcaa2a954e196d6cd997f8ba506f776df83b1f/packages/gatsby/content/features/zero-installs.md#does-it-have-security-implications

And yarn team has already foreseen the issue and provided a --check-cache command which verifies the files by checksum.

I'd like to know if such a flag is already supported / could be supported for the yarn-path binary.

What makes this issue more insidious than cache verification is that it seems yarn delegates to yarn-path immediately. This means a malicious yarn-path file could actually, say fake the --check-cache check itself. So I think at least the same level of care as pnp cache verification (if not greater) is needed for this issue.

peey commented 2 years ago

@arcanis is it possible to extract yarn version from an untrusted repo and use that version to get a trusted release binary from a trusted server (e.g. wherever yarn downloads from in the first place), without invoking the yarn binary in package?

If someone wishes to implement any kind of solution to this issue (matching a hash / downloading independent release binary) inside of yarn or as an independent tool (even at corepack level as you suggested), I believe that's the absolute minimum support that'll be required from within yarn itself.

joshwlewis commented 1 year ago

I'm also interested in seeing some additional support for binary verification, but my use case is a bit different.

At Heroku, our buildpack can install the yarn 1.x series into customer apps from our own mirror. We haven't yet added the yarn 2+ release lines to our mirrors, because we can't be sure what we mirror or install into the customer app hasn't been tampered with by a MITM attack.

Corepack aside, having a signing and verification infrastructure isn't easy and I'm not sure we'll be able to address that for now.

Indeed the infrastructure isn't simple. And I wonder if registry.npmjs.com's existing signature infra would make things easier. I can verify npm, yarn (1.x), and pnpm tarballs against checksums and signatures published by the registry (e.g. npm view yarn dist). Really, yarn 2+ is the only package manager that this doesn't work for, since AFAICT, the yarn 2+ binary isn't published as a part of any npm package. If there was an npm package with the binary included (maybe @yarnpkg/cli?), that might be a bit easier than rolling your own signing/checksums here?

arcanis commented 1 year ago

I can verify npm, yarn (1.x), and pnpm tarballs against checksums and signatures published by the registry (e.g. npm view yarn dist).

If we assume that the https layer between https://repos.yarnpkg.com and you can be broken and a MITM attack performed, can't we say the same from the layer between https://registry.npmjs.org and you? Since the registry-provided checksums come from the same domain that serves the tarballs, I'm not sure they provide a significantly better security - an attacker could just MITM both the checksum and the tarball 🤔

(I'm however not an expert, so if I'm very wrong I'm interested to learn about anything I might be missing)

the yarn 2+ binary isn't published as a part of any npm package.

It's published as part of @yarnpkg/cli-dist.

joshwlewis commented 1 year ago

If we assume that the https layer between https://repos.yarnpkg.com/ and you can be broken and a MITM attack performed, can't we say the same from the layer between https://registry.npmjs.org/ and you? Since the registry-provided checksums come from the same domain that serves the tarballs, I'm not sure they provide a significantly better security - an attacker could just MITM both the checksum and the tarball 🤔

Yes, you are correct about the checksum portion. However, the registry's public signing key (available here) can be stored in code or config at a time when uncomprimised. Later, when the connection might be comprimised, verifying the signature (from npm view @yarnpkg/cli-dist dist.signatures) should fail, because the attacker can't generate a valid signature without the matching private signing key.

It's published as part of @yarnpkg/cli-dist.

Perfect, this should work for me! I searched several times for a package that might work, but I think npmjs.com was truncating the search results.

MatthiasKunnen commented 1 year ago

Perhaps this should be extended to the plugins downloaded to .yarn/plugins such as @yarnpkg/plugin-workspace-tools?