Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

What is the current state of signed packages? #533

Closed
sam-github opened this issue May 13, 2019 · 15 comments
Closed

What is the current state of signed packages? #533

sam-github opened this issue May 13, 2019 · 15 comments

Comments

@sam-github
Copy link
Contributor

I'd like to kick off a discussion of what the best practice currently is for updating dependencies "securely", and what could be done to make the process more secure.

I've been reviewing the disparate threads around adding "security features" to Node.js. There seem to be two basic attack vectors they attempt to deal with:

  1. From the network (the traditional attacks)
  2. From dependent packages

The latter idea, that apps are vulnerable to malicious code in their dependent libraries, isn't qualitatively different between node and any other language that has thirdparty dependencies/libraries, but the ease of use of npm install, the number of packages in npmjs.com, and the granularity (https://www.npmjs.com/package/left-pad) arguably make node+npm quantitatively more vulnerable to injection of code via dependencies.

The most obvious protection against dependency-poisoning is to freeze your package dependencies and check the package integrity at install time, something npm and yarn do by default with package locking.

However, this just forces dependency updating into an explicit process. The deps still have to be updated sometime, and when they are, how is a user to know the dependency is safe to update? Having to audit the contents of every single dependency as it is updated is pretty daunting, so that's not much of a solution.

I've seen some comments to the affect that "signing npm packages" would solve this problem, but I don't think that stands up to scrutiny. npm already checked the identity of the package publisher *, the problem is whether I trust that publisher.

* In theory. The theft of that eslint publisher's credentials is an example of the check not working. 2FA might have helped there, and signing would have, but if a publisher has their identity stolen, they could have their gpg signing keys stolen, too.

I've been considering two ideas (I don't claim credit for them, I think @rmg suggested at least one of them):

  1. An npm install mode where deps do not get installed unless they were published with 2FA.
  2. The ability to publish signed "attestations" (somewhere...), where the attestation could be "I state the license is correct" or "I state that I have audited this package version", along with a tool that would report on unattested versions. It would be the responsibility of each user to decide who they trust as "attestors".

So, to kick off the conversation:

Is either of those capabilities useful? What other suggestions does anybody have? Is there any ongoing work to help with the "secure dependency update" process? Is a good npm audit enough, even though its after the fact, and people should be more concerned with actively monitoring of their deployed apps for newly reported vulnerabilities? Is it even worth discussing updates to the npm client here, given that its controlled by npmjs.com?

And even if changes to npm install were useful, is there any practical way to achieve them? Maybe npm should just decline non-2FA publishes, so that 1 would go away?

@bmeck
Copy link
Member

bmeck commented May 15, 2019

@sam-github is the intent to only do this check when they are installed / not when the code is to be run? If so that is outside of the node runtime and more up to the different package managers.

I'm not sure that signing will be of much use without enforcing a form of trust and revoking trust, maybe looking at https://github.com/WICG/webpackage (not just for browsers) would be informative here since it has a CA/signing model in mind that is applied to bundles of files.

Is the goal here to assert the signing party's identity or to also produce a revocation infrastructure as well?

@mhdawson
Copy link
Member

I think that being able to do the checks when the code is run as well. Would give devops a tool to validate any restrictions on modules a company wants to enforce.

@bmeck
Copy link
Member

bmeck commented May 16, 2019

@mhdawson can you clarify a bit, we do have policies which apply integrity checks per file. In particular it does this as runtime mutation and installation scripts can alter the integrity of when something was downloaded vs when it was run.

@mhdawson
Copy link
Member

@bmeck that might be part of the tooling do the check but as you mention there are other aspects related to establishing trust.

@bmeck
Copy link
Member

bmeck commented May 17, 2019

