Drop Root Privileges in Node.js

A common use for Node.js is to build web applications. Usually, we want these applications to listen on port 80. As a security precaution, most OS’s require root privileges for this to happen (e.g. OS X, Linux, BSD). To run a Node application this way, we need to do the following:

sudo node server.js

Then, the application runs as root for the rest of the session. There are potential security risks to this, though. What if there is a vulnerability in your application and a hacker starts controlling your app and doing naughty things with it? Thankfully, we can drop the user account running our process to a less secured user, such as our normal account. There are two methods on the process global which can handle this for us, .setgid() and .setuid().

Here’s a working example of this in action. We want to run this code AFTER we bind to port 80, so we run the code in a callback:

app.listen(80, 'localhost', null, function() {
  // Listening
  try {
    console.log('Old User ID: ' + process.getuid() + ', Old Group ID: ' + process.getgid());
    process.setgid('users');
    process.setuid('tlhunter');
    console.log('New User ID: ' + process.getuid() + ', New Group ID: ' + process.getgid());
  } catch (err) {
    console.log('Cowardly refusing to keep the process alive as root.');
    process.exit(1);
  }
});

The results of .getuid() and .getgid() will be numeric, and aren’t really useful, other than showing that something happened. They’ll probably both say 0 the first time (that’s root in *nix land), and then some bigger number afterwards.

Unsure of your username or group name? For shame! Run the following commands:

whoami
groups

14 Responses to “Drop Root Privileges in Node.js”

  1. Patrick O'Leary

    I think you got your username and group names swapped in the code snippet.

    Reply
  2. This is not a good way to do it IMO.

    Instead consider authbind.

    Installation is simple: add a file to /etc/authbind/byport/80 that is executable by the user you want to run the app (let’s say ‘www-data’).

    Then run authbind as www-data. Here’s an excerpt from an upstart script I use:

    su -c ‘authbind node server.js 2>&1 >> /var/log/node/app.log’ www-data

    This simple command runs authbind as the user www-data. Because /etc/authbind/byport/80 is executable by www-data, it can run on port 80 with no root privileges whatsoever.

    Reply
  3. Guessing your uid isn’t “users”, and your gid isn’t “tlhunter” – I think you have the arguments to setgid and setuid swapped.

    Reply
  4. Why not just use authbind?

    Reply
  5. Bad: Do this

    Better: Use auto bind

    Best: Use iptables, ipfw, or a reverse proxy through nginx, Apache, or Varnish to move traffic from port 80 to your node app running on a high port (>2000ish)

    Reply
  6. s/auto\ bind/authbind

    I blame OS X’s autocorrect.

    Reply
  7. You could also use iptables to redirect port 80 to a port that doesn’t require root privileges.

    Reply
  8. May I suggest using nginx or varnish in front of the node.js server. That, or simply using port forwarding to another port.

    Reply
  9. Ivan Drinchev

    There is a great tool I’m using for my linux box, running multiple node servers. I found it in the great djbdns server.

    It’s called daemontools and it supports auto-restart, logging STDOUT & STDERR, running from different accounts and a lot more.

    I’m using apache and virtualhosts for redirection to my node apps ( they use ports 800+ ).

    Reply
  10. Charlie Root

    you could always spawn it in .sh and use the battle-tested ‘daemon -u’

    Reply
  11. or socat.

    sudo socat -4 TCP-LISTEN:80,fork TCP:127.0.0.1:9669

    on opensolaris or solaris 10 systems you may also grant the ‘net_privaddr’ privilege to a user or role.

    Reply
  12. If you’re deploying to a Ubuntu box, you can also use Upstart to manage your Node.js instance, and setting the process runner to a unprivileged user.

    Something like exec sudo -u deploy sh -c "cd /your/app && node server.js".

    Reply

Comment

  • (will not be published)

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>