mysteriumnetwork / node

Mysterium Network Node - official implementation of distributed VPN network (dVPN) protocol
https://mysterium.network
GNU General Public License v3.0
1.09k stars 310 forks source link

RFC: securing web-ui #2041

Open zolia opened 4 years ago

zolia commented 4 years ago

This is more like a summary for a discussion we had between @chompomonim, @zolia , @soffokl and @vkuznecovas . Its an attempt to resolve #1572 securely.

Problem statement

Currently web-ui is unprotected by default:

This is due to usability for users to be able to access newly setup nodes easily. It is intended to do so in local networks only, but there is no proper way to restrict to that.

Unsanctioned and unprotected default access to a node in a current state would enable a possibility to change payout address.

Suggested solutions

Please comment and give your alternatives. More detailed in-depth solution descriptions are welcome.

zolia commented 4 years ago

Adding https support

One way to move web-ui to https could be as follows:

Node operator being in local network now can access his node using https.

anjmao commented 4 years ago

For me the biggest problems seems to be default password. Even if you setup https and I connect to your network I can still access https://0xMY_VERY_LONG_IDENTITY.webui.net isn't it? Another problem is that we allow web ui access from public IP (data center nodes).

eugenegoncharuk commented 3 years ago

There are a couple of simple wildcard DNS services for any IP Address, like nip.io. We could generate a certificate with Lets Encrypt for .nip.io And https://.nip.io:4449 would route you to your local IP address Node UI web.

pianoman10 commented 3 years ago

This issue is probably more relevant than it might seem and I think it deserves to be taken care of soon. Many people is starting to have multiple residential nodes and only way to "administer" them remotely is having this port forwarded. The change of password alone is not enough. Not having SSL the password can be captured. Something should be implemented sooner than later to avoid hackers from stealing identities of nodes if they can change the payout address or change parameters that only the owner of the node should be able to change

HappyEarthDay commented 3 years ago

I would consider a local web interface with fillable fields that doesn't support SSL a very high security risk. Why does the local web interface remain after setting up the node? You can't change much on node via the local web UI, so it should be easy to move those settings and dashboards to my.mysterium.network. In my opinion, the webui from the node should be disabled unless it loses connectivity to my.mysterium.network, and everything should be managed from the cloud interface.

Another alternative would be to mimic Plex's model, and redirect the user to login to the my.mysterium.network. In this way, you are only utilizing SSO after registering the device. After signing in through the core online service, you are then signed into the local node. Obviously this would require SSL, and a standard like SAML.

chompomonim commented 3 years ago

MMN (my.mysterium.network) is not in control of your node, it simply visualizes data. Node's private keys are never revealed to MMN. And in terms of stay decentralized, MMN should be always be a add-on solution, not main node's management tool.

We understand importance of making NodeUI securely exposed outside of local network. There are a few ideas how to do that. Some are discussed in this issue. Some not.

One more idea: We could allow node runner to export private key into his consumer application (desktop or mobile app), and when he is connecting into own node via Mysterium dVPN, then NodeUI becomes accessible to him and only to him. When other people connects, node is checking for Identity and is rejecting them. Most probably node should not charge for such connection.

Additional benefit of this solution would be possibility to spend earned tokens for VPN services (because same privKey would be used in node and in consumer app).

stutteringp0et commented 2 years ago

Why not start the web ui on localhost, and then require SSH port forwarding to access it?

ssh -N -q -L 4449:127.0.0.1:4449 me@remote.ip.address

Here's the command breakdown: -N = Do not execute a remote command -q = quiet mode -L = port forwarding [local port]:[remote listen interface address]:[remote listen port] then the ssh destination user@host.

When this command is run, it forwards the remote 127.0.0.1 port 4449 to your localhost port 4449 - you just open your browser and navigate to 127.0.0.1:4449

Ctrl+C on the ssh command and the port forward is terminated.

This is how I control many services on servers around the world. This method allows automatic setup of the server, prevents anonymous access while the server is unconfigured, and restricts valid access to system users - the only people who can port forward are those who can SSH into the system.

Easy, and clean.

stutteringp0et commented 2 years ago

Expanding on my previous comment - it's simple enough to edit /etc/default/mysterium-node to add a command line option which enables the web ui on only 127.0.0.1

I added it to the DAEMON_OPTS after the keystore setting.

DAEMON_OPTS="--keystore.lightweight --ui.address 127.0.0.1"

to apply this change, you'll need to restart the daemon:

systemctl restart mysterium-node

or

service mysterium-node restart

Now, when systemd starts the service, it only listens on localhost - which requires that I use the SSH port forwarding trick I detailed above.

Now, if the installation didn't automatically start the service, that would be awesome....but such is the way of the world....

pianoman10 commented 2 years ago