@mhdawson yes, I was intentionally vague. I am wondering what parts of trust are being sought and to handle what kind of threats. If we have proof of authorship that cannot be repudiated that is only useful if we revoke trust at authorship level instead of file/package/etc. level. If we have revocation to deal with loss of trust however that can be handled at the integrity level of each of file/package/etc. I am still unsure what the exact desire for adding to a trust model is being expressed and I want that to just be cleared up a bit. I do think signing has some nice things, but almost only about revocation to my knowledge given things like event-stream that did come from a trusted publish of a package. Signing event-stream would not have prevented the problem, nor would it have helped detect the problem if it was deployed compared to integrity checks. One of my great fears with this, is a lack of clarity on how big a task adding a trust model via PKI would be. One of my reasons for pushing for WebPackage to handle this is that it already has review and uses a trust model that Node.js already has via TLS certs.

@sam-github
Copy link
Contributor Author

@bmeck It sounds like you are nostly talking about package signing. As I said (" I don't think that stands up to scrutiny") npm already asserts identity of package publisher at time of publish, and integrity of package at time of package install. Webpack has a different distribution model, webapps download their deps at runtime via https, so it needs signatures/revocation, but otherwise doesn't help with knowing a particular version of a package is trusted to not contain malicious code.

I believe the core problem is:

how is a user to know the dependency is safe to update?

Basically, npm has packages (of many versions), but people don't trust them. They were securely uploaded, and securely downloaded, but we don't know if a specific package version contains malicious code.

Can we do anything about that? Is there any ongoing work on that specific problem?

Debian deals with this by only allowing package uploads from very carefully vetted people. Their mantra is "every debian developer has root access to every debian box". npm has the same problem, there is a sense in which every npm package author who can upload a new version of an npm package can inject code into any app that uses that package. But, npm can't (and won't, its impossible) make the same kind of trust checks for npm package authors as debian does for its developers, it leaves it up to the user.

And as users, we don't know how to decide if we trust.

Mostly, trust is done in an after-the-fact wait-for-problems kindof way. npm audit and the like are an example of that. We tentatively trust the authors of our dependent packages, until someone finds that trust was misplaced (either a package is deliberately malicious, or more commonly, the package has an accidental security problem), and npm audit starts to tell you that you have a problem.

So, to say it again: I don't think package signing does anything npm doesn't already do, and doesn't help with that problem. I think you agree:

Signing event-stream would not have prevented the problem,...

but then you sound like you are suggesting package signing for npm packages is useful, using webpack packages?

One of my reasons for pushing for WebPackage to handle this...

So, I'm a bit confused about whether you are saying signing can already be done using webpack, or saying webpack-signing can help us trust publishers (I am not convinced of the latter).

The node file integrity checks ("policies") aren't relevant to the problem of trusting a package. They help with attack vector 1. from my description (network attackers somehow mutating the files on disk of a live deployment). They also have niche value, most deployments are better off using the same mechanism that is required to securely protect the policy file (making it read-only to the user ID running the app) on the entire app, making the policy file unneeded.

The heart of my question is this:

Is there any ongoing work to help with the "secure dependency update" process?

So, I am not proposing any good great solutions, just floating some ideas.

One idea was an attestation framework, see description, and I fully realize its unusual, far fetched, and hard to deploy.

The other more realizable idea is that npm either mandate 2FA for all package publishing (would have helped with the eslint publish credential theft of last year), or allow users to require 2FA for any package they install. This doesn't protect against malicious publishes from actual maintainers, but would help against malicious publishes by non-maintainers using stolen credentials.

Are there any other works in progress or ideas floating around to allow us to trust packages, and/or package authors?

@bmeck
Copy link
Member

bmeck commented May 17, 2019

It sounds like you are nostly talking about package signing.

That was what I thought this topic was about.

Can we do anything about that? Is there any ongoing work on that specific problem?

The efforts in this are revolve around moving to a least privilege approach, these are talked about in the Realms calls weekly on Thursdays by various interested parties. Some contributors to Node do participate, but ongoing efforts for this are slow going a high level overview of the plan that was laid out last year as a possible approach is here.

And as users, we don't know how to decide if we trust.

