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

requires - require modules securely (restricted access to fs,net, etc) #29788

Closed
Z3TA opened this issue Oct 1, 2019 · 11 comments
Closed

requires - require modules securely (restricted access to fs,net, etc) #29788

Z3TA opened this issue Oct 1, 2019 · 11 comments
Labels
deprecations Issues and PRs related to deprecations. experimental Issues and PRs related to experimental features. policy Issues and PRs related to the policy subsystem.

Comments

@Z3TA
Copy link

Z3TA commented Oct 1, 2019

problem: When you use third party modules, they often have a lot of dependencies, and it only takes one compromised module out of tens of thousands to infect your own app with a backdoor, that might steal your .ssh keys or crypto wallet, or create a remote shell.

solution: A new function "requires" (require securely) that works similar to require, but does not give access to fs, net, os, native (and others) built in modules unless specifically allowed when requiring the module.

const foo = requires("bar", {fs: true, net: "0.0.0.0:8000", os: true});

First parameter is the module name (bar), and the second parameter is the settings object; which specifies what native modules can be used.
If the value is truthy, it will be allowed.

Further settings can be specified as a string or object (for future refinement) eg. if we want to add the option to restrict port and IP.

Alternatives are Realms and SES (Secure ECMAScript), but I think requires will be easier to implement, and easier for the user/developer to require modules securely.

Currently you can restrict your app using Linux namespaces, se_linux, Apparmor, user access, etc, but then it will apply to your whole app! The idea is to make restrictions to individual modules and their dependencies!
With "requires" you can give for example file-system (fs) access to only the modules that actually need it.

Additional request:
If "requires" is implemented, effort should be taken in order to make it fast, see: #29789

@Z3TA Z3TA changed the title requires - require modules securely (restricted access) requires - require modules securely (restricted access to fs,net, etc) Oct 1, 2019
@mscdex
Copy link
Contributor

mscdex commented Oct 1, 2019

You're probably looking for policies. However, simply turning module support on and off doesn't help you that much, since modules with say fs access enabled, could still unintentionally read/write from/to sensitive files. Ultimately you will probably want protection at the OS layer instead.

@Z3TA
Copy link
Author

Z3TA commented Oct 1, 2019

Right now a malicious actor could target any module, no matter if it reads from the file system or not. With module granular security, the bad actor would have to target a module that already read from the file system. To limit reads further, the fs module could have a virtual "root" and filters, for example:

const foo = requires("bar", {fs: {read: ["/home/someuser/.dotconfig/", "/home/someuser/data/"], write: ["/home/someuser/data/"]}})

Security is best applied using several layers. We need an additional layer that will be simple to use, and work on all platforms.

Depending what paradigm is used to code the Node.JS app, probably you would not like modules to have side effects like writing to fs or net. Instead you will want to have the module return data, and write to the fs using your main.js, and in that case you would only have to replace require with requires to make sure some dependency of a dependency aren't doing shenanigans.

@Z3TA
Copy link
Author

Z3TA commented Oct 1, 2019

I'm not sure how policies works. Will having an empty policy.json block everything by default ?

Edit: I have now played around with policies, which seem very tedious as you need to hash every file for integrity checksum. It did stop me from using the fs module unless it was listed as a dependency.

Advantage of policies:

  • You can add policies to existing modules that you do not control

Disadvantages:

  • A malicious user can infect a file that already have fs listed as a dependency.
  • A malicious user could use try/catch and wait for when you accidentally forget the --policy flag.

My solution with fs filters could also be added to policies.

@devsnek
Copy link
Member

devsnek commented Oct 1, 2019

they're intended to be generated, not written directly.

@mscdex
Copy link
Contributor

mscdex commented Oct 2, 2019

The problem is that the proposed method of restriction is not very granular and there will always be someone who wants behaviors tweaked a certain way for their particular needs. For example,

const foo = requires("bar", {fs: {read: ["/home/someuser/.dotconfig/"]}});

Does this restrict reads in just this directory or does it also allow reads in subdirectories? Some users may want one behavior, some may want the other.

Having flexible restrictions all in one place (policies) is the best way to go and means anyone can restrict things exactly how they want (via code) by supplying their own module overrides.

@tomasgvivo
Copy link

tomasgvivo commented May 12, 2020

I want to add that, currently, policies are not 100% secure.
For example:
given policy

{
    "onerror": "log",
    "resources": {
        "./index.js": {
            "integrity": "sha256-Czk43BtRnmC0SwsIAIm7ijc+/cAZa1FX5teyFxb6/5w=",
            "dependencies": {
                "./test.js": true,
                "fs": true
            }
        },
        "./test.js": {
            "integrity": "sha256-o2LIBKLQeei6y7XLmOu2IF6M/T2msAjcd9o/VukQ4pU=",
            "dependencies": {
                "fs": "./fs_mock.js"
            }
        }
    }
}

Let's suppose ./fs_mock.js disallow access to all fs method.
test.js can still access the file system by using one of the following methods:

// Internal bindings
const fs = process.binding('fs');

// Escaping current module
const fs = module.parent.require('fs');

I'm not sure policies are meant to be used for this kind of things (blocking access to system resources).
If that's the case, it needs some improvements (i know, it's still experimental).
It would be nice to have some way to define system resources access policies (network, file system, exec, fork, spawn, etc) for modules. And I would love to have the option to define cgroup, chroot, capabilities for a nodejs process instance without having to rely on apparmor or docker/runc.

@Trott Trott added the policy Issues and PRs related to the policy subsystem. label Sep 20, 2020
@Trott
Copy link
Member

Trott commented Sep 20, 2020

@bmeck Thoughts on whether there's work to do here, how it ought to be accomplished, whether this should be closed, etc.?

@bmeck
Copy link
Member

bmeck commented Sep 21, 2020

I think the ability to "require"/"import" is solved, but this thread is about increased granularity for each reference, of which I don't have a solution or even a plan on how to tackle. The issues with the granularity described are laid out in particular in the model writeup I did a few years ago. There is simply too much to do such as preventing side channel leakage and dealing with Node's mutable core before we can get to that point for me to state the concerns in the thread are able to be addressed currently.

@bmeck
Copy link
Member

bmeck commented Sep 21, 2020

We could just mark this as known / blocked

@tomasgvivo
Copy link

tomasgvivo commented Sep 22, 2020

I think the ability to "require"/"import" is solved, but this thread is about increased granularity for each reference, of which I don't have a solution or even a plan on how to tackle. The issues with the granularity described are laid out in particular in the model writeup I did a few years ago. There is simply too much to do such as preventing side channel leakage and dealing with Node's mutable core before we can get to that point for me to state the concerns in the thread are able to be addressed currently.

@bmeck Keep in mind the document you shared can be edited by anyone who has access to it... in case that was not intended.

@RedYetiDev
Copy link
Member

The policy system has been deprecated, so unfortunately it doesn't look like this will find a home in Node.js.

@RedYetiDev RedYetiDev closed this as not planned Won't fix, can't repro, duplicate, stale Apr 26, 2024
@RedYetiDev RedYetiDev added experimental Issues and PRs related to experimental features. deprecations Issues and PRs related to deprecations. labels Apr 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
deprecations Issues and PRs related to deprecations. experimental Issues and PRs related to experimental features. policy Issues and PRs related to the policy subsystem.
Projects
None yet
Development

No branches or pull requests

7 participants