berstend / node-safe

🤠 Make using Node.js safe again with Deno-like permissions

Home Page:https://node-safe.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[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 through puppeteer 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 a manifest.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.

commented

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:

  1. Create multiple Sandboxes; put modules with similar profiles in the same sandboxes. Communications are done via IPC
  2. 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.