novnc / websockify

Websockify is a WebSocket to TCP proxy/bridge. This allows a browser to connect to any application/server/service.
GNU Lesser General Public License v3.0
3.91k stars 772 forks source link

Specify a port below 1023 for encryption to work #485

Closed fedelep closed 3 years ago

fedelep commented 3 years ago

Dear Websockify Devs,

Thanks to the Covid pandemic, and lack of access to computers, I am trying to solve a problem whereby students who have only Chromebooks to use can utilize Cisco Packet Tracer. So far, the project has been successful at using noVNC / Websockify and a GUI restricted to only share that program over a browser at port 11000 (my port choice).

The problem that I am having is twofold. SSL does not work on port 11000 with a browser, even though my domain is set up and certificates have been acquired through letsencrypt. Also, I can not run /usr/bin/websockify with the port specified to 443 without becoming root (sudo).

To run Websockify at port 11000, the following command can be issued (note that I have replaced the domain with "URL"):

/usr/bin/websockify -D --verbose --web=/usr/share/novnc/ --ssl-version=tlsv1_2 --cert=/etc/letsencrypt/live/URL/cert.pem --key=/etc/letsencrypt/live/URL/privkey.pem $ip_address:11000 --ssl-target --token-plugin=TokenFile --token-source=/usr/local/share/websockify

The output of the command is:

WebSocket server settings:

Also, the user is "administrator" (not root) based on the command: ps -aux | grep /usr/bin/websockify

adminis+ 10164 6.4 0.2 53492 27620 ? S 13:51 0:01 /usr/bin/python3 /usr/bin/websockify -D --verbose --web=/usr/share/novnc/ --ssl-version=tlsv1_2 --cert=/etc/letsencrypt/live/URL/cert.pem --key=/etc/letsencrypt/live/URL/privkey.pem :11000 --ssl-target --token-plugin=TokenFile --token-source=/usr/local/share/websockify

If the port is changed to 443, the following output occurs and Websockify quits (gracefully):

/usr/bin/websockify -D --verbose --web=/usr/share/novnc/ --ssl-version=tlsv1_2 --cert=/etc/letsencrypt/live/URL/cert.pem --key=/etc/letsencrypt/live/URL/privkey.pem $ip_address:11000 --ssl-target --token-plugin=TokenFile --token-source=/usr/local/share/websockify

WebSocket server settings:

Adding sudo to the beginning of the command, the following occurs:

sudo /usr/bin/websockify -D --verbose --web=/usr/share/novnc/ --ssl-version=tlsv1_2 --cert=/etc/letsencrypt/live/URL/cert.pem --key=/etc/letsencrypt/live/URL/privkey.pem $ip_address:443 --ssl-target --token-plugin=TokenFile --token-source=/usr/local/share/websockify

The command which uses port 11000 runs without sudo, while the command using port 443 requires it. The only difference is the port number. There is only one glaring problem, the owner of the /usr/bin/websockify process in the second instance is root. This is very dangerous from a security standpoint and I wish to avoid it.

There is a convergence of technologies that is conspiring against me when trying to use HTTPS with Websockify.

First, many networks allow only ports 80 and 443 through their firewalls Second, SSL only works on port 22 (SSH) and 443 (HTTPS) Third, Linux does not allow non-root users to open listening ports below 1024 without recompiling the kernel

At this point, I have attempted to implement NAT using iptables to redirect between ports 443 and 11000. I have also tried using Apache as a proxy to Websockify. Finally, I have used setcap to attempt to bypass the restrictions. Nothing worked, and I may yet try to recompile the kernel. Here is the thread that I was following:

https://serverfault.com/questions/112795/how-to-run-a-server-on-port-80-as-a-normal-user-on-linux

So I am left with a question or three. How do Apache, Nginx, OpenSSH, WUFTP, etc. use ports below 1024 without being root? Is this something that can be replicated in the Websockify project? Am I just completely off base here?

Thanks,

FedeleP

CendioOssman commented 3 years ago

So I am left with a question or three. How do Apache, Nginx, OpenSSH, WUFTP, etc. use ports below 1024 without being root? Is this something that can be replicated in the Websockify project? Am I just completely off base here?

I'm afraid there has been some misunderstanding. Using such low ports always requires privileged access (i.e. root). Many servers start as root to do all the privileged stuff (like grabbing the port), and then switch to another user. But they must always be allowed to start as root to get those ports.

So I'm afraid there is nothing we can do here. If you want websockify on a low port you need to either start it as root, or have something else started as root that proxies the data to websockify. Using your firewall settings might also be an option, yes. But it's again a privileged operation to set that up.

fedelep commented 3 years ago

Turns out that there is a way to easily resolve the issue, and it is being added here just in case someone else runs into the same problem.

Before starting Websockify: sudo sh -c "echo 443 > /proc/sys/net/ipv4/ip_unprivileged_port_start" This will make it possible for non-root processes to open port 443

After starting Websockify: sudo sh -c "echo 1024 > /proc/sys/net/ipv4/ip_unprivileged_port_start" This returns to the Linux default of only root being able to open processes below 1024

Put these commands in a script together with the Websockify command sandwiched in between and Websockify will own the process running on port 443.