
Drop Root Privileges in Node.js after Binding to Port 80 - renownedmedia
http://thomashunter.name/blog/drop-root-privileges-in-node-js/
======
ejdyksen
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).

~~~
ruxkor
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.

~~~
toong
Authbind looks really appropriate here.

(Hmm, did parent just edit his comment ? He didn't mention authbind when I hit
reply, did he ?)

From the man page: authbind allows a program which does not or should not run
as root to bind to low-numbered ports in a controlled way. The shared library
loaded using LD_PRELOAD overrides the bind(2) system call. When a program
invoked via authbind calls bind to bind a socket to a low-numbered TCP/IP
port, and if the program doesn't already have an effective uid of 0, the
version of bind supposed by authbind forks and executes a setuid-root helper
program.

You can create configuration file like /etc/authbind/byport/port and use
standard linux file permissions to allow certain non-root users to bind to
ports < 1024

------
wonnage
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
Please excuse my ignorance, but why would I want to run nginx to proxy
requests through?

~~~
onewland
[This response is a guess, and very generalized]

You probably won't handle every HTTP edge case as well as nginx defaults, and
you don't really need the control at that level to implement a functional,
high performance web app.

------
mappu
Another technique is to launch the service via authbind, in your repositories.
It's especially useful if you aren't able to recompile the target.

<http://en.wikipedia.org/wiki/Authbind>

------
darklajid
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
Yep; A typo I made when converting variables to strings for the example.

------
sigil
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
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
Not a good idea to hardcode the name of the "owner". Standard practice is to
setuid/gid to 65535 (nobody).

~~~
zorked
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.

~~~
Hello71
Point taken. Allow me to revise my statement.

"In production, one should create a specialized user to run any service." And
if you have lots of money to waste, stick 'em all in separate VMs too.

------
jeremiep
You could also create a unix socket and have node.js bind on it.

