Currently the authentication is brute-forceble as in, no limits on the the amount of attempts or the period wherein it's taken place. Meaning an attacker could try guessing as long and as fast as he wants without any interruption.
I suggest to allow two or three wrong attempts normally. Then doing two things:
Also to make brute-forcing harder you could consider something like reCAPTCHA.
The session should be bind to the IP-address and/or user-agent. If any of those changes during the session, we can destroy the session as that might be a sign of session hijacking. That is especially easy if people don't use SSL. Binding it to the IP-address and user-agent solves that. Also it would be great to be able to configure the session timeout time on the settings page.
Clear-text password storage is not done. https://github.com/deluan/navidrome/issues/202. Password should always be hashed preferably salted also, never encrypted. We should make an API token or insecure and very restricted (read-only) credential if that's needed for compatibility with other tools.
I was just allowed to make an admin user with a one-letter password. I would at activate some minimal password policy. Minimal 6 characters, one char of [a-z][A-Z][0-9] and a special char. Not allowing the password to be identical (or very similar) to the username or e-mail address. _Also, probably one, two or three letter usernames should be prevented. I am not sure if there is a maximum length on the password now, but there should not be or it should be as high as possible._
To greatly improve the authentication we could think of introduction of the open standard HOTP/TOTP two-factor authentication (which I would also like to see a lot). It works with all current TFA apps like Google Authenticator, Microsoft Authenticator, Authy.
Lastly, I just removed myself (test user), that should not be possible. Also, when I did that I wasn't logged out or sent back to the login page. So I stayed without valid session in the application showing me only "internal server errors" (luckily). Also I noticed that email is a required field when adding a new user but not when editing it. I should make it consistent.
And of course all of above suggestions could be optional and configurable in the settings page. But personally I would always opt for a secure-by-default and privacy-by-default option for as much as possible without degrading the user experience or limiting functionality for advanced users too much.
Captchas are a disaster in term of accessibility: people struggling to type their password would have their live made more difficult if they have to fill captchas. Moreover, blocking user login will lead to denial of services: an attacker can trivially throw a ton of login attempts, preventing legitimate users from using the service.
Session-binding is a bad idea in 2020, since everybody is roaming a lot.
As for password policy, something like zxcvbn would be better than enforcing some arbitrary rules.
I'm not sure I understand the value of OTP here: an attacker could perform authentication bruteforce via the API, and gain almost the same privileges.
Would it be possible to just restrict navidrome to 1 auth attempt per 10 seconds? That would slow down any bruteforcing attempt considerably.
I'm gonna work on these improvements next. My considerations and what I'm planning to do:
Removing own user: This is a bug and will be fixed
Blocking/Delayed logins, Captcha, Two-factor authentication: These are out-of-scope for Navidrome. Remember: Navidrome is not a service, it is a server! When installing your own server you should use a reverse proxy to harden your installation, and these features are better suited to be implemented/configured/supported by this inbound proxy server. I may even implement a way to disable authentication all-together, allowing the (power) user to use Navidrome with something like Vouch to provide SSO/OAuth2 authentication
exponential backoff instead of a linear delay, and be mindful about ipv6 addresses :)I'll search for a ready to use implementation of exponential backoff, but I don't want to spend too much time on this, as rate-limiting also falls into the category of things that are responsibility of the inbound proxy server, IMHO.
For session bind, I think having to login when the browser is updated is a small price to pay for a more secure experience, don't you think?
What security property does it bring? If an attacker is able to intercept a session cookies, they'll likely able to intercept the user-agent as well :P
Yep, you are right :P
Rate limit using a Sliding Window strategy was implemented in f0160f5d2adc77291afd56329f17377daa802bdc, will be part of the v0.26.0 release
Is this by IP address? With IPv6 you probably want to rate-limit it by IPv6 prefix - i.e. limiting logins from the same /56, /60 or /64, since it's trivial to generate a new IPv6 address for every login attempt.
It is based on IP address. It was implemented using this middleware: https://github.com/go-chi/httprate
The algorithm used to create the key for the limiter is here: https://github.com/go-chi/httprate/blob/master/httprate.go#L24. When I'm back at this, I may take a look on ways to improve it
@jvoisin Is there anything newer than zxcvbn that you recommend? Last release of zxcvbn was 4 years ago, has some issues with modern JS and lots of open PRs... :(
I don't know any alternatives :/
Most helpful comment
Captchas are a disaster in term of accessibility: people struggling to type their password would have their live made more difficult if they have to fill captchas. Moreover, blocking user login will lead to denial of services: an attacker can trivially throw a ton of login attempts, preventing legitimate users from using the service.
Session-binding is a bad idea in 2020, since everybody is roaming a lot.
As for password policy, something like zxcvbn would be better than enforcing some arbitrary rules.
I'm not sure I understand the value of OTP here: an attacker could perform authentication bruteforce via the API, and gain almost the same privileges.