Yes, some tooling is being made to audit what a package needs for authority before install such as this PoC; however, without a more robust Node core it is difficult to actually provide any guarantees and some efforts are being investigated.

Essentially the UX workflows being investigated are intended to allow a similar workflow to browsers/phones/etc. where you approve a feature before it is used. Users would approve that a library has access to features prior to installing.

but then you sound like you are suggesting package signing for npm packages is useful, using webpack packages?

WebPackage from WICG , not webpack the bundler. Revocation does have value for automated auditing and for preventing critical flaws. However, it is hard to do correctly and you can look up various ways that people have worked around OS level signing infrastructures for more info. The main gain from this is the ability to form longer chains of trust and to revoke trust at different levels using those chains. Effort towards this seems like something that is not a low hanging fruit and can largely be achieved using audit tools on a chron and integrity files.

The node file integrity checks ("policies") aren't relevant to the problem of trusting a package. They help with attack vector 1. from my description (network attackers somehow mutating the files on disk of a live deployment). They also have niche value, most deployments are better off using the same mechanism that is required to securely protect the policy file (making it read-only to the user ID running the app) on the entire app, making the policy file unneeded.

Not necessarily, if the policy file itself has an integrity that would also mitigate those attacks. In addition, most applications ideally should run with the entire fs being immutable, but thats not the typical cloud or desktop environment. Policies are meant to work in the mutable state of fs that the typical Node application lives within such as running commands from a desktop.

Per From dependent packages this also is unaffected by signed packages, I don't understand the relation again to the issue title/topic. Dependent packages are intrinsically tied to package installation and need to upstream approvals into policy files (this is true even if we use keys for signing since we have to create policies for what features the keys are allowed to grant).

This doesn't protect against malicious publishes from actual maintainers, but would help against malicious publishes by non-maintainers using stolen credentials.

Were there recent examples of publishes by non-maintainers? ESLint comes to mind, but I can't think of others. Certainly an audit of packages for malicious authority usage could also expose usage of non 2FA protected packages.

@mhdawson
Copy link
Member

I'm less interested in packages being signed by the publisher, but a way for one or more third parties to sign modules after vetting them.

@lirantal
Copy link
Member

What other suggestions does anybody have? Is there any ongoing work to help with the "secure dependency update" process? Is a good npm audit enough, even though its after the fact,

What do you think about npq ?
We could add more checks and validations into it so it can be more powerful for a pre-install check

@bmeck
Copy link
Member

bmeck commented May 20, 2019

@lirantal I think what @mhdawson is asking about is doing this check at runtime instead of install time (@mhdawson can you clarify)?

@lirantal
Copy link
Member

I think that being able to do the checks when the code is run as well. Would give devops a tool to validate any restrictions on modules a company wants to enforce.

For runtime we have solutions like integrity checks, and experimental permissions like with anna's PR.

An npm install mode where deps do not get installed unless they were published with 2FA.

For pre-install we don't really have anything, that's what npq aims to solve.

I think though we might have derailed the original issue's question about signed packages...? Perhaps let's try to get back on track for that and open other issues so discussion can be focused.

@mhdawson
Copy link
Member

@bmeck you are correct that I was talking about runtime

@sam-github
Copy link
Contributor Author

@mcollina You just mentioned npm exposing package metadata for whether a package was published with 2FA, see the issue description here, I also think it would be useful.

@sam-github
Copy link
Contributor Author

@ahmadnassri suggested I post an idea to npm's community forum to suggest exposing 2FA metadata for packages, see https://npm.community/t/expose-metadata-about-whether-a-package-was-published-with-2fa/8431

@bnoordhuis
Copy link
Member

The ability to publish signed "attestations" (somewhere...) [..] It would be the responsibility of each user to decide who they trust as "attestors".

This "web of trust" approach is interesting although I could see it merely moving the issue of trust from packages to attesters.

On the other hand, it's more diffuse (no single entity to take over, unlike a package) and therefore harder to game, hopefully.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants