Project-Pandora-Game / pandora

https://project-pandora.com
Other
11 stars 2 forks source link

Improve account security #462

Open ClaudiaMia opened 11 months ago

ClaudiaMia commented 11 months ago

As the username is known, the topic of making it too hard to guess passwords comes into focus.

For once, we should require a minimum password length of 8(?) characters.

Then I believe the server should artificially wait a random amount of milliseconds (maybe within the range of 1 and 4 seconds) while checking for a password and then maybe limit the amount of accepted parallel requests with the same username.

Unless we always ask for a captcha after 3 failed tries, we should maybe consider the following: After we detected that we had a large amount (30? 50? 100?) of failed login attempts with the same username within a certain amount of time, we switch the login form of Pandora globally to a different design for the next hour: The form would ask only for the username and providing it proceeds to a new page that prompts for the password separately. If the provided username was one of the usernames that received a large amount of failed login tries, we ask the user to solve a captcha from the start alongside the password input.

Sekkmer commented 10 months ago

I think we could add a second factor, this could have a few options after the user presses login, the second factor will be requested, and password validity is only returned if both succeed

maybe captcha could be enforced to be set at least the 'after 3 failed attempts' option

another thing that could be considered is time-based IP ban, where after 10-50 invalid attempts the IP address will be banned for some period of time from login in, registering, or requesting a password change

ClaudiaMia commented 10 months ago

Yes, requesting a captcha after 3 failed attempts with the same username in a certain amount of time, was what I basically suggested. After a successful login, the required captcha flag could be removed again from the affected account.

That we force the user to set up a 2nd factor via a token app or something like that is not a good idea I think. It is of course very secure, but it would be quite demanding of our users and I am not sure they would be willing to do so during registration.

Sending a 2nd factor code via email is not possible as we cannot contact users via e-mail unless they provide the email to us during the login, too. I think this would be possible as an alternative to solving a captcha after the x-th failed attempt or so.

I guess IP ban is too easy to circumvent? Hence my original suggestion of artificial login request processing limits based on small waits if the request is for the same username as well as not allowing parallel requests for the same username and limiting the amount of such requests we would queue for different users/IPs. But not sure if these measures are actually still needed if the captchas are enough of a roadblock and after some further failed attempts we ask for the email to send a code for every further attempt.

ClaudiaMia commented 10 months ago

The flow to ask for the email and to input the code might be interesting to design though.

So if we imagine the user sent username and password and successful captcha solution for the maybe 10th time:

  1. the screen would show a new input field that prompts for the email address
  2. sending any email address would change the screen to a new input field for entering the 2nd factor code received via the provided mail address
  3. in the background we would compare the entered email address with the stored hash and send an email with the code only if the hashes match, but we would not tell the user if we sent an email or not
  4. this screen to enter the code from the email could then be a fake as we never sent out an email
  5. I suggest we forward the user back to the login screen after they tried to enter some code for 3 times and it was either not the one we expected or we never expected a code as we never sent a mail, hiding all of that from the user
Jomshir98 commented 10 months ago

Hmm, I would like to suggest a lot simpler way to do it, that is just as effective: When we receive enough failed login attempts recently (e.g. more than 30 in the last 15 minutes; can be edited or even be scalable; counted globally across all accounts), then we give a captcha to everyone trying to log in.

ClaudiaMia commented 10 months ago

Hmm, sure! I think that may be good enough for now if we also demand a minimum password length of maybe 8 characters.

If we later on see that this is triggered heavily and we see evidence that we may need more security, we can still implement other measures on top.

But I would not count all failed login attempts globally across all accounts, but I would say only if some account goes over the threshold of failed attempts for that username, we set that globally for some time or is that tricky to track per account over some time frame?

ClaudiaMia commented 10 months ago

On the other hand, if we simply track number of failed attempts as a value per account as well as timestamp of last login attempt, then we can avoid bothering everyone with captchas, IF....

...if we change the login form to two steps: First only the username and only in the next screen the password.

That way we can enforce captchas per account.

Otherwise someone could make it a sport to ensure that captchas are requested all the time to annoy every user.

Jomshir98 commented 10 months ago

This is problematic, as it brings possibility of enumerating usernames - it is not that easy to implement this in a way that someone cannot test if username exists. Also browser password autocomplete doesn't really like this - while you can make it work and let it fill in the username and password one at a time, it also removes possibility of resident credentials autologin and makes it less convenient for users (they have to click button to continue twice, while their browser would have otherwise filled both at the same time on the first screen). Yes, there are other possibilities that makes this less of a problem, such as remembering username even if login token is no longer valid (so user that logged at least once always skips username entry, even if they need to log in again), but it is all about tradeoffs.

ClaudiaMia commented 10 months ago

Hmm, I would like to suggest a lot simpler way to do it, that is just as effective: When we receive enough failed login attempts recently (e.g. more than 30 in the last 15 minutes; can be edited or even be scalable; counted globally across all accounts), then we give a captcha to everyone trying to log in.

Then I guess we are back to the above for now?

Sekkmer commented 10 months ago

Separating user and password in separate forms is a no, we never want to give out any information based on the username alone

the way I would add this is login response with a list of 2nd factors the user needs to complete, this allows it to be extendable if we want, and would allow us to force captche globally if we want to if we deem that to many global attempts has been made, and same if it just for a single user

Sekkmer commented 10 months ago

displayName that Jomshir started to add should be standardized across all public interfaces so username is no longer public, then a mechanism with at least a week time limit should be added that allows displayName change

Jomshir98 commented 10 months ago

Ref: #505

Sekkmer commented 9 months ago

Ref: #567

lina-cat commented 7 months ago

As for password strength I strongly advice against rules like "at least 8 characters" since it often does not lead to stronger passwords. Instead using a password strength estimator like zxcvbn is usually a way better option. It requires enough entropy and blocks commonly used words etc. "password" has 8 characters but is a very bad idea... and the library would catch that. Additionally it allows a life preview of password strength that can be displayed under the password field when chosing it.

TOTP I would also recommend as a very simple second factor.

For bruteforce protection I would recommend the standard exponential backoff on top of forcing captchas and forcing captchas globally if the ratio of success/attempts falls too low