Habitica: convert user password encryption to BCrypt

Created on 7 Nov 2015  路  16Comments  路  Source: HabitRPG/habitica

Currently, we use SHA1 for encrypting users' passwords. BCrypt is more secure so we will move to it.

Reasons why are outlined in the MOVE TO BCRYPT Trello card, especially the comment by Sherman Boyd. We're continuing the conversation in this issue.

As Sherman points out, the code change will be easy but migrating users will be hard. We cannot invalidate all current passwords, even with advanced notice, because many users would not read the notice and having many unable to log in with their expected passwords would be a support and publicity nightmare.

Perhaps we can have both schemes in use in the codebase at the same time, with each user account having a flag to indicate which they use.

  • Any new account would be on the new scheme automatically.
  • Any existing account that changed their password would use the new scheme.
  • Any account that logged in could have their password updated to the new scheme at that time (@crookedneighbour's idea).
  • To future-proof this, was can use "tags" or similar in the password hash or in a related database field so that multiple algorithms can be supported at once (shermanhuman's comment below).

Assuming we do the password-update-on-login idea, these ideas become less relevant (although note that some users might not log off and on for weeks):

  • Users could be encouraged to reset their passwords with repeated notifications.
  • We could make a modal pop up when the user first loads the site prompting them to update their password.
  • We could offer incentives such as an achievement badge, but that's probably not a good idea since many users would be getting it automatically just by logging out and in.
  • We might need to consider something different for those users who never use the website.
  • After a few months, we could send emails to users on the old scheme, and eventually perhaps enforce the change by invalidating old passwords. An enforced change would help us by allowing us to remove the old SHA1 code and the database flag (cleaner codebase). It would also help the users by making their accounts more secure.

I suggest that accounts that haven't been used for more than several months could be changed to the new scheme immediately. It's likely those users would have forgotten their passwords anyway (admittedly I'm ignoring those who use password managers).

Any other suggestions / comments?

EDIT: Note @crookedneighbor's comment below about changing the code to use hashedPassword instead of hashed_password, and storing the BCrypt password in a new hashedPassword database field. We can probably use the existence of that field instead of the flag mentioned above.

important status in progress

Most helpful comment

All 16 comments

Note that when users change their passwords, they can enter the same password as before. It would then be encrypted in the new scheme and they wouldn't have to remember a new password.

The simplest approach might be to go with the two-schemes system (all new users use BCrypt, all users who change passwords use BCrypt, everyone else keeps their old SHA1 password) but with no user notification, and then later we can worry about whether we ask/encourage/force users to change.

Could we also have it swap out the password for new hashed one when the user logs in?

omg genius

I'm updating my first post to include that so we don't forget it and so it looks as if I thought of it. ;)

For this, we should make the snakecase hashed_password a camelcase hashedPassword.

With v3, eslint will fail the build for using snakecase. I can set it to ignore that specific line (see https://github.com/HabitRPG/habitrpg/pull/6203/files#r44226378), but it'd be better to not have to do that. Since this work needs to be done anyway, we might as well do that change now, rather than do a migration later.

I'm thinking that whenever the new Bcrypted password gets saved, it gets saved to the new hashedPassword instead of to hashed_password, and then once everyone is converted over we can remove hashed_password from the model.

You could also do the following:

  • Log everyone out, except for those who have passwordless Facebook logins
  • When they log back in, check the password against the SHA-1 version
  • If the password is correct, add the bcrypted version and destroy the SHA-1 version

If they forgot their password:

  • The "Forgot Password" link on the login screen will work as normal
  • They reset their password with a new one
  • The new password is stored bcrypted

This is a very smooth way of handling it with only minor, if any, annoyance. Most people will just take a few seconds, log in, and won't even notice the nice security benefit.

The only people I see needing help are those who forgot their password and no longer have access to their e-mail account.

Being logged out automatically from Habitica isn't something that typically happens, so if all non-facebook players were logged out at once, there'd be questions in the Tavern and social media about what had happened, and then a lot of "me too" posts. It would make Habitica seem buggy.

Also there's likely to be more players than you'd think who have lost access to their email accounts or who mistyped their email addresses when they registered - we get a surprising number of support requests about that. If we had to handle requests from all of those players at once, it would be overwhelming.

I think a slower process of converting passwords as people log out and in manually in their own time is all that's needed at first. After a few weeks, we can assess the accounts remaining to be converted and make plans for them then.

I agree. Logging out everyone at once would be a support nightmare.

I think we should just have some friendly reminders to do it, and maybe some kind of incentive?

If we can get the majority of active users to switch over voluntarily, then we can discuss logging the rest of them out.

The tags idea is a good one. It doesn't hurt to look at the future too, when someone figures out an attack against bcrypt. I was looking into how Linux handles this. Linux predates most hashing algorithms, so they had to figure out a future proof way handle hashing algorithm changes. Basically they embed a tag in front of the hash:

Example hash: $1$Etg2ExUZ$F9NTP7omafhKIlqaBMqng1

$1$ = MD5 
$2$ = Blowfish 
$2a$ = eksblowfish 
$5$ = SHA-256 
$6$ = SHA-512 

You could add the tags (not necessarily in the hash), and support multiple algorithms, with a 'default' algorithm.

The switch should be transparent to users, changing the passwords hashes when they login is a great way to do it. They don't really care about password hashes, so best not to involve them. You'll get the most active users, the valuable ones right away. Add processes to kick users after being logged for an extended period of time, and a process to prune / retire inactive accounts. Eventually you will get them all.

The upside to this approach is that you could just code it, implement and forget it. Logging someone out eventually is probably a good thing in general, and so is pruning inactive members. Downside is more code, complexity. Some exposure over time, but they have to get your hashes first, before they can start cracking them.

I love the idea of tags or similar - that's very clever! I've added a note about it to the top post.

I'm glad to see this is being worked on - thank you! @crookedneighbor 's idea of offering incentive would definitely speed compliance (assuming the infrastructure exists to offer the user a piece of gold for doing a site task). If it takes several months to slowly migrate the rest, so as to not overwhelm support, at least it's done after those several months! Unfortunately at $dayjob I've been telling people "when your password database is stolen" rather than "if" lately.

We could also make a modal pop up when the user first loads the site prompting them to update their password. (They could even do it right from the modal)

A modal is a nice idea! It might be the only incentive we need to get many of the users converted. Although I'd like to see it implemented a couple of weeks or more after the feature where their password is automatically updated when they log in. We're bound to get questions about why the modal exists (even if the modal explains why itself!) and reducing the number of people who need to be shown the modal would help with that.

I've added the idea to the top post.

Unfortunately at $dayjob I've been telling people "when your password database is stolen" rather than "if" lately.

Yeah, additionally the exposure goes beyond habitica, surely there are users that use the same password for everything; Amazon, Paypal, online baking etc. With that in mind sooner sounds better than later.

Was this page helpful?
0 / 5 - 0 ratings