Disclaimer: there are many similar questions on SO, but I am looking for a practical suggestion instead of just general principles. Also, feel free to point out implementations of the "ideal" algorithm (PHP would be nice ;), but please provide specifics (how it works).
What is the best way to calculate hash string of a password for storing in a database? I know I should:
use salt
iterate hashing process multiple times (hash chaining for key stretching)
I was thinking of using such algorithm:
x = md5( salt + password);
repeat N-times:
x = md5( salt + password + x );
I am sure this is quite safe, but there are a few questions that come to mind:
would it be beneficial to include username in salt?
I have decided to use a common salt for all users, any downside in this?
what is the recommended minimum salt length, if any?
should I use md5, sha or something else?
is there anything wrong with the above algorithm / any suggestions?
... (feel free to provide more :)
I know the decisions necessarily depend on the situation, but I am looking for a solution that would:
provide as much security as possible
be fast enough ( < 0.5 second on a decent machine )
So, what would the ideal algorithm look like, preferably in pseudo-code?
The "ideal" password hashing function, right now, is bcrypt. It includes salt processing and a configurable number of iterations. There is a free opensource PHP implementation.
Second best would be PBKDF2, which relies on an underlying hash function and is somewhat similar to what you suggest. There are technical reasons why bcrypt is "better" than PBKDF2.
As for your specific questions:
1. would it be beneficial to include username in salt?
Not really.
2. I have decided to use a common salt for all users, any downside in this?
Yes: it removes the benefits of having a salt. The salt sole reason to exist is to be unique for each hashed password. This prevents an attacker from attacking two hashed passwords with less effort than twice that of attacking one hashed password. Salts must be unique. Even having a per-user salt is bad: the salt must also be changed when a user changes his password. The kind of optimization that an attacker may apply when a salt is reused / shared includes (but is not limited to) tables of precomputed hashes, such as rainbow tables.
3. what is the recommended minimum salt length, if any?
A salt must be unique. Uniqueness is a hard property to maintain. But by using long enough random salts (generated with a good random number generator, preferably a cryptographically strong one), you get uniqueness with a high enough probability. 128-bit salts are long enough.
4. should I use md5, sha or something else?
MD5 is bad for public relations. It has known weaknesses, which may or may not apply to a given usage, and it is very hard to "prove" with any kind of reliability that these weaknesses do not apply to a specific situation. SHA-1 is better, but not "good", because it also has weaknesses, albeit much less serious ones than MD5's. SHA-256 is a reasonable choice. As was pointed out above, for password hashing, you want a function which does not scale well on parallel architectures such as GPU, and SHA-256 scales well, which is why the Blowfish-derivative used in bcrypt is preferable.
5. is there anything wrong with the above algorithm / any suggestions?
It is homemade. That's bad. The trouble is that there is no known test for security of a cryptographic algorithm. The best we can hope for is to let a few hundreds professional cryptographer try to break an algorithm for a few years -- if they cannot, then we can say that although the algorithm is not really "proven" to be secure, at least weaknesses must not be obvious. Bcrypt has been around, widely deployed, and analyzed for 12 years. You cannot beat that by yourself, even with the help of StackOverflow.
As a professional cryptographer myself, I would raise a suspicious eyebrow at the use of simple concatenation in MD5 or even SHA-256: these are Merkle–Damgård hash functions, which is fine for collision resistance but does not provide a random oracle (there is the so-called "length extension attack"). In PBKDF2, the hash function is not used directly, but through HMAC.
I tend to use a fixed application salt, the username and the password
Example...
string prehash = "mysaltvalue" + "myusername" + "mypassword";
The benefit here is that people using the same password don't end up with the same hash value, and it prevents people with access to the database copying their password over another users - of course, if you can access the DB you don't really need to hack a login to get the data ;)
IMO, salt length doesn't matter too much, the hashed value length is always going to be 32 anyway (using MD5 - which again is what I would use)
I would say in terms of security, this password encryption is enough, the most important thing is to make sure your application/database has no security leaks in it!
Also, I wouldn't bother with repeated hashing, no point in my opinion. Somebody would have to know you algorithm to try to hack it that way and then it doesn't matter if it is hashed once or many times, if they know it, they know it
Related
I am working on a project that has to store users passwords. With that password you can gain access to a user achievements and stuff so it's really important that you can not get the password even if you hacked into the database. My problem is which hashing function to choose in security and efficiency level.
Right now I am using sha256 with salt and pepper but I read that using a slow hashing function like Bcrypt with cost factor of 12 can be superior. And if it does, how much more security do I gain from using a pepper as well because it's really time consuming for hash function like Bcrypt.
My question is what hash function should I use base on the assumption that I do not expect to get hacked by a global hacking organization with supercomputers?
Plain crypto hash functions like sha2 or sha3 don't cut it anymore for password hashing, because it's too efficient to compute them, which means an attacker that controls many cpu cores can compute large tables relatively quickly. In practice the feasibility of this still depends on the length of passwords mostly (and the character set used in those password to some extent), but you should still not use these unless you really know why that will be acceptable.
Instead, you should be using a hash or key derivation function more suitable for password hashing. Pbkdf2, bcrypt, scrypt and Argon2 are all acceptable candidates, with somewhat different strengths and weaknesses. For a regular web app, it almost doesn't matter which of these you choose, and all will be more secure than plain hashes.
The difference will be very real if your database is compromised, properly hashed passwords will likely not be revealed, while at least some passwords with sha likely will, despite salt and pepper.
Let's say we don't use password_hash and use crypt() with sha512 instead to hash passwords. We need to add salt to the password, so an attacker couldn't use a rainbow table attack. Why the salt has to be good and very random as stated in many SO answers? Even if salt differs by a little or not very random, it will still give a totally different hash from others. So, an attacker won't know who uses the same passwords and he still won't be able to create just one rainbow table.
Computing and storing a strong salt requires minimal effort yet reduces the chances of a rainbow table having being pre-computed with the salt astronomically small.
If the salt was a 3 digit number it would be feasible that an attacker could have pre-computed rainbow tables for all possible salt combinations. If the salt is a random 24 character alpha-numeric string then the chances an attacker could pre-compute this for all possible salts are practically zero.
A salt is supposed to be unique, must be long enough, and should be unpredictable. Randomness is not necessary, but it is the easiest way for a computer to meet those requirements. And it is not the purpose of a salt to be secret, a salt fulfills its purpose even when known.
Uniqueness means that it should not only be unique in your database (otherwise you could use a userid), it should be unique worldwide. Somebody could create rainbowtables for salts like e.g. 1-1000 and would be able to retrieve passwords for all accounts with those userids (often admin accounts have low userids).
Long enough: If the salt is too short (too few possible combinations), it becomes profitable again to build rainbow-tables. Salt and password together can then be seen as just a longer password, and if you can build a rainbow-table for this longer passwords, you also get the shorter original passwords. For very strong and long passwords, salting would actually not be necessary at all, but most human generated passwords can be brute-forced because they are short (people have to remember them).
Also using salts derrived from other parameters can fall into this category. Only because you calculate a hash from the userid, this doesn't increase the possible combinations.
Unpredictability is a bit less important, but imagine once more the case that you use the userid as salt, an attacker can find out what the next few userids will be, and can therefore precalculate a narrow number of rainbow-tables. Depending of the used hash-algorithm this can be applicable or not. He has a time advantage then, can retrieve the password immediately. More of a problem will be, if the admin accounts used a predictable salt.
So using a really random number, generated from the OS random source (dev/urandom), is the best you can do. Even when you ignore all reasons above, why should you use a derived salt when there is a better way, why not use the best way you know?
Hearing about all the recent hacks at big tech firms, it made me wonder their use of password storage.
I know salting + hashing is accepted as being generally secure but ever example I've seen of salting has the salt key hard-coded into the password script which is generally stored on the same server.
So is it a logical solution to hash the user's password initially, pass that hash to a "salting server" or some function stored off-site, then pass back the salted hash?
The way I I'm looking at it is, if an intruder gains access to the server or database containing the stored passwords, they won't immediately have access to the salt key.
No -- salt remains effective even if known to the attacker.
The idea of salt is that it makes a dictionary attack on a large number of users more difficult. Without salt, the attacker hashes all the words in a dictionary, and sees which match with your users' hashed paswords. With salt, he has to hash each word in the dictionary many times over (once for each possible hash value) to be certain of having one that fits each user.
This multiplication by several thousand (or possibly several million, depending on how large a salt you use) increases the time to hash all the values, and the storage need to store the results -- the point that (you hope) it's impractical.
I should add, however, that in many (most?) cases, a very large salt doesn't really add a lot of security. The problem is that if you use, say, a 24 bit salt (~16 million possible values) but have only, say, a few hundred users, the attacker can collect the salt values you're actually using ahead of time, then do his dictionary attack for only those values instead of the full ~16 million potential values. In short, your 24-bit salt adds only a tiny bit of difficulty beyond what a ~8 bit salt would have provided.
OTOH, for a large server (Google, Facebook, etc.) the story is entirely different -- a large salt becomes quite beneficial.
Salting is useful even if intruder knows the salt.
If passwords are NOT salted, it makes possible to use widely available precomputed rainbow tables to quickly attack your passwords.
If your password table was salted, it makes it very difficult to precompute rainbow tables - it is impractical to create rainbow table for every possible salt.
If you use random salt that is different for every password entry, and put it in plaintext right next to it, it makes very difficult for intruder to attack your passwords, short of brute force attack.
Salting passwords protects passwords against attacks where the attacker has a list of hashed passwords. There are some common hashing algorithms that hackers have tables for that allow them to look up a hash and retrieve the password. For this to work, the hacker has to have broken into the password storage and stolen the hashes.
If the passwords are salted, then the attacker must re-generate their hash tables, using the hashing algorithm and the salt. Depending on the hashing algorithm, this can take some time. To speed things up, hackers also use lists of the most common passwords and dictionary words. The idea of the salt is to slow an attacker down.
The best approach to use a different salt for each password, make it long and random, and it's ok to store the salt next to each password. This really slows an attacker down, because they would have to run their hash table generation for each individual password, for every combination of common passwords and dictionary words. This would make it implausible for an attacker to deduce strong passwords.
I had read a good article on this, which I can't find now. But Googling 'password salt' gives some good results. Have a look at this article.
I would like to point out, that the scheme you described with the hard-coded salt, is actually not a salt, instead it works like a key or a pepper. Salt and pepper solve different problems.
A salt should be generated randomly for every password, and can be stored together with the hashed password in the database. It can be stored plain text, and fullfills it's purpose even when known to the attacker.
A pepper is a secret key, that will be used for all passwords. It will not be stored in the database, instead it should be deposited in a safe place. If the pepper is known to the attacker, it becomes useless.
I tried to explain the differences in a small tutorial, maybe you want to have a look there.
Makes sense. Seems like more effort than worth (unless its a site of significant worth or importance) for an attacker.
all sites small or large, important or not, should take password hashing as high importance
as long as each hash has its own large random salt then yes it does become mostly impracticable, if each hash uses an static salt you can use Rainbow tables to weed out the users hashs who used password1 for example
using an good hashing algorithm is also important as well (using MD5 or SHA1 is nearly like using plaintext with the mutli gpu setups these days) use scrypt if not then bcrypt or if you have to use PBKDF2 then (you need the rounds to be very high)
I am currently using SHA256 with a salt to hash my passwords. Is it better to continue using SHA256 or should I change to SHA512?
Switching to SHA512 will hardly make your website more secure. You should not write your own password hashing function. Instead, use an existing implementation.
SHA256 and SHA512 are message digests, they were never meant to be password-hashing (or key-derivation) functions. (Although a message digest could be used a building block for a KDF, such as in PBKDF2 with HMAC-SHA256.)
A password-hashing function should defend against dictionary attacks and rainbow tables. In order to defend against dictionary attacks, a password hashing scheme must include a work factor to make it as slow as is workable.
Currently, the best choice is probably Argon2. This family of password hashing functions won the Password Hashing Competition in 2015.
If Argon2 is not available, the only other standardized password-hashing or key-derivation function is PBKDF2, which is an oldish NIST standard. Other choices, if using a standard is not required, include bcrypt and scrypt.
Wikipedia has pages for these functions:
https://en.wikipedia.org/wiki/Argon2
https://en.wikipedia.org/wiki/Bcrypt
https://en.wikipedia.org/wiki/Scrypt
https://en.wikipedia.org/wiki/PBKDF2
EDIT: NIST does not recommend using message digests such as SHA2 or SHA3 directly to hash passwords! Here is what NIST recommends:
Memorized secrets SHALL be salted and hashed using a suitable one-way
key derivation function. Key derivation functions take a password, a
salt, and a cost factor as inputs then generate a password hash. Their
purpose is to make each password guessing trial by an attacker who has
obtained a password hash file expensive and therefore the cost of a
guessing attack high or prohibitive. Examples of suitable key
derivation functions include Password-based Key Derivation Function 2
(PBKDF2) [SP 800-132] and Balloon [BALLOON].
SHA256 is still NIST Approved, but it would be good to change to SHA512, or bcrypt, if you can.
The list of NIST approved hash functions, at time of writing, is: SHA-1, SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, SHA-512/256, and SHA3-224, SHA3-256, SHA3-384, and SHA3-512, SHAKE128 and SHAKE256.
See https://csrc.nist.gov/projects/hash-functions
Depending on what operating system you are running, you probably don't have access to the SHA3 or SHAKE hash functions.
Many people prefer bcrypt to SHA512, but bcrypt is also only available on some operating systems.
SHA512 will be available on your system, or if not, you probably have such an old system that choice of hashing algorithm is the least of your problems.
One reason commonly given for preferring bcrypt is that bcrypt is tuneable - you can increase the number of rounds (work factor) to increase the time it takes to crack bcrypt hashes.
But SHA256 and SHA512 are also tuneable. While the default is 5000 rounds, you can specify more if you wish. 500000 takes my current pc about 0.45 seconds to calculate, which feels tolerable.
e.g.:
password required pam_unix.so sha512 shadow rounds=500000 ...
The reason to change from SHA256 to SHA512 is that SHA256 needs a lot more rounds to be as secure as SHA512, so while it's not insecure, it's less secure.
See, for example: https://medium.com/#davidtstrauss/stop-using-sha-256-6adbb55c608
Crypto changes quickly, so any answer you get might be proved wrong tomorrow, but current state of the art is that while bcrypt is possibly better than SHA512, SHA512 is fine.
If SHA512 is what you have available 'out of the box', use it (not SHA256), and don't worry about bcrypt or any of the SHA3 family until they become standard for your distribution.
As an aside, the current top rated answer has a number of claims that are either wrong or misleading.
"Switching to SHA512 will hardly make your website more secure."
This is misleading. Switching to SHA512 will make your site slightly more secure. SHA256 isn't as good as SHA512, but it isn't dreadful either. There's nothing that is clearly better than SHA512 that is likely to be available on your system yet. Bcrypt might be better, but this isn't clear, and bcrypt isn't available on a lot of systems. The SHA3 family is probably better, but it isn't widely available either.
"SHA256 and SHA512 were never meant to be password-hashing"
This is wrong. Both SHA256 and SHA512 are approved NIST hash algorithms.
"to defend against dictionary attacks, a password hashing scheme must include a work factor to make it as slow as is workable."
This is wrong. A high work factor will protect against brute force hash cracking, but not against a dictionary attack. There is no work factor that is low enough to be usable but high enough to protect against a dictionary attack. If your password is a dictionary word, it will fall to a dictionary attack. The protection against a dictionary attack to not use passwords that can be found in dictionaries.
On my current PC, the limit on rounds seems to be 10 million, which produces a delay of 8.74 seconds for each password entered. That's long enough to be extremely painful, longer than you'd want to use. It's long enough to prevent a brute force attack - but a determined adversary with a good cracking rig and a bit of patience could still iterate through a dictionary if they wanted to.
"A password-hashing function should defend against ... rainbow tables"
This is, at best, misleading. The defence against rainbow tables is to make sure that each password has their own 'salt'. That's pretty much standard practice these days, and it happens before the hash function is called. (Salting means adding a random string to the password before hashing it. The salt is stored with the password, so it's not a secret, but it does mean that even if a user picks a well-known password, the attacker can't just recognise that {this hash} belongs to {that password}, they still need to crack the hash.)
"Currently, the best choice is probably Argon2. This family of password hashing functions won the Password Hashing Competition in 2015."
This is unclear. Any 'new' cryptographic function can have unobvious ways of being broken, which is why most people prefer functions that have been widely used. Besides which, Argon2 is probably not available to you.
"Other choices, if using a standard is not required, include bcrypt and scrypt."
This is unclear. At one point, scrypt was seen as a better bcrypt. However, for various reasons, sentiment has moved away from scrypt towards bcrypt. See, for example: https://blog.ircmaxell.com/2014/03/why-i-dont-recommend-scrypt.html
To repeat, at this point in time, SHA512 appears to be a good choice and so does bcrypt.
SHA512 is NIST approved and bcrypt is not.
SHA512 will almost certainly be available on your system. Bcrypt may or may not be.
If both are on your system, I'd probably recommend bcrypt, but it's a close call. Either is fine.
This has already been answered reasonably well, if you ask me: https://stackoverflow.com/questions/3897434/password-security-sha1-sha256-or-sha512
Jeff had an interesting post on hashing, too: http://www.codinghorror.com/blog/2012/04/speed-hashing.html
Note that SHA512 is a lot slower to compute than SHA256. In the context of secure hashing, this is an asset. Slower to compute hashes mean it takes more compute time to crack, so if you can afford the compute cost SHA512 will be more secure for this reason.
SHA512 may be significantly faster when calculated on most 64-bit processors as SHA256ses 32-bit math, an operation that is often slightly slower.
Outside of the really good and more practical/accurate answers regarding passwords, I have another perspective (one that I think is complementary to the others).
We use tools and companies to perform vulnerability assessments. One red flag we've had in code is use of MD5. This was not anything related to passwords... it was simply to generate a digest for a string. MD5 is nice and short, and really not a security issue for this specific scenario.
The problem is, it takes time to configure scanners to ignore these false-positives. And it is much more difficult to modify a security report written by an external vendor, in order to change the "high risk" finding to "low risk" or removed.
So my view is, why not use a better algorithm? In my case, I'm starting to use SHA512 in place of MD5. The length is a bit obscene compared to MD5, but for me it doesn't matter. Obviously, one's own performance needs in either calculation or storage would need to be considered.
As an aside for my situation, switching from MD5 to SHA256 would probably also be okay and not raise any red flags... but that leads me to my "why not use a better algorithm" comment.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
I've always been curious... Which is better when salting a password for hashing: prefix, or postfix? Why? Or does it matter, so long as you salt?
To explain: We all (hopefully) know by now that we should salt a password before we hash it for storage in the database [Edit: So you can avoid things like what happened to Jeff Atwood recently]. Typically this is done by concatenating the salt with the password before passing it through the hashing algorithm. But the examples vary... Some examples prepend the salt before the password. Some examples add the salt after the password. I've even seen some that try to put the salt in the middle.
So which is the better method, and why? Is there a method that decreases the chance of a hash collision? My Googling hasn't turned up a decent analysis on the subject.
Edit: Great answers folks! I'm sorry I could only pick one answer. :)
Prefix or suffix is irrelevant, it's only about adding some entropy and length to the password.
You should consider those three things:
The salt has to be different for every password you store. (This is quite a common misunderstanding.)
Use a cryptographically secure random number generator.
Choose a long enough salt. Think about the birthday problem.
There's an excellent answer by Dave Sherohman to another question why you should use randomly generated salts instead of a user's name (or other personal data). If you follow those suggestions, it really doesn't matter where you put your salt in.
I think it's all semantics. Putting it before or after doesn't matter except against a very specific threat model.
The fact that it's there is supposed to defeat rainbow tables.
The threat model I alluded to would be the scenario where the adversary can have rainbow tables of common salts appended/prepended to the password. (Say the NSA) You're guessing they either have it appended or prepended but not both. That's silly, and it's a poor guess.
It'd be better to assume that they have the capacity to store these rainbow tables, but not, say, tables with strange salts interspersed in the middle of the password. In that narrow case, I would conjecture that interspersed would be best.
Like I said. It's semantics. Pick a different salt per password, a long salt, and include odd characters in it like symbols and ASCII codes: ©¤¡
The real answer, which nobody seems to have touched upon, is that both are wrong. If you are implementing your own crypto, no matter how trivial a part you think you're doing, you are going to make mistakes.
HMAC is a better approach, but even then if you're using something like SHA-1, you've already picked an algorithm which is unsuitable for password hashing due to its design for speed. Use something like bcrypt or possibly scrypt and take the problem out of your hands entirely.
Oh, and don't even think about comparing the resulting hashes for equality with with your programming language or database string comparison utilities. Those compare character by character and short-circuit as false if a character differs. So now attackers can use statistical methods to try and work out what the hash is, a character at a time.
It shouldn't make any difference. The hash will be no more easily guessable wherever you put the salt. Hash collisions are both rare and unpredictable, by virtue of being intentionally non-linear. If it made a difference to the security, that would suggest a problem with the hashing, not the salting.
If using a cryptographically secure hash, it shouldn't matter whether you pre- or postfix; a point of hashing is that a single bit change in the source data (no matter where) should produce a different hash.
What is important, though, is using long salts, generating them with a proper cryptographic PRNG, and having per-user salts. Storing the per-user salts in your database is not a security issue, using a site-wide hash is.
First of all, the term "rainbow table" is consistently misused. A "rainbow" table is just a particular kind of lookup table, one that allows a particular kind of data compression on the keys. By trading computation for space, a lookup table that would take 1000 TB can be compressed a thousand times so that it can be stored on a smaller drive drive.
You should be worried about hash to password lookup tables, rainbow or otherwise.
#onebyone.livejournal.com:
The attacker has 'rainbow tables' consisting not of the hashes of dictionary words, but of the state of the hash computation just before finalising the hash calculation.
It could then be cheaper to brute-force a password file entry with postfix salt than prefix salt: for each dictionary word in turn you would load the state, add the salt bytes into the hash, and then finalise it. With prefixed salt there would be nothing in common between the calculations for each dictionary word.
For a simple hash function that scans linearly through the input string, such as a simple linear congruential generator, this is a practical attack. But a cryptographically secure hash function is deliberately designed to have multiple rounds, each of which uses all the bits of the input string, so that computing the internal state just prior to the addition of the salt is not meaningful after the first round. For example, SHA-1 has 80 rounds.
Moreover password hashing algorithms like PBKDF compose their hash function multiple times (it is recommended to iterate PBKDF-2 a minimum of 1000 times, each iteration applying SHA-1 twice) making this attack doubly impractical.
BCrypt hash if the platform has a provider. I love how you don't worry about creating the salts and you can make them even stronger if you want.
Inserting the salt an arbitrary number of characters into the password is the least expected case, and therefore the most "secure" socially, but it's really not very significant in the general case as long as you're using long, unique-per-password strings for salts.