1 of 30

Node.js Policies

Bradley Farias - GoDaddy

2 of 30

Model

3 of 30

Model

Parent Process

Node.js Process

Node.js

Loader

Application

Disk

CLI Arguments*

ENV Variables

STDIN

4 of 30

  • Node.js does not control the process by which the user application process is spawned
  • Parent process must limit OS level privileges to prevent application from using OS resources inappropriately
    • Prevent information disclosure by access to resources
    • Prevent denial of service by resource usage
    • Prevent denial of service by restarting application as needed
  • Parent process must spawn the application process with the appropriate initialization parameters
    • STDIO/CLI/ENV/etc.

5 of 30

  • Responsible to read source text, linking, and evaluation.
  • Is mutable through runtime and/or configuration
  • Loads source text from different sources at runtime
    • Off disk
    • STDIO
    • In memory (not all code goes through the Loader [eval/Function/etc.])
      • Requires off disk module to bootstrap
    • Potential for network based loading
  • Queues evaluation through different means
    • require
    • CLI (STDIN/ARGV)
    • import

6 of 30

  • Access to all ambient authority of the Node.js process
    • Can rewrite disk, ENV, etc.
    • Can spawn child processes
      • Use parent process to set OS privileges appropriately
    • Can communicate over the network, stdio, etc.
    • Can harden APIs, perform privilege dropping, etc.
  • Can be affected by multiple instances of the process
    • Parallel processes
    • Restarts
  • Can generate multiple Loaders via Worker threads

7 of 30

  • Main module
  • --require
  • --loader
  • --eval
  • --interactive
  • --check
  • --inspect

8 of 30

  • NODE_OPTIONS
  • PATH (for child process)
  • SHELL (for child process)

9 of 30

  • Modules on disk
    • New modules could be generated by application
    • Affected by directory structure and indirection
      • file extension searching
      • index.*
      • symlinks
      • package.json
  • Application dependent files on disk
    • Configuration/Templates/etc.

10 of 30

Assets

  • Application
    • Modules on disk
    • Application dependent files
      • Out of scope if it does not go through the Loader

11 of 30

Attackers (malicious or not)

  • Dependency authors
    • event-stream / eslint-scope
  • Upload users
  • Unvetted module using authority

12 of 30

Software

  • Parent process
  • Application process
    • Worker Threads
  • Child process

13 of 30

Attacking

14 of 30

Out of scope

  • Preventing information disclosure of source text
  • Loading code not through a loader
    • All code must initially go through a loader, any code that has been whitelisted through the loader is given ambient authority including running an interpreter
    • This includes starting child processes
  • Denial of service by restarts/errors
    • Application restart should be managed by parent process, including rolling back VM state such as disk
    • Application refusing to run to completion used to prevent arbitrary logic running
  • Alteration of parent process initialization parameters

15 of 30

Use of untrusted modules with ambient authority

  • Any module must be given privilege of ambient authority in accordance with principle of least privilege

16 of 30

Mutate application logic by loading differences

  • Update dependency to malicious form
  • Inject code into existing modules
  • Replace module with symlink to different path
  • Remove module
  • Inject module in search path
    • require('foo') -> /foo.js : require('foo') -> /foo

17 of 30

Adding policies

18 of 30

--policy ./policy.json

  • Means to mitigate attacks via checking integrity of resources passed through the loader
  • Responsibility of parent process to manage the file
  • Use ( Location, SRI ) pair to mitigate spoofing if a module is trusted
    • Location can be relative to the policy file
      • calculated prior to any user code based only using parent process trusted data
    • SRI can be updated to have new algorithms as old ones are deprecated in a transitionary fashion
  • Applies to whole process, including workers
  • Checks cannot be manipulated by user code at runtime

19 of 30

Attacking the policy file

  • Replace the contents of the policy to whitelist new logic
    • Ensure the parent process can assert the integrity of the policy file
      • --policy-integrity (TODO)
  • Delete policy file
    • Fail on missing policy file or missing --policy when --policy-integrity is specified
  • Change permissions to prevent reading policy file
    • Fail on inability to obtain source of policy file

20 of 30

Next Steps

21 of 30

Frozen core

  • Prevent core from being used by a module to intercept another module's authority
  • Stop userland mutation of core to be used as interception points
  • Add {"core": {"frozen": true}} default to policy.json
  • Require extra privilege to run mutations like polyfills prior to freeze operation

22 of 30

Constrain APIs

  • Prevent need to check all modules against entire ambient authority
  • Allow specifying removal of systems from entire process
    • Remove ability to create a child process for example
  • Allow specifying authority level of individual modules
    • Only allow a package to read from disk instead of both read and write
    • Useless without frozen core due to intercepting powerful APIs

23 of 30

HTTPS Imports

24 of 30

Model

Node.js Process

Node.js

Loader

Node.js

HTTPS

Server

Node.js

DNS

25 of 30

Assets

  • URL
  • HTTPS
  • TLS
  • DNS

26 of 30

Attack Vectors

  • URL
    • Information disclosure via auth
    • Spoofing if sanitized
  • DNS
    • Hijacking
    • Denial of Service via connectability
    • Mutable core can intercept
  • TLS
    • Cert authority
    • Mutable core can intercept
  • HTTPS
    • Denial of Service via connectability
    • Mutable core can intercept

27 of 30

HTTPS Whitelisting

  • Given the attacks above a HTTPS scheme of import should be feasible with a (Location, Integrity) pair
    • Integrity mitigates tampering even with mutable core
    • Redirects should not affect the Location of a resource, matching web
    • Prevents need to have files on disk that can be modified
    • Allows simpler deprecation/logging of usage of a specific module
    • Opens denial of service if connectivity fails
    • Opens information disclosure by auth URL part

28 of 30

Data Imports

29 of 30

Attack Vectors

  • Poisoning module state ahead of time

30 of 30

DATA Whitelisting

  • Data URLs do not have an unforgeable aspect/trusted origin and can be poisoned if they are not hardened modules:
    • import(`data:text/javascript,� let auth = null;� export function setup(v) {if (auth===null) auth = v;}� export function creds(v) {return auth;}�`);
  • This can be mitigated by only allowing data URLs to be loaded at the top level or if whitelisted in the policy