[feature discussion] granular permissions for packages
clouedoc opened this issue · comments
Would it be desirable and technically feasible to define package-based configurations instead of project-based configurations?
I.e.:
- allowing
got
to access the internet - allow
puppeteer
to access/tmp
and the internet to store Chrome profiles. - allow
random-ssh-client
to access~/.ssh/id_rsa
Thanks for starting the discussion on packages 😄
(This is a more long form answer with context, as the project is new and it might be a good reference)
Behind the scenes:
- We only get to define sandbox permissions once when launching a process (we cannot modify the permissions on the fly afterwards for that process or for child processes that are spawned)
- The macOS sandbox has no notion of "packages" - we simply instruct it to launch the
node
process with the permissions we generated earlier
Would it be possible to define package-based permissions?
- Yes, we can simply parse the
package.json
file (if any) and it's list of dependencies to understand what packages are used in a project
Caveats:
- Not every invocation might use all packages listed in the dependencies (e.g.
npm run build
would probably not run Chrome throughpuppeteer
and therefore doesn't need these extra permissions)
Where would these package permission definitions come from?
- Initially, while prototyping
node-safe
, I thought about having packages provide amanifest.json
like file for their permissions, but we can't trust anything the dependency tells us as it might've been compromised 😄 - We could maintain a repo of permissions for popular projects (similar to the
@types
project) - this would be really cool but without proper community support not really feasible. On the other hand: Most dependencies probably don't require special permissions outside their project folder, so the list of packages that require special permissions might not be too crazy to maintain - The user could define per-package permissions themselves: This would be quite cumbersome and probably brings no real benefit over using the already supported per-script permissions? 🤔
Overall the next step of the node-safe
project is to figure out where to go with the sandboxing idea, to make it really frictionless so it's a no brainer to use sandboxing by default.
In #2 I'm discussing the idea of supporting a default config file that would scope all permissions to the project folder (and temp) by default, which should make most common projects work out of the box without the need to configure anything.
We're still in the early days of this project but I'm eager to build something that is useful for myself, working on this made me acutely aware of the madness of not sandboxing random code from the internet. 😄
Thinking about it: Using a default configuration file mentioned in #2 in combo with package name specific extra permissions (defined in the default file) makes a lot of sense:
We get good security by default with zero work for everything we work on and when using packages like puppeteer we only need to add their name and special permissions once to our default config and whenever puppeteer is used anywhere the extra permissions will apply automatically.
How exactly would such feature work? Will it still be a set of permissions for a single process, but now needed permissions would be automatically enabled/disabled according to used packages?
Having read discussions about module-based granular permissions in deno repos, it seems like there's no simple way to detect what code belongs to what package and what permissions it should have. For example, a library might take user function as callback
Here are some ideas:
- Create multiple Sandboxes; put modules with similar profiles in the same sandboxes. Communications are done via IPC
- Mark user function callbacks with read-only Symbol at startup by analysing the codebase. Hook NodeJS low-level APIs and check the call stack to see functions permissions.
I wonder if the new permissions API + nodejs/node#47855 can be used for this.