crates.io icon indicating copy to clipboard operation
crates.io copied to clipboard

Lessons from recent NPM password vulnerabilities

Open Diggsey opened this issue 7 years ago • 7 comments

See https://github.com/ChALkeR/notes/blob/master/Gathering-weak-npm-credentials.md for reference.

Cargo/crates.io is less affected than NPM, since it relies on github authentication for publishing, which one would expect to already be fairly well hardened against these kind of brute-forcing attacks. However, this doesn't prevent the use of leaked passwords and other human errors.

AFAICT, these are the only actions from the article which might apply to crates.io:

  • [ ] Notify package authors when a new version of a package they own is packaged (with opt-out)
  • [ ] Opt-in confirmation of package-publish on the website (in case a user's API key is leaked somehow)

These are some other possibilities:

  • [ ] Requiring 2FA for accounts with publish access to popular repositories (for example, more than N downloads). Publishing would be restricted until all users have 2FA enabled, or until the organisation has the "require 2FA" option enabled.
  • [ ] Opt-in confirmation of package-publish via a second maintainer

Diggsey avatar Jun 26 '17 23:06 Diggsey

Also maybe https://github.com/rust-lang/crates.io/issues/1667

rugk avatar Mar 13 '19 15:03 rugk

I'll bump this.

Recently a Ruby gem has been compromised via stolen credentials.

To reduce chance of this happening, a combination of:

  • e-mail notification after every publish,
  • requiring user to enter TOTP (AKA "Google Authenticator") code on every publish, or U2F key.

would be a big improvement for crates.io. This is what npm does already.

Note that I mean 2FA managed by Cargo+crates.io specifically. GitHub's own 2FA is not sufficient here, because ~/.cargo/credentials contains a token powerful enough to publish, and it's separate from GitHub, so it doesn't benefit from GitHub's security.

kornelski avatar Apr 04 '19 13:04 kornelski

In a situation like this, I think it's important to determine your threat models. I see multiple distinct risks discussed so far here.

  • Risk of a github account compromise due to password. As mentioned, you could require that cargo publishers must have 2fa on their accounts as indicated in the oauth token. This seems like a simple and easy change to proceed with.
  • Risk of .cargo/credentials compromise from a compromised host. This could be improved by having cargo's cli integrate with webauthn or totp to manage 2fa to crates.io, but this would now require crates.io to store 2fa material in addition to github. An alternate suggestion could be that the cargo tool can push to crates.io, but the "publishing" step must be finalised in the webui of crates.io - which can be prompted for via an email, and then visiting the site via a browser which then allows the github authentication and security policy to step in.
  • Risk that a single maintainer can publish without authorisation in a team environment. Ultimately this is a complex issue as there are many single owner crates, but many other high profile crates which have teams associated. A potential solution is that once a crate has 3 or more "owners", a policy can be enabled that one user can "push" from cargo, but that the notification and approval as mentioned above would be sent to the other team members and they need to finalise the operation. There would need to be appropriate mechanisms in place for account recovery here when maintainers leave which could push the number of owners to one.

I hope that this helps the discussion and clarifies what the problems seem to be from the outside.

Firstyear avatar Apr 10 '19 23:04 Firstyear

the cargo tool can push to crates.io, but the "publishing" step must be finalised in the webui of crates.io

I like that idea. :smiley:

rugk avatar Apr 11 '19 06:04 rugk

Another option to bolster access control around the publication of crates is to use a public-key infrastructure which allows developers to opt-into requiring end-to-end signatures for published crates.

The Update Framework a.k.a. TUF (see also https://github.com/rust-lang/crates.io/issues/75) supports a notion of "delegated targets" which allows developers to enroll digital signature keys and require releases are signed by them. This process is optional (TUF will still sign packages with a server-side key otherwise) but enables additional security which might be nice for widely used or security-sensitive crates. Using an end-to-end signature model can greatly reduce overall attack surface: TUF subdivides the functions of package registries like crates.io into various "roles", and enables what the original paper describes "survivable compromise" of certain roles including some of the currently most sensitive ones like generation of the index.

Python's PyPI is deploying TUF for this purpose (PEP 458) and they recently had a root key generation ceremony.

At one point I worked on an RFC for what a minimum viable TUF integration with crates.io might look like. It doesn't include the aforementioned "delegated targets" feature, but it paves the way for it: https://github.com/withoutboats/rfcs/pull/7

There are many options for securing digital signature keys used for package signing (and other sensitive functions). Hardware tokens like YubiKeys and SoloKeys (in the forthcoming V2 models) can be used to protect such keys from compromise and support a standard called PIV which can be used to create ECDSA/P-256 (or with SoloKeys, Ed25519) signatures. YubiHSMs (used by PyPI) can be used for keys where it would be useful to keep encrypted backups. Failing that, digital signature keys can be kept in the OS keychain (which on macOS devices can be optionally backed by a Secure Enclave Processor which can enforce things like biometric authentication).

If any of this sounds interesting to people, I'd be happy to help organize at least some general discussion, and perhaps we can look into dusting off my TUF RFC draft.

tarcieri avatar Feb 18 '21 19:02 tarcieri

This is being discussed again thanks to the fact that the exact same issue happened again with a prominent NPM package. The GitHub API now supports checking if 2FA is in use: https://docs.github.com/en/rest/reference/users#get-the-authenticated-user

leo60228 avatar Oct 25 '21 12:10 leo60228