How to upgrade a password storage scheme (change hashing-algorithm)

后端 未结 7 1090
庸人自扰
庸人自扰 2021-02-02 09:33

I\'ve been asked to implement some changes/updates to an intranet-site; make it \'future proof\' as they call it.

We found that the passwords are hashed using the MD5

相关标签:
7条回答
  • 2021-02-02 09:50

    The best answer is from an actual cryptography expert https://paragonie.com/blog/2016/02/how-safely-store-password-in-2016#legacy-hashes

    This post also helps explain which hashing you should use. It's still current even if it says 2016. If in doubt use bcrypt.

    Add a column to your user accounts table, called legacy_password (or equivalent). This is just a Boolean

    Calculate the new stronger hash of the existing password hashes and store them in the database.

    Modify your authentication code to handle the legacy flag.

    When a user attempts to login, first check if the legacy_password flag is set. If it is, first pre-hash their password with your old password hashing algorithm, then use this prehashed value in place of their password. Afterwards (md5), recalculate the new hash and store the new hash in the database, disabling the legacy_password flag in the process.

    0 讨论(0)
  • 2021-02-02 09:52

    Add passwordChange datetime field to the database.

    All password set before day X, check using MD5

    All passwords set after day X, check using BCrypt or whatever.

    0 讨论(0)
  • 2021-02-02 10:00

    Since you don't know plaintext password, maybe you should to create a field which indicates encription version (like PasswordVersion bit default 0)

    Next time user tries to log in, check hashed password using current algorithm version, just like you do today. If it matches, hash it again and update PasswordVersion field.

    Hopefully you'll not need a PasswordVersion column bigger than bit. =)

    0 讨论(0)
  • 2021-02-02 10:09

    I'm not entirely sure about this option, since I'm not an expert on cryptography. Please correct me if I'm wrong at some point here!

    I think Dave P. has clearly the best option.

    ... but. There is an automagic solution - hash the older hashes themselves. That is, take the current hashes, and hash them again with a stronger algorithm. Notice that as far as I understand, you don't get any added security from hash length here, only the added cryptographical complexity of the new algorithm.

    The problem is, of course, that checking a password would then have to go through both hashes. And you'd have to do the same for evey new password as well. Which is, well, pretty much silly. Unless you want to use a similar scheme like Dave P. explained to eventually graduate back to single-hashed passwords with the new hashing algorithm... in which case, why even bother with this? (Granted, you might use it in a flashy "Improved security for all passwords, applied immediately!"-way at a presentation to corporate suits, with a relatively straight face...)

    Still, it's an option that can be applied immediately to all current passwords, without any gradual migration phase.

    But boy, oh boy, is someone going to have a good laugh looking at that code later on! :)

    0 讨论(0)
  • 2021-02-02 10:10

    You could store, either in the hash field itself (e.g. "MD5:d41d8cd98f00b204e9800998ecf8427e") or in another column, which algorithm was used to create that hash. Then you'd have to modify the login process to use the correct algorithm when checking the password. Naturally, any new passwords will be hashed using the new algorithm. Hopefully, passwords eventually expire, and over time all of the MD5 hashes will be phased out.

    0 讨论(0)
  • 2021-02-02 10:11

    You should change your password database to store 3 items:

    1. An algorithm identifier.
    2. A random salt string chosen by the server when it first computes and stores the password hash.
    3. The hash of the concatenation of salt+password using the specified algorithm.

    Of course these could just be stored together in one text field with a delimiter:

    "SHA256:this-is-salt:this-is-hash-value"

    Now convert you existing entries to a value with empty salt and the old algorithm

    "MD5::this-is-the-old-md5-hash-without-salt"

    Now you have enough information to verify all you existing password entries, but you can also verify new entries (since you know which hash function was used). You can convert the old entries to the new algorithm the next time the existing users login since you will have their password available during this process:

    1. If your database indicates they are using the old algorithm with no salt, first verify the password the old way by checking that the MD5 hash of the password matches. If not, reject the login.
    2. If the password was verified, have the server choose a random salt string, compute the SHA256 hash of the salt+password, and replace the password table entry with a new one specifiy the new algorithm, salt and hash.
    3. When the user logs in again, you'll see they are using the new algorithm, so compute the hash of the salt+password and check that it matches the stored hash.

    Eventually, after this system has been running for a suitable time, you can disable accounts that haven't been converted (if desired).

    The addition of a random salt string unique to each entry makes this scheme much more resistent to dictionary attacks using rainbow tables.

    0 讨论(0)
提交回复
热议问题