node icon indicating copy to clipboard operation
node copied to clipboard

RFC: securing web-ui

Open zolia opened this issue 5 years ago • 22 comments

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:

  • default passwords
  • web-ui listens on non-localhost IPs
  • web-ui uses plain http

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

  • enable tor (or tor like) integration to make administrative access to node secure
  • do not start a node until terms & conditions are accepted and default password changed
  • do not allow changing payout address. Payout address is registered during identity registration
  • generate 2nd private key for node management and export it via qrcode to some external application for secure communication with node. This communication could be performed via current broker or through additional service exposed through discovery for node management.

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

zolia avatar Apr 10 '20 12:04 zolia

Adding https support

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

  • we setup DNS server and manage some domain: *.webui.net
  • on node startup node sends his public identity to this DNS service
  • DNS service registers this domain as 0xMY_VERY_LONG_IDENTITY.webui.net
  • DNS service uses letsencrypt client to fetch certificate for that specific domain using DNS validation
  • node performs another request to DNS service. This time it sends its local IP to service and fetches generated certificate
  • DNS service updates domain with local IP
  • node sets up certificate and enables HTTPS access for a node operator
  • connecting to plain http :4449 now redirects to https://0xMY_VERY_LONG_IDENTITY.webui.net

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

zolia avatar Apr 10 '20 12:04 zolia

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).

anjmao avatar Apr 10 '20 13:04 anjmao

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 <you private IP>.nip.io And https://<you private IP>.nip.io:4449 would route you to your local IP address Node UI web.

eugenegoncharuk avatar May 14 '21 08:05 eugenegoncharuk

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

pianoman10 avatar Jun 22 '21 10:06 pianoman10

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.

HappyEarthDay avatar Jun 24 '21 03:06 HappyEarthDay

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).

chompomonim avatar Jun 24 '21 11:06 chompomonim

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 [email protected]

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 avatar Dec 06 '21 21:12 stutteringp0et

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

stutteringp0et avatar Dec 07 '21 03:12 stutteringp0et

@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

pianoman10 avatar Dec 07 '21 08:12 pianoman10

@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.

stutteringp0et avatar Dec 07 '21 15:12 stutteringp0et

@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

pianoman10 avatar Dec 07 '21 19:12 pianoman10

@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.

stutteringp0et avatar Dec 07 '21 20:12 stutteringp0et

@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

pianoman10 avatar Dec 07 '21 20:12 pianoman10

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.

stutteringp0et avatar Dec 07 '21 22:12 stutteringp0et

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

pianoman10 avatar Dec 07 '21 22:12 pianoman10

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

stutteringp0et avatar Dec 08 '21 00:12 stutteringp0et

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!

pianoman10 avatar Dec 08 '21 00:12 pianoman10

Excellent @pianoman10 !

stutteringp0et avatar Dec 08 '21 01:12 stutteringp0et

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:

  • LetsEncrypt limits: 50 certificates per registered domain per week. Registered domain is a first significant name after common part in public suffix list.
  • It relies on centralized domain as a mean to access decentralized nodes and requires to trust that domain operator ultimately.
  • It does questionable transfers of trust: trust to accessed node -> trust to identity it serves -> trust to subdomain -> trust to PKI certificate for that subdomain. Below I'll propose a method which allows to induce trust to encrypted channel between node and node operator just from the fact operator installed it.

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.

Snawoot avatar Dec 13 '21 19:12 Snawoot

Sounds good as a long-term robust solution.

pianoman10 avatar Dec 13 '21 19:12 pianoman10

@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.

chompomonim avatar Dec 14 '21 13:12 chompomonim

@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:

  • If I want to suspend share of traffic, I'd like to stop VPN service at all, leaving node running to re-enable it later. But after that I won't be able to connect to a node this way because VPN is disabled. In general, point of visiting admin UI is to troubleshoot something, but this way admin UI depends on node operation in first place. For this reason admin interface usually does not depend on service itself.
  • Our NAT traversal does not enable universal access either because symmetric NAT can't connect to symmetric NAT or port restricted cone NAT and vice versa. At this moment there are 7131 proposals in our discovery and only 4353 are compatible with symmetric NAT consumer.

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.

Snawoot avatar Dec 14 '21 14:12 Snawoot