Salted Password Hashing - Doing it Right
crackstation.net
crackstation.net
function HashPassword($password)
{
$salt = bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM)); //get 256 random bits in hex
$hash = hash("sha256", $salt . $password); //prepend the salt, then hash
//store the salt and hash in the same string, so only 1 DB column is needed
$final = $salt . $hash;
return $final;
}
It's becoming ridiculous.md5(sha1(md5(md5(password) + sha1(password)) + md5(password)))
Which is not an appropriate method to circumvent.
SHA512 is obviously a bit most costly, and therefore harder to bruteforce, but if you truly care about security you would be best to use PBKDF2 at minimum (built into Django's standard).
The length of the salt might incur 1-2 additional calls to the SHA core permutation function, which is nothing.
This is where some people think they are being clever. Because they think to themselves,
"hey, if I keep the salt secret and don't store the salt in the same table, or in the same field, then I've got awesome security by secrecy".
So all they do is hard code a salt that they reuuse for every hash in their application. Which offers them a lot less security overall for their users.
I have zero problem with storing the salt alongside the hashed password, because in practice, it doesn't make anything less secure.
Great, now please go and fix your software to use slow password hashing function!
Nothing that I said was wrong (in fact it's sound advice), so I'm a little shocked at the massive downvotes, your blunt response, followed up with the patronising advice to rewrite all my software.
(And no, I don't use SHA. I didn't spot that in your snippet.)
An article [1] that appeared on HN last month (comments:[2]) also explains why just using hashing with a quick digest function is a bad idea, although this original article does a decent job of it (despite the author ignoring his/her own advice).
This article also uses built in equality tests for comparing the supplied hash to the stored hash. This is bad practice, as it is vulnerable to timing attacks. [1] covers this in the Extra section.
[1] : http://throwingfire.com/storing-passwords-securely/?utm_sour...
Agreed. The article at http://codahale.com/how-to-safely-store-a-password/ is also convincing in this respect.
If you store the session key then delete them.
If you calculate a session key on the fly (as a hash) then mix the hashed password into your session key, so if the password changes (even if it changes back to what it was) the session key will be different.
What prevents the same enumerating attack against the sign up form. Are you going to give them a generic message that the username is invalid when it in fact has been taken?
Also the article implies that you need to use salt but than recommends using bcrypt which already includes salt.
Good read on how passwords are attacked.
This is a good point, but I suppose that, all other things being equal, it's better to put the key under the mat than it is to put it on top it. IOW, the more sophistication your attacker needs, the better.
Good point. Nothing prevents this, but it is easier to detect this kind of abuse on the sign up form and alert on it than all of the noise on the sign-in side.
There are, more frequently, CAPTCHAs on registration forms.
A better solution would be to rate limit incorrect username guesses. It's highly unlikely that a user is going to try more than a dozen usernames/emails - so that's strong signal that someone is trying to leak username information from your database.
Why should a form that accepts human input accept input much faster than a human can generate it? Limiting form submissions to about one every second per IP should greatly reduce the value of brute force attacks without being perceptible at all to actual users.
If you're worried that will be too slow for your users, make it a tenth of a second. That should still be far too slow for enumeration or other brute force techniques to be worthwhile.
Rule 1: Use a Modern Hash Algorithm (bcrypt, PBKDF2, scrypt)
Rule 2a: Use a Long Cryptographically Random Per-User Salt
Rule 2b: Have an additional 'system' salt that is a fixed value for the entire system and it's not stored in the database (better hide it in the source code)
Rule 3: Iterate the hash
Source: https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet
------
For ASP.NET the only proven option for rule 1 is PBKDF2 which is builtin (http://msdn.microsoft.com/en-us/library/system.security.cryp...)
At least if the salt is within the source code, it's hidden from plain view. Or did I miss something?
Edit: also, instead of using a "system salt", why not use an HMAC to replace hash function?
DO NOT DO CRYPTO YOURSELF
Of course, in the case of password hashing, the answer is pretty easy. (Spoilers: scrypt if there's an easy library for your language of choice, bcrypt otherwise, and PBKDF2 if you need to justify your decision to someone who habitually wears a tie.)
You're preaching to the choir on HN when it comes to PBKDF and Bcrypt and Scrypt and all that; but outside of our circle, people will consider anything documented on the net to be potentially expert advice.
Check this for a bunch of custom password hashing functions: http://php.net/manual/en/function.sha1.php
This is what HN does right now. I know, because I forgot my password just yesterday.
Why not? The salt is still unique to that user. What's the benefit to changing it?
By changing the salt, you change the hashed password. So when the user changes their password it actually changes, and those other hashes change too.
If you kept the salt the same then if the user changes the password back to what it was nothing actually changes.
No! At the very least, you ought to be using an HMAC.
1. Use memcached or asp.net cache to detect if a high number of login attempts are happening, if so, implement a 1 to 2 second sleep on each login attempt for 15 minutes (with some additional per IP slowing).
2. Put a sleep for 500ms on all login attempts.
I've been doing both for a while, with the thought that they are effective methods in conjunction with proper hashing.
You do mention this in addition to "proper hashing", so I'm sure you recognize this as well, but I think it is important to emphasize secure hashing practices before any talk of securing your app's login endpoint itself.
Additionally, each salt is still unique per password, so the attacker would need to generate a full dictionary per record that they want to crack - generally not worth it.
I just think that starting out planning for password hash function migration, when it's easy to retrofit later, is a bad case of premature optimization.
"when it's easy to retrofit later" - I think this is the key part of your statement. When is it easy to retrofit later? You then have to pick your poison:
1. Switch entire system over to new hashing function - reset all user's passwords 2. Add in interoperability of hashing functions - what I'm suggesting you do from the beginning, making it much easier to do.
Number 1 is a horrible user experience, number 2 is much easier to do from the onset.
I like the method that link provided, but there are some drawbacks, needing to update every user record with a new hash (offline process) - this is almost guaranteed to require taking the site down, which most people do not like to do. This is because you can't have some users with the old hashing process ,and some with the new.
There is a third way that is not poison:
No need to reset the passwords at one fell swoop.
When you decide to do a new password storage function:
New users get the new hash right away.
Calculate the new hash and the old hash when the user next logs in.
If the old hash matches, the user has logged in, and now calculate the new hash and store it over the old hash in the table. Perhaps make a note in a separate column that the hash has been converted.
Eventually, when all users have refreshed their passwords, quietly remove the old way.
Zero user involvement.
[method]$[salt]$[hash]
sha256$fi93heyf789s2hfk$j2398fdperoc983m4n58djs20
Also, I like how Django's authentication can cycle through a list of schemes making it easy to switch or accommodate legacy accounts.
Although there is an open source BCrypt port to .NET from Java, it hasn't been verified in terms of its implementation as a third party library, and to do so costs bucks.
Therefore, the recommendation for .NET for increasing the compute factor is to use PBKDF2 instead of bcrypt since it is baked into the framework. It doesn't mean that is better, but if you are doing government work, then they will prefer you use a verified implementation, thus PBKDF2.