-
Notifications
You must be signed in to change notification settings - Fork 0
Privilege separation
Goal
Mitigate exploitation of any bugs in the bundled C/C++ code that ships with NodeJS and can be reached over the network (V8, libuv, OpenSSL etc.).
How
Principle of least privilege, split privileges between system processes:
- chroot to /var/empty
- drop to a system account that is only used for one specific type of process/privilege
- make sure any other environmental leaks are closed like open file descriptors etc.
- limit the remote attack vector to a single unnamed pipe (the IPC channel with the master process)
- further reduce the attack surface by utilizing an extremely simple protocol
Design
PerspectiveDB is split into three (or four with wss) different type of processes, each with it's own set of privileges:
-
master (master priv)
- read password database
- fork preauth_exec and db_exec processes
- authenticate and authorize clients coming in via preauth_exec
- initiate auth request to configured remotes over ssh or local tcp
-
db_exec (db priv)
- write to database in chroot
- send requested data as BSON over authenticated incoming connections
-
preauth_exec (preauth priv)
- handle incoming connections (local TCP)
- handle auth requests (parse incoming data as a line-separated JSON stream)
- pass auth requests to the parent for verification
- optionally fork a WebSocket server
-
wss_server (wss priv)
- handle incoming connections via WebSocket tls
- only support forward secure key exchange with AEAD ciphers (at the moment that is RSA-CHACHA20-POLY1305 and RSA-AES128-GCM-SHA256, both DHE and ECDHE)
The master process is started as root. Reads config and password databases, then spawns db children and an unprivileged preauth child to handle incoming connections (local TCP and/or WebSocket depending on configured listen directive). Once all this is done the master process chroots itself and drops privileges to the configured user and group. An IPC channel is kept open during the whole lifetime of the process to each spawned process. After dropping privileges master sends each perspective configuration (import and export rules) to the corresponding db child, so that the child can initiate new connections.
Each spawned db child drops privileges after all requested modules and hooks are loaded and before new connections are initiated or accepted.
The preauth process drops privileges after it's servers are started and only exists if at least one listen directive is given. New auth requests and connections are tested if they contain a valid JSON auth request in the first 1024 bytes and if so are sent via IPC along with the socket to the parent for further evaluation. The master process does the verification using bcrypt and if successful it passes the request stripped from it's username, password and db field, along with the connection to the accompanying db privileged process. The db privileged process can then send an auth response followed by BSON data over the received connection.
This mitigates:
- Remote exploits of bugs in V8, libuv, OpenSSL and other bundled C/C++ code that comes with NodeJS. The code that is reachable over the network is decoupled and chrooted and can only communicate with a master parent via a socketpair. Only a strictly typed single JSON object is accepted as input on this channel which makes it easy to parse, put bounds checks in place, and disconnect early if invalid. The largest attack vector comes from the optional WebSocket server.
- Escalation of the preauth process reading or writing to any database, since it is chrooted.
- db privileged process reading anything other then it's own database (chroot)
- Both the master process and the unprivileged process can be chrooted to
/var/empty
. db privileged processes are chrooted to the location of the LevelDB.
TODO
- better handle DoS of preauth process (maybe spawn one preauth per connection)
- determine if different node processes running under the same user can read each others memory
Discussion
https://groups.google.com/forum/#!topic/nodejs/6PDd8xU89xA
Inspired by OpenSSH privilege separation: http://www.citi.umich.edu/u/provos/papers/privsep.pdf