0

We are building a service that manages multiple user accounts. For that reason, we need to store the credentials to a user's accounts using a symmetrical algorithm so they can be retrieved for the server to pull updates for the accounts. We however do not want to keep the keys in the database therefore here is the scheme we came up with:

  • User logs into our system using their password over a secure SSL connection. Each user account has a unique salt attached to their account and it is used to hash their password and verify against the database. Hashing function used for this process is bcrypt.

  • If user login credentials are confirmed, a symmetrical AES-128 key is generated from their unencrypted password and their unique salt and attached to their session to decrypt the credentials of the third party accounts stored in the database.

I am no security expert therefore I will leave it to you guys to tear our scheme apart. Let the carnage begin.

  • Take a quick tout of the question in the "Related" box along the right side of this page. You might find some options in the questions others have asked. – schroeder May 9 '16 at 17:55
  • 1
    What happens when a user changes their password? suddenly their 3rd party account is now un-usable. Bad idea? – Robert Mennell May 9 '16 at 18:40
  • @RobertMennell That is a downfall we're willing to live with to keep our users' information confidential in case of an external or an internal breach. If a user changes their password, they will have to reenter the passwords to all their third party accounts so they can be reencrypted with new key. It would be worked into the password changing process as the first thing you would do when you log back in. – ReX357 May 9 '16 at 18:55
  • so they get decrypted, then encrypted with the new key if I'm understanding this right? – Robert Mennell May 9 '16 at 18:58
  • @RobertMennel In the case that the user changes their account password, they will have to reenter their passwords for all their managed accounts. The old ones will be worthless since there will be no way to decrypt them. Once you're logged in after changing your password, the server will attempt to pull updates and when the login credentials for an account do not work, you will simply be prompted to fix the credentials. Once you fixed the credentials, the reentered credentials will be encrypted with the new key generated from your new password. Think email client when you change your password. – ReX357 May 9 '16 at 19:40
1

You don't really describe this step very well:

If user login credentials are confirmed, a symmetrical AES-128 key is generated from their unencrypted password and their unique salt and attached to their session to decrypt the credentials of the third party accounts stored in the database.

Exactly how is that 128-bit key created? That should be a very slow process, otherwise you are providing a side-channel to brute-force user passwords. The way it would work is an attacker gets their hands on your database. Rather than try to brute force the bcrypt hashes, which would be very time consuming, they get to work on the encrypted passwords. They simply brute-force the user password to get keys that appear to work (ie: the decrypted text looks like passwords, whatever that means). This will be a fast attack because encryption is fast.

You need to make the 128-bit key creation a slow process. The best way to do this is probably to use bcrypt. But, as you have probably figured out, you don't want to use the bcrypt value that you've stored in the DB for authentication as that would not be a safe way to store encryption keys. I suggest that you keep a second salt for each user. You then use that salt, plus their clear-text password, in a call to bcrypt to generate the 128-bit encryption key.

When a user changes passwords, you should either wipe or reencrypt all of the encrypted passwords. This is needed because users frequently change passwords when they are concerned that their password has been compromised. So you better wipe the data that was encrypted with the compromised password. Though this, of course, won't help if the attacker already got a copy of the database before the password change.

Another security measure you could add is to pepper (search for "pepper" in this answer) the encryption key. The pepper should be a truly random bit string (no, your cat's name doesn't qualify) that you store someplace else. That is, it is not in the database. Use of a pepper will prevent an attacker who gets both a copy of your database and a user's password, from decrypting the user's data as they will still need the pepper. Remember that a pepper is only as helpful as it is secure. Putting it in your source repo is probably a bad idea.

  • To generate the key we simply hash the plain password with the user's salt (Same one used to bcrypt) using SHA-256. The resulting hash becomes the key to encipher/decipher text. As for the concern about the database compromise, talking with Robert in the comments above, I came to the conclusion that we would also hash the third party account passwords and in case of a breach, we would force users to change their 3rd party account passwords by comparing the hashes of the resubmitted credentials to the ones in the database. – ReX357 May 10 '16 at 3:26
  • I like the solution you came up with though, to hash again with bcrypt using a different salt. – ReX357 May 10 '16 at 3:28
  • @ReX357 - you must rehash to slow down brute force searches for the password. – Neil Smithline May 10 '16 at 4:01
  • @ReX357 - I read your conversation with Robert. While I think that's a good idea, it is not perfect. Another thing that you can do in the face of a breach is to destroy your pepper. That will instantly invalidate all of the passwords you have stored. So, even if an attacker has the database and a user password, they'll be no way to get the pepper as you've changed it (and done your best to remove backups and such). – Neil Smithline May 10 '16 at 4:03
  • @ReX357 - In the end, storing recoverable passwords, however it is done, is risky. Systems like OAuth were created to prevent the need for password storage. But, if the services you're integrating with don't support OAuth, there's nothing that you can do about it. – Neil Smithline May 10 '16 at 4:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.