Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node Express Unix Domain Socket Permissions

I am running an nginx server and a node express web server, using daemontools, setup to communicate over Unix Domain Sockets. There's just a few problems:

  1. The socket file stays present on shutdown, so I have to delete it when bringing the server back up, otherwise I will get the EADDRINUSE error.
  2. The nginx server runs as the nginx user, and the node server runs as the node user.
  3. The socket file gets created by Express when the server starts up and umask sets the permissions on the socket file to 755.
  4. The setuidgid application sets the group to the default group of the user, both the node username in this case.
  5. The deployment scripts for the application and daemontools' run script execute before the node server instance gets launched, so there's no way to set the permissions on the file, as it has to get recreated during the launch process.

If I chgrp and chmod g+w the socket file, everything works fine. Is there a way to set this up so that the node application's socket file gets generated with the correct permissions for nginx to be able to write to it without compromising the security independence of one application or the other? I would even be okay with adding nginx to the node user's group, if there was still a way to set the permissions on the socket file so that it would be group writable.

like image 213
Bobby Avatar asked Jan 24 '14 21:01

Bobby


People also ask

Are UNIX sockets blocking?

The traditional UNIX system calls are blocking. For example: accept() blocks the caller until a connection is present. If no messages space is available at the socket to hold the message to be transmitted, then send() normally blocks.

Is Unix domain socket reliable?

Valid socket types in the UNIX domain are: SOCK_STREAM, for a stream-oriented socket; SOCK_DGRAM, for a datagram-oriented socket that preserves message boundaries (as on most UNIX implementations, UNIX domain datagram sockets are always reliable and don't reorder datagrams); and (since Linux 2.6.

Are UNIX domain sockets faster?

Unix domain sockets are often twice as fast as a TCP socket when both peers are on the same host. The Unix domain protocols are not an actual protocol suite, but a way of performing client/server communication on a single host using the same API that is used for clients and servers on different hosts.

Do Unix domain sockets use ports?

Unix Domain Socket uses a local file on the device. It does not require network ports to be open, instead the Linux system controls who can have access to the file for communication. This is advantageous as you can assign permissions that suit the way you want to set up the system.


3 Answers

@Bobby's answer left me with connect() to unix:/run/static0.sock failed (13: Permission denied) in nginx. Chmod 777 was the trick. Here's my solution [building on his]:

var fs = require('fs');
var http = require('http');
var process = require('process');
var express = require('express')
var app = express()

app.get('/', function (req, res) {
  res.send('Hello World!')
})

var sock = process.argv[2];

fs.stat(sock, function(err) {
  if (!err) { fs.unlinkSync(sock); }
  http.createServer(app).listen(sock, function(){
    fs.chmodSync(sock, '777');
    console.log('Express server listening on ' + sock);
  });
});

Run like:

$ node server.js /run/static0.sock
Express server listening on /run/static0.sock
like image 60
A T Avatar answered Nov 03 '22 14:11

A T


Maybe I am too late.

As a complement of your own answer there is a solution not having to add the nginx user to the node group.

Create a directory only for the socket file, assign it to the node user and www-data (or whatever group the nginx is) group and set the group-id bit (SGID) on that directory.

mkdir -p /var/lib/yourapp/socket
chown nodeuser:nginxgroup /var/lib/yourapp/socket
chmod g+rxs /var/lib/yourapp/socket

All files created inside this directory will automatically be owned by the nginxgroup group.

like image 29
Patxitron Avatar answered Nov 03 '22 14:11

Patxitron


I was able to get it working by adding nginx to the node user's primary group:

gpasswd -a nginx node

And then starting the express server using the following:

// Create the server
fs.stat(listen, function(err) {
  if (!err) { fs.unlinkSync(sock); }
  http.createServer(app).listen(sock, function(){
    fs.chmodSync(sock, '775');
    console.log('Express server listening on ' + listen);
  });
});

I don't really feel like this is a valid solution, just a hack. Express wasn't built with deleting and setting file perms in mind, and it especially bugs me to have to add the nginx user to the node user's primary group. If there were ever a compromise of the nginx account, the attacker could conceivably have access to all of the application's source, and an avenue to try endless attacks on the code using the socket. The best that I can do is set the umask to 077 for the node user and try to get 100% coverage with a chmod 600 on every file and chmod 700 on every directory, or set the group to the non-default for the user on everything.

That said, I would still appreciate any ideas.

like image 5
Bobby Avatar answered Nov 03 '22 13:11

Bobby