top | item 4873139

Drop Root Privileges in Node.js after Binding to Port 80

38 points| tlhunter | 13 years ago |thomashunter.name | reply

39 comments

order
[+] ejdyksen|13 years ago|reply
Alternatively, you could grant the node binary the ability bind ports < 1024, using setcap (Linux only):

    sudo setcap 'cap_net_bind_service=+ep' /path/to/nodejs
Then you don't have to ever run it as root (at least not for the purpose of binding to the right port).
[+] X-Istence|13 years ago|reply
If you are on Solaris (10 or higher works from experience) you can grant a single user the ability to bind to the lower ports:

  usermod -K defaultpriv=basic,net_privaddr ${user}
You can off course also assign the privileges to a role, and then assign the user that role so as required they can su to the role and use the privileges.

Here is a pretty neat description of what is possible and why it is pretty awesome: http://www.c0t0d0s0.org/archives/4075-Less-known-Solaris-fea...

---

On FreeBSD if you have the MAC framework enabled, you can use the portacl module to give new privileges:

  sysctl security.mac.portacl.rules=uid:$user_id:tcp:80
See http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/ma... for more information.
[+] typpo|13 years ago|reply
Or route port 80 to your node port (eg. 8080):

  sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080
[+] ruxkor|13 years ago|reply
setcap solves the problem in the wrong way in this scenario imho: With setcap, any user could run node with a node script using ports < 1024.

What would be more useful is the ability to allow a _user_ to open a privileged port. In my option mappu's answer is the right way to go, i.e. using authbind to allow a certain user to open a port or a range of ports.

[+] hahainternet|13 years ago|reply
Endless bonus points to you for mentioning capabilities. They're so unknown but gems to come across.
[+] Hello71|13 years ago|reply
That kinda defeats the purpose of restricting ports under 1024.
[+] wonnage|13 years ago|reply
It's probably a better idea to just run nginx on port 80 and proxy requests through in any sort of real environment. And if you're not in production...well, it doesn't really matter which port you choose anyway.
[+] parasight|13 years ago|reply
Please excuse my ignorance, but why would I want to run nginx to proxy requests through?
[+] trebor|13 years ago|reply
Very true. This will also let you run multiple instances of node and do load balancing.
[+] darklajid|13 years ago|reply
Looking at the snippet of code: Isn't that sample (probably) confusing group and user?

  process.setgid('tlhunter');
  process.setuid('users');
I'd expect that 'users' is the group here and 'tlhunter' the user 'thomas l. hunter'?
[+] renownedmedia|13 years ago|reply
Yep; A typo I made when converting variables to strings for the example.
[+] sigil|13 years ago|reply
Alternatively, if you don't trust a large program with dropping root, you can factor out the binding and listening into a separate program. Then accepting and everything beyond can be done with normal privileges.

Assuming a tcpserver-like program called tcplisten, this would look like

    sudo tcplisten 0.0.0.0 80 setuidgid nobody \
      program-that-accepts-on-stdin
FastCGI works similarly. Multiple workers can run underneath, calling accept(2) on stdin.

A simple implementation of tcplisten:

https://gist.github.com/4211098

[+] olalonde|13 years ago|reply
I wrote a similar article a few weeks ago (http://syskall.com/dont-run-node-dot-js-as-root/) but have since then realized that changing the process' UID brings a lot of unexpected problems and a much simpler solution is to use a higher port and proxy via nginx. For example, if you initialize a logger before starting your HTTP server and changing the process UID, you will might create root owned files and eventually run into permission conflicts.
[+] Hello71|13 years ago|reply
Not a good idea to hardcode the name of the "owner". Standard practice is to setuid/gid to 65535 (nobody).
[+] zorked|13 years ago|reply
Actually, even in the classical Unix security model, setuid'ing to nobody is considered a bad idea. Because so many services do it, giving an attacker an opportunity to become nobody will likely grant him access to those other services as well.
[+] jeremiep|13 years ago|reply
You could also create a unix socket and have node.js bind on it.