Feature Request: Package Permissions
Closed this issue · 9 comments
Problem: Malicious packages
With the recent news of the event-stream/flatmap-stream
attack (summary), it seems like now would be a good time to discuss defending against these kind of attacks.
Presently available defences:
- use a lockfile
- fully audit the published code of entire dependency tree
While a lockfile is generally good practice, it would require auditing to be effective. There lies the issue, auditing is not feasible. Dependency graphs are too large in most modern projects to effectively audit manually.
Suggestion
One defence is to introduce permissions for node core modules such as fs
, http
, process
, and others.
A package.json
would need to specify which core modules it uses, ex:
{
"name": "package-name",
"version": "1.0.0",
"description": "",
"main": "index.js",
"permissions": [
"fs"
]
}
Restrict import/require such that requiring http
in this package would throw an error, but fs
would be permitted.
Each package would be provided a uniquely restricted import/require.
For backwards compatibility packages without a permissions, would be considered to have all permissions. This could be deprecated in favour of always requiring a permissions field.
Additionally tooling could be developed for package managers such as yarn and npm. Users could be alerted when permissions have changed anywhere in their dependency graph. Upon install of a dependency the user could be prompted with accepting the permissions for all packages added to the dependency graph.
This is not intended to eliminate the need for auditing, but could reduce the amount of packages needing audits to a reasonable level.
Outstanding Issues
- What to do with C++ addons? Being able to identify them as such may be enough, during install the user could be warned that module has full access to their system (equivalent to all permissions).
- Permissions of main package during development, build scripts, ect.
Other Defences
- Content security policy / sandboxing (restrict access to white-listed directories, and domains)
@nodejs/security-wg
(Should this be moved to the security-wg repo for discussion? I'm inclined to say "yes". Otherwise, discussion will be fragmented. This is already being discussed there.)
Refs: nodejs/security-wg#327
It is the same feature isn't it? I think @addaleax worked on some efforts into that direction. I'd merge the threads.
@Trott not apposed to moving the discussion there.
@dgonzalez not quite from what I can tell that is directed at restricting what the process has access to. Where as this is a per module restriction. Process restriction does not defend against malicious modules.
One thing to note: Node.js does surprisingly little with package.json. Most of the magic with package.json is in npm. There may be resistance to the idea that Node.js should parse and understand more package.json than it already does. A lot of feature requests come in the form of suggesting some package.json configuration and they are (as far as I've seen, anyway) always rejected. As I recall, the primary concerns tend to be:
- having one more place for configuration stuff (in addition to environment variables and CLI flags) makes debugging/troubleshooting more challenging
- likelihood of breaking someone's app out there, as people add all sorts of things to package.json for all sorts of reasons, and we're likely to collide with someone's existing keys
- package.json is regarded by many (including Node.js creator Ryan Dahl) as a mistake in the first place and adding more stuff to it exacerbates that
- performance impact of the overhead of additional parsing on startup
@robbiespeed Yes, it’s not quite the same thing – it’s the best thing I could think of that has no measurable runtime overhead.
If somebody comes up with a system for implementing per-package permissions, I’d love to that, and I could probably spend some time to help implement it.
That's a topic we've been discussing in the WG since last summer. TBH, it seems pretty hard right now to have a silver bullet strategy that would not break the ecosystem or not have some kind of bypasses: a lot of JavaScript objects are global and only instanciated once per thread and anyone can override them (e.g. change the function String.prototype.indexOf
).
So far, we would need to get a realm-like strategy around module loading (and there is an ongoing work involving @bmeck on that if I'm not mistaken).
Because of this I am usually a supporter of the per-process approach as of @addaleax 's PR as this is a good first feature set IMO (preventing your ESLint from having network access).
Due to recent events, there is definitely a need for a solution to introduce better trustability in dependencies loading. Another approach by @bmeck is to allow dependencies policies checks at runtime (see PR #23834). This is another approach I believe we should follow.
I remember trying to find equivalent features in other ecosystems and did not find much. @robbiespeed do you know if any platform already has such?
I'm going to close out this issue because otherwise we end up with discussion that's scattered all over the place. Let's use nodejs/security-wg#327 as the canonical place.
When you move it there, keep in mind that in some contexts a global require() function exists (the REPL, node -e '...'
); that will need to be addressed.