ravenclaw900 / DietPi-Dashboard

A lightweight, standalone web dashboard for DietPi
GNU General Public License v3.0
127 stars 17 forks source link

Fingerprint cookie breaks connecting to different nodes #548

Open ravenclaw900 opened 1 year ago

ravenclaw900 commented 1 year ago

Due to browser mechanics, when trying to connect to another node, the fingerprint cookie cannot be set by the other node when trying to login, therefore the token will always fail to validate. I have tried a lot of things to get it to work, but there really seems to be no way to either set the cookie or read the original one from a different domain.

Therefore, my new idea is to scrap the fingerprint/long-lived token approach for a different best-practice. 2 major things will need to change:

  1. The other/backend nodes will no longer have their own login and password. Instead, they will use asymmetric (pub/priv) key authentication to verify the token generated by the main node.
  2. Instead of having 1 token stored in localStorage, when logging in there will be 2 tokens generated. One will be a long-lived 'refresh' token, stored (like the fingerprint currently) in an HttpOnly cookie so it can't be read/stolen by the JS script. The other will be a very short-lived 'access' token, with no persistent storage. If the frontend tries to make a request with an expired access token, it can use the refresh token to request a new access token (this might also update the timestamp on the refresh token so that it lives longer).

This will prevent many of the same security holes that the fingerprint approach did, with fewer downsides. However, if an access token is somehow stolen, the attackers will have access to change things until it expires. To minimize the damage caused from this hypothetical attack, the terminal page could require a separate login, which would give you one-time access to the terminal, so that it would not be possible to make any massive changes to the device by stealing the access token.

I hope that explanation made sense, but for more information on the access/refresh approach (though anything about OAuth2 can be ignored): https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/

MichaIng commented 1 year ago

I think the single credentials are even positive (simpler) from user perspective. But how to we handle the initial key exchange between frontend and backend?

Access+refresh tokens are quite common practice, also Google Drive and/or Dropbox use this (we needed to implement it into motionEye for cloud uploads).

I lost track on how authentication with backend nodes was/is actually handled until last release?

the terminal page could require a separate login

Simplest would be to enforce manual login on the console, so no additional login mechanism needs to be implemented.

ravenclaw900 commented 1 year ago

My current thought is that a keypair will be generated on initial install, and the public key will just have to be copied from the main node to the other nodes. That seems easier than trying to implement something like ECDH over HTTP.

Before the fingerprint was set up, there was just a token stored in localStorage, with only the traditional verification (issuer, expiry time, issued time).

MichaIng commented 1 year ago

The public key long with a "copy to clipboard" button could be shown on the frontend as well, to make it a little easier.

Before the fingerprint was set up, there was just a token stored in localStorage

Ah right: #330 Does this mean that connecting to other backends is broken with current release, or is it just that one needs to re-enter the password whenever reloading the page? Not sure when I tested it the last time.

ravenclaw900 commented 1 year ago

Yes, assuming the backend node has a password, it is currently broken.