@mysterium team. Could you please supervise this recommendation from @stutteringp0et, test it and advise if will not harm anything and if it is recommended as a work-around of security to access 4449 while an epic developing this properly is not in place? We need some kind of protection, we are no longer in testnet. That’s in Adam e for your response and your understanding

stutteringp0et commented 2 years ago

@pianoman10 @mysterium - I cleaned up and elaborated on the commands described above. I have this running on 16 servers in 7 countries - let me know if you need my account details so you can inspect their operation.

pianoman10 commented 2 years ago

@stutteringp0et I have been struggling to implement this "simple" thing for long time, using my Mac and the Terminal App on Mac to execute this ssh, but I will give it another try with your detailed instructions that I appreciate so much. Just a bit concerned of editing the DAEMON_OPTS as I do not like to touch anything on the RPi, but given that MYST Team is not given their input, I will take the risk, that I believe is less risky in the long-term than having the ports forwarded!!!!. Thanks again

stutteringp0et commented 2 years ago

@pianoman10 I see....

The command line options (which you can see by issuing the command: myst --help) shows the available command line options. The systemd service file shows that all of the configuration options come from /etc/default/mysterium-node - so there are only 2 ways to modify the mysterium-node service (/lib/systemd/system/mysterium-node.service), to edit the service file (which would get replaced on the next update - don't do it) or to edit the options file in /etc/default/mysterium-node.

I run a lot of Ubuntu servers for my business, and have figured out where best to make config changes. The nice part about this change is that the config file is super short, like 10 lines - there's really no getting lost in it. It's very easy to undo....just edit the file and restart the service.

I'd test out the ssh command first - because it will work (you'll be able to test browsing to 127.0.0.1:4449) without altering the server. Once you have that working, you can make the change to the server to shut off the public IP access to 4449.

Anyway, good luck - it's an easy config to make as long as you can make the ssh connection.

pianoman10 commented 2 years ago

@pianoman10 I see....

The command line options (which you can see by issuing the command: myst --help) shows the available command line options. The systemd service file shows that all of the configuration options come from /etc/default/mysterium-node - so there are only 2 ways to modify the mysterium-node service (/lib/systemd/system/mysterium-node.service), to edit the service file (which would get replaced on the next update - don't do it) or to edit the options file in /etc/default/mysterium-node.

I run a lot of Ubuntu servers for my business, and have figured out where best to make config changes. The nice part about this change is that the config file is super short, like 10 lines - there's really no getting lost in it. It's very easy to undo....just edit the file and restart the service.

I'd test out the ssh command first - because it will work (you'll be able to test browsing to 127.0.0.1:4449) without altering the server. Once you have that working, you can make the change to the server to shut off the public IP access to 4449.

Anyway, good luck - it's an easy config to make as long as you can make the ssh connection.

I have tried it and it works wonderfully! . I will remove immediately the forward of the port 4449. In regards to the changes in /etc/default/mysterium-node , I do not even have the DAEMON_OPTS= entry, my file is this simple:

cat /etc/default/mysterium-node

Define additional args for myst service (see myst --help for full list)

CONF_DIR="--config-dir=/etc/mysterium-node" SCRIPT_DIR="--script-dir=/etc/mysterium-node" RUN_DIR="--runtime-dir=/var/run/mysterium-node" DATA_DIR="--data-dir=/var/lib/mysterium-node" SERVICE_OPTS="wireguard"

So I guess that I only need to make another entry under "SERVICE_OPTS" that should read like this:

DAEMON_OPTS="--ui.address 127.0.0.1"

correct? should I dare? :-)

I guess that will not harm anything, but again, It would be nice to have the advise of the Mysterium team right?

I appreciate very much your explanation with this @stutteringp0et . as this is a CRITICAL issue, , especially to node-runners like me that I am very rusty in admin skills (use to have them back in the 90's !!!!!! I am very old :-)

I would suggest to the Mysterium Team to PIN your solution as the best workaround so far, while they implement more automated use-cases, that will take longer to be implemented, but we need a workaround like this RIGHT NOW

stutteringp0et commented 2 years ago

DAEMON_OPTS must retain what it had before, only adding the --ui.address parameter.

Not sure if the raspberry pi version uses different DAEMON_OPTS than the server version - but mine looks like this:

DAEMON_OPTS="--keystore.lightweight --ui.address 127.0.0.1"

Basically, whatever is already there, add to it.

pianoman10 commented 2 years ago

DAEMON_OPTS must retain what it had before, only adding the --ui.address parameter.

Not sure if the raspberry pi version uses different DAEMON_OPTS than the server version - but mine looks like this:

DAEMON_OPTS="--keystore.lightweight --ui.address 127.0.0.1"

Basically, whatever is already there, add to it.

Yes, understood, but the thing is that I have nothing there :-), that is, I do not even have an entry with "DAEMONS_OPTS" in any of my nodes, all of them are RPi. and they have been running for months, and were migrated into main net with auto-update (I did not even updated them, I let the team do it automatically)

so, my /etc/default/mysterium-node is EXACTLY as follows:

CONF_DIR="--config-dir=/etc/mysterium-node" SCRIPT_DIR="--script-dir=/etc/mysterium-node" RUN_DIR="--runtime-dir=/var/run/mysterium-node" DATA_DIR="--data-dir=/var/lib/mysterium-node" SERVICE_OPTS="wireguard"

so, as you can see, no "DAEMONS_OPTS entry pre-exist. I would need to create it. Weird? not sure. That is why I am requesting always help from the development team too, to clarify these kind of things. I sent a private message to one of the team members of Mysterium in discord. Let's see what they answer

Thanks again for your help

stutteringp0et commented 2 years ago

OK, have a look at /lib/systemd/system/mysterium-node.service

In the ExecStart line - do you see $DAEMON_OPTS ?

If so - then you can safely create the DAEMON_OPTS line in /etc/default/mysterium-node

If NOT, paste your ExecStart line here

pianoman10 commented 2 years ago

OK, have a look at /lib/systemd/system/mysterium-node.service

In the ExecStart line - do you see $DAEMON_OPTS ?

If so - then you can safely create the DAEMON_OPTS line in /etc/default/mysterium-node

If NOT, paste your ExecStart line here

YES, I can see $DAEMON_OPTS, this is the line that I have:

ExecStart=/usr/bin/myst $CONF_DIR $SCRIPT_DIR $DATA_DIR $RUN_DIR $DAEMON_OPTS service --agreed-terms-and-conditions $SERVICE_OPTS

I will then create this line DAEMON_OPTS="--keystore.lightweight --ui.address 127.0.0.1" in /etc/default/mysterium-node

(and of course, restart the service "systemctl restart mysterium-node")

All done! 💯 Thx!

stutteringp0et commented 2 years ago

Excellent @pianoman10 !

Snawoot commented 2 years ago

There were two questions raised: default password and secure remote access (authenticated encryption).

Answer to first question is very simple: we should just not enable any remote admin access before password is set. It's a wide practice and I don't see much of other options. It's less usable than unprotected access to onboarding page, but it's hard to compete with unprotected web page access in terms of usability.

Regarding HTTPS, I don't think what @zolia proposed is a viable option. There are number of reasons against that:

In a situation when node operator initializes sets up password-protected remote access we can utilize PAKE schemes. Namely, for that case TLS-SRP appears to be a good fit: user sets password and can connect to server with mutual authentication using just a password, without use of any PKI certificates. Moreover, data stored on node to validate password is insufficient to recover password, phish it or make a connection to anotner such node with same password.

However, there is a major challenge with TLS-SRP: it's not widely used and major browsers do not support it. But workaround is possible: node UI already proxies requests from its /tequilapi route to original tequilAPI on local port. If we separate node UI into a separate application and make it utilize TLS-SRP client connection, we will have separate client for node control and, at the same time, a client app which covers that gap in lack of TLS-SRP support in browser, accepting plain connections on local interface and forwarding requests to TequilAPI via TLS-SRP connection.

As far as I know @mdomasevicius is already experimenting with NodeUI Version Management. For me it is somehow consonant with my current proposal, if it helps making a separate admin app which does connection right.

pianoman10 commented 2 years ago

Sounds good as a long-term robust solution.

chompomonim commented 2 years ago

@Snawoot You proposed solution looks good. However there is one more problem. How users could connect to own node which is behind NAT? Not everyone is able to setup port forwarding (due to lack of skills or limitations of routers/ISPs). For such case I was proposing to allow setting "friendly identities" in node and when consumer with that identity would connect to node, node would allow his to reach NodeUI.

Snawoot commented 2 years ago

@chompomonim what you're talking about is a separate issue of node reachability. My proposal addresses explicitly security model for node admin access.

Reachability

If we implement my proposal and allow TLS-SRP port to be reachable on all network interfaces, then it will be possible for a user to use VPN to access node UI too. As these things are orthogonal, we can combine these approaches. It may prove useful sometimes, but not always:

Authentication

If we use "friendly identities" for authorization of access to node UI, we will have to build following chain of trust: trusted identity -> session and wireguard connection -> IP address assigned to that wireguard session. So, essentially it boils down to IP-based authorization because it's the only way for daemon to associate incoming request connection with trusted wireguard session.

We can improve such approach if in addition we will require something signed by friendly identity key. But that defies any benefits of such authentication because we could have secure key exchange with SRP in the first place, regardless of wireguard/IP tricks.