N|Solid Documentation

Versions

Policies

N|Solid ships with the ability to enable some security-related policies to help harden your application. Currently these include the ability to disable core modules and bindings.

To enable policy configuration with N|Solid, you must create a policies file in JSON format, and specify that file via the policies flag when starting N|Solid.

nsolid --policies my-policies.json app.js

Disabling Core Modules

N|Solid includes the ability to disable core modules with a policy file. This can be used to restrict application access to system resources or features that should not be used by your application.

There are two types of core resources that can be disabled: modules and bindings:

There are four different severity levels you can configure:

Parameter Level Description
0 ignore No notice will be provided during the loading of the module or binding.
This is the default behavior.
1 warning A warning is written to stderr during the loading of the module or binding. The application otherwise runs normally.
2 throw error A error is thrown only when the policy is violated​ which doesn't occur during the ​loading​ of the module, but when a function on it is called. You can catch this by writing a try/catch in your code around your require() calls.
3 exit The application exits during the loading of the module or binding.

Disabling a module in the policy file prevents all non-core modules from using it i.e a warning is printed when loaded, but only when it is used does the violation handler kick in). Core modules are still able to load it (e.g. the core module library can still use fs to read new files via require() )

Example Policy File: disable-dns-all.policy.json

{
  "// severity levels": "0 - ignore; 1 - warning; 2 - throw error; 3 - exit",

  "blacklist": {
    "modules": {
      "dns": 2
    },
    "bindings": {
      "cares_wrap": 2
    }
  }
}

Access to bindings can also be restricted, if so desired, by the policy writer. The example policy file above disables both the dns module and the cares_wrap module, both of which can be used to access DNS.

When a non-core module attempts to access a disabled core module, messages will be logged to stdout, and an exception thrown.

Usage of disable-dns-all.policy.json

$ nsolid --policies disable-dns-all.policy.json faux-dns.js

nsolid error Binding "cares_wrap" is requested via a process.binding call
nsolid error at Object.<anonymous> (/Users/user/nsolid-demos/demos/faux-dns.js:3:23)
nsolid error But it was disabled in the policies.
_module_wrap.js:423
    throw new Error('Binding "' + id +
    ^

Error: Binding "cares_wrap" has been disabled by the policies flag, using "GetAddrInfoReqWrap" on it is not allowed, terminating execution.
    at new throwError (_module_wrap.js:423:11)
    at Module._compile (module.js:430:26)
... more stack trace lines here

More Policy Usage

Disabling a child process

{
  "blacklist": {
    "modules": {
      "child_process": 2,  -- blacklist entire child_process module with severity level 2
    }
  }
}

Code usage

var ls = require("child_process").execSync("ls -l")
console.log(ls.toString())

Running with policy

$ nsolid --policies disable_childprocess.json child_process_example.js
nsolid error Module "child_process" is required
nsolid error at Object.<anonymous> (/home/bryce/ns/nsolid-node/foo.js:1:72)
nsolid error But it was disabled in the policies.
child_process.js:75
  throw new Error('"' + module.id + '" has been disabled ' +
  ^

Error: "child_process" has been disabled by the policies flag, terminating execution.
    at handleDisabledMethodCall (child_process.js:75:9)
    at Object.execSync (child_process.js:89:22)
    at Object.<anonymous> (/home/bryce/ns/nsolid-node/foo.js:1:96)
    at Module._compile (module.js:434:26)
    at Object.Module._extensions..js (module.js:452:10)
    at Module.load (module.js:355:32)
    at Function.Module._load (module.js:310:12)
    at Function.Module.runMain (module.js:475:10)
    at startup (node.js:149:18)
    at node.js:985:3

Function using the binding 'cares_wraps'

module.exports = lookup;

var cares = process.binding('cares_wrap');

function lookup(hostname, callback) {

  var req = new cares.GetAddrInfoReqWrap();
  req.callback = callback;
  req.family = 4;
  req.hostname = hostname;
  req.oncomplete = callback;

  var err = cares.getaddrinfo(req, hostname, 4, 0);

  if (err) {
    callback(new Error("OOPS"));
    return {};
  }
  return req;
}

Calling function

var look = require("./fauxdns.js");
look("nodesource.com", function (err, data) {
  console.log(data);
});

Without a policy file we're able to access the network via the DNS binding

$ nsolid lookup.js
[ '162.243.142.64' ]

With a policy file that prevents just the dns module

$ cat disable_dns.js
{
  "blacklist": {
    "modules": {
      "dns": 2
    }
}

We can still access it!!

$ nsolid --policies disable_dns.js lookup.js
[ '162.243.142.64' ]

To actually prevent this circumvention of the modulesBlacklist we need to blacklist the cares_wrap binding

$ cat disable_cares.json
{
  "blacklist": {
    "bindings": {
      "cares_wrap": 2
    }
  }
}

Now the behavior is blocked!

$  nsolid --policies disable_cares.json lookup.js
nsolid error Binding "cares_wrap" is requested via a process.binding call
nsolid error at Object.<anonymous> (/Users/kevin/develop/nodesource/policies/fauxdns.js:3:21)
nsolid error But it was disabled in the policies.
_module_wrap.js:423
    throw new Error('Binding "' + id +
    ^

Error: Binding "cares_wrap" has been disabled by the policies flag, using "GetAddrInfoReqWrap" on it is not allowed, terminating execution.
    at new throwError (_module_wrap.js:423:11)
    at lookup (/Users/kevin/develop/nodesource/policies/fauxdns.js:7:13)
    at Object.<anonymous> (/Users/kevin/develop/nodesource/policies/lookup.js:3:1)
    at Module._compile (module.js:434:26)
    at Object.Module._extensions..js (module.js:452:10)
    at Module.load (module.js:355:32)
    at Function.Module._load (module.js:310:12)
    at Function.Module.runMain (module.js:475:10)
    at startup (node.js:150:18)
    at node.js:986:3

A policy file that disables several modules and bindings

{
  "blacklist": {
    "modules": {
      "child_process": 2,  -- blacklist entire child_process module with severity level 2
      "fs": 3,             -- blacklist entire fs module with severity level 3
      "path": 0            -- blacklist path with severity level 0, same as omitting `path` from blacklist all together
    }
    "bindings": {
      "stream_wrap": 2     -- blacklist entire stream_wrap binding with severity level 2
    },
  }
}

Comments

We allow properties whose keys start with "//" anywhere and they are ignored.

Invalid Policies

Anytime an unexpected property or a property with an invalid value is encountered, the policies are considered invalid and the process halted.

Further Thoughts

N|Solid's policies feature should not be used as a blind replacement for good security practices with regard to your code and the code of your application's dependencies. Disabling core modules and bindings does not provide a complete guarantee that your application is unable to use the features provided by those parts of Node.js. For example, child processes interacting with Unix utilities, if not disabled, can be used to replace the functionality of many of the core modules. Some core modules may be completely re-implemented in user-land modules, such as the dns and cares_wrap functionality. Compiled add-ons have complete freedom to insert new functionality that can replace anything that has been disabled.

N|Solid's policies features augment and support existing enterprise-wide application security hardening programs. Please contact NodeSource if you wish to discuss your Node.js application security needs and prepare a customized security hardening program that involves the use of internal and third-party code review, application monitoring and the use of operating system security tools.

Modules That Can Be Blacklisted

The following is a list of modules that can be blacklisted. It should be noted that for most of these modules it is rare to have a business need where blacklisting makes sense.

Module Description
_debug_agent Provides support for debugging node.js, mostly used internally.
_debugger Provides support for debugging node.js, mostly used internally.
_linklist Data structure used internally by node.js.
assert Used for writing unit tests for your applications, you can access it with require('assert').
buffer Raw data is stored in instances of the Buffer class.
child_process Provides a tri-directional popen(3) facility in order to create a child process.
console Console object is a special instance of Console whose output is sent to stdout or stderr, - constants.
crypto Crypto module offers a way of encapsulating secure credentials to be used as part of a secure HTTPS net or http connection.
cluster Allows you to easily create child processes that all share server ports.
dgram Provides Datagram sockets.
dns Provides name resolution.
domain Pending deprecation - provide a way to handle multiple different IO operations as a single group.
events Provides event emitters.
freelist Data structure used internally by node.js.
fs Provides file I/O via simple wrappers around standard POSIX functions.
http Provides ability to create http servers and clients.
_http_agent Provides support for http and https modules, mostly used internally.
_http_client Provides support for http and https modules, mostly used internally.
_http_common Provides support for http and https modules, mostly used internally.
_http_incoming Provides support for http and https modules, mostly used internally.
_http_outgoing Provides support for http and https modules, mostly used internally.
_http_server Provides support for http and https modules, mostly used internally.
https Provides ability to create https servers and clients.
module Provides the node.js module system, mostly used internally.
net Net module provides asynchronous network wrapper for server and clients.
os Provides basic operating-system related utility functions.
path Provides utilities for handling and transforming file paths.
process Same as the global process object.
punycode Provides Unicode utilities.
querystring Provides utilities for dealing with query strings.
readline Allows reading of a stream (such as process.stdin) on a line-by-line basis.
repl Provides a way to interactively run JavaScript and see the results.
stream Provides streaming functionality.
_stream_readable Provides the ReadableStream exposed via the stream module.
_stream_writable Provides the WritableStream exposed via the stream module.
_stream_duplex Provides the DuplexStream exposed via the stream module.
_stream_transform Provides the TransformStream exposed via the stream module.
_stream_passthrough Provides the PassThroughStream exposed via the stream module.
_stream_wrap Provides the wrapper to the libuv stream implementation, mostly used internally.
string_decoder Decodes a buffer to a string with utf8 support.
sys Alias for util.
timers Provides internal support for global Timers.
tls Uses OpenSSL to provide Transport Layer Security and/or Secure Socket Layer: encrypted stream communication.
_tls_common Provides support for tls module, mostly used internally.
_tls_legacy Provides support for tls module, mostly used internally.
_tls_wrap Provides support for tls module, mostly used internally.
tty Provides the tty.ReadStream and tty.WriteStream classes.
url Provides utilities for URL resolution and parsing.
util Primarily designed to support the needs of node.js's internal APIs, but many of these utilities are useful for user programs.
v8 Events and interfaces specific to the version of v8.
vm Provides support to compiled code and run immediately or compile, save it, and run later.
zlib Provides bindings to Gzip/Gunzip.
profiler Profiler module (explained in nsolid docs).
_function_origin Internal module used by nsolid.
_module_wrap Internal module used by nsolid.
_module_wrap_known_modules Internal module used by nsolid.
_module_wrap_known_bindings Internal module used by nsolid.
_policies_validation Internal module used by nsolid.
nsolid Internal module used by nsolid.
nsolid_versions Internal module used by nsolid.

Bindings That Can Be Blacklisted

The following is a list of bindings that can be blacklisted. It should be noted that for most of these bindings it is rare to have a business need where blacklisting makes sense.

Binding Description
async_wrap Base class for all async request modules which supports hooks into async events.
buffer Interface to libuv methods to operate on buffers.
cares_wrap Wraps the cares library for asynchronous name resolves.
contextify Interface to v8 in order to create execution contexts.
crypto Provides crypto functionality such as SSL and ciphers
fs Interface to file system methods provided by libuv.
fs_event_wrap Binding to listen to file related events in order to support watching files and directories for changes.
http_parser Binding to http_parser.
js_stream Binding that provides support for node.js streams.
os Interface to libuv in order to obtain process state information.
pipe_wrap Wraps libuv's socket implementation.
process_wrap Provides process functionality such as spawning child processes.
signal_wrap Supports sending and handling signals to processes.
spawn_sync Supports child_process.execSync functionality via libuv.
stream_wrap Wraps stream implementations exposed by libuv to communicate via file descriptors or network connections.
tcp_wrap Integrates TCP functionality exposed by libuv in order to create TCP connections.
timer_wrap Integrates with timer functionality provided by libuv so support things like setTimeout and setInterval.
tls_wrap Provides TLS termination functionality via crypto.
tty_wrap Integrates with TTY terminal functionality provided by libuv.
udp_wrap Provides UDP protocol functionality such as binding and broadcasting.
uv Provides libuv integration such as error name resolution.
v8 Limited interface to the v8 API, i.e. to set flags and get process information.
zlib Wraps the zlib library.