47

Possible Duplicate:
Which password hashing method should I use?

There are a ton of great posts about password security in databases on stack overflow and on other sites and as I am completely new to this I spent quite some hours trying to learn more about it in the last days. However, there are so many different suggestions and best practices that I still got very confused...

Also, there are still many older posts from 2007-2010 etc I as I saw how fast things change I am not sure if this is still common to use it like they suggest. So, I wanted to summarize what I found in the posts and then ask if this method I found was a good practice...

So, this is not a guide, but a summary, I know it is very very basic and if there are mistakes please correct me!

  1. Just to mention: you should never store plain text passwords :)
  2. You "one-way" hash passwords, so nobody can ever see the plain text. When the user enters the password, you hash it the same way and compare it with the hashed pass in the database.
  3. In addition to hash a password, you should salt it. You add the salt to the plain password string and hash the new string. If the plain password is weak, adding the salt makes it longer and stronger.
  4. The salt should furthermore be random (I've read that the term "salt" means it is random anyway, otherwise it was called "key"?). This is to prevent rainbow table attacks, because the attacker would need to create one table for each salt which is much more expensive in terms of time etc. Also if two users have the same password you will not recognize it if you use random salts.
  5. The salt is not a secret! It is being stored in the database next to the hashed password. However, it may not be the best idea to use a timestamp, the user's e-mail address or anything else connected to the user as a random salt. As a reason it is e.g. mentioned that users tend to use the same passwords on multiple sites/services. So, the salt should be a random string, I've read best would be 64-bit?
  6. The next step is to add iteration to the hashing process (1000 or more loops), so the salt is added to the password and they are then hashed over and over, which means only a fraction of a second for the user to wait when logging in, but sums up if you have somewhat 10.000 entries in your DB.
  7. It might be a slight benefit, if you add a site key, stored e.g. as a global var in addition to the salt. However, you should always suppose that attackers have access to your file system as well.
  8. Hashing algorithms: I found for sure it is not secure anymore to use MD5, SHA1 and other weak methods...

So, there are different opinions on wether to use SHA256, SHA512? Should you use hash_hmac? Some say yes: (http://rdist.root.org/2009/10/29/stop-using-unsafe-keyed-hashes-use-hmac/) some say using libraries is the only secure way... and then once or twice in a post I've read not to use libraries as bcrypt or bubble fish??

Is it really necessary to use a library or is e.g. a method like this enough:

function hash_password($password, $nonce) {

  for ($i = 0; $i < 5000; $i++) {
    $hashed_pass = hash_hmac('sha512', $hashed_pass . $nonce . $password, $site_key);
    }
  return $hashed_pass;
}

Many people say don't invent your own algo, so I am a little bit scared just to use anything self-invented.

I can imagine it is hard to predict, but how long can a method used to today be considered as being secure enough?

UPDATE: So, thank you for all your great feedback. There is one main point missing, as I see and many of you said: password security, meaning a strong password is the basic. I think I got the message, thank you again! :)

UPDATE 2: Just for completion, I have found following code on http://www.lateralcode.com/creating-a-random-string-with-php/ that I use to generate a random salt:

function rand_string( $length ) {
    $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!§$%&/().-:;_#+*[]{}="; 

    $size = strlen( $chars );
    for( $i = 0; $i < $length; $i++ ) {
        $str .= $chars[ rand( 0, $size - 1 ) ];
    }

    return $str;
}

$random_salt= rand_string(20);
14
  • 2
    One of the better questions I've seen in a while. =)
    – Zeta Two
    Feb 29, 2012 at 9:44
  • As zerkms commented and referred to php.net, I also thought about an iteration of 5000 times... you all say it makes no sense? is it the right way the function is built or what did I do wrong with overwriting the variable in every loop? @zeta two: thank you, I did not expect it...
    – Chris
    Feb 29, 2012 at 9:54
  • so, a user tends to use the same timestamp to register on multiple sites/services? interesting...
    – Col. Shrapnel
    Feb 29, 2012 at 10:04
  • 1
    but as far as I understand the topic is about creating a unique salt that is unique worldwide which is not true if you use a timestamp. And the question is EXACTLY about using timestamp, so I did not get your statement that it was not about timestamps Col. Shrapnel??
    – Chris
    Feb 29, 2012 at 12:36
  • 9
    Caution: This question was migrated from Stackoverflow with many answers of dubious quality that already had a lot of votes -- more than the IT Security community can correct for. As a result, you should not trust the answers here, since the IT Security community is not able to mass enough votes to ensure the quality of the answers. Comment: This question has already been answered in depth several times on IT Security. Please consult those pages, not this one, for good advice.
    – D.W.
    Mar 1, 2012 at 3:26

5 Answers 5

2

General info:

Nice question but all I can say is it totally depends on the usage. If you use it only for a small website, there is a high chance only "script kiddies" will visit you, in that case a simple SHA1 with salt is totally enough today as well. In this case, 5-8-10 years or maybe even more is totally good, script kiddies won't really break into it if they see that they can't break in easily. If your site will be attacked for some reason - monetary site, etc. then you should use the newest available functions. In this case I'd even "risk" to use a non-official but already ported function. Right now there's an SHA3 competition, for websties which'll have high money in it, I'd use one of the 5 competitors of these.

The points I say that are important:

1. use a random salt, perhaps even 20 characters. It makes a lot harder to break passwords, and even if they are breakable, it takes too much time to be worth.
2. use SHA-1, SHA-2 or WHIRLPOOL. With good salt, MD5 is OK as well, but I still suggest these.
3. you can use any great cryptography if users' passwords are trivial. You must make sure they use non-dictionary, long passwords with uppercase, lowercase letters, numbers and symbols else it is easily breakable by brute force. You might consider that they could be forced to change password every year or so.

To the code:

Looping many times could be useful but I don't think 5000 is required. 3 for normal security is good, or 100, maybe 1000 could work, but I think 5000 is just too much. SHA-256 is good, but you could use an algorithm specifically developed for that, see the comments.

19
  • 1
    Chris: not really. Imagine this situation: somehow hacker A breaks into your server, gets to the database and sees your coding. A saves the database to their own server and tries to brute-force password of B. If B's pass is "Benjamin", "78492823", or even "damn16websites", A will break it with simple dictionary attacks. But if it's "60EaD$qőPo", they won't.
    – axiomer
    Feb 29, 2012 at 9:50
  • 1
    Addition to this: they don't even have to break, just have the info that username of B is "whateveritis" and then they'll try to log in with this with many dictionary-based passwords. And they might be successful. You might do that aftern (3? 5? 10?) tries, it won't let people login, but then B will be angry that they cannot login because a hacker has tried to login and leaves your site and goes to a competitor.
    – axiomer
    Feb 29, 2012 at 9:54
  • 1
    ok, you are right axiomer, to some point... probably the username should as well have a minimum length. I just thought if you know the email address from somebody or you have a list of emails or common names you could try [email protected]??
    – Chris
    Feb 29, 2012 at 10:14
  • 7
    downvote from me for general purpose hashing algorithms (SHA family or MD5) for password storage I'd recommend an algorithm specifically designed for the problem (eg, bcrypt, pbkdf2). General purpose hashing algorithms are designed to be "fast", which helps the attacker, password storage hashing algorithms are designed to be "slow" which helps the defender. Feb 29, 2012 at 19:00
  • 5
    -1 for suggesting 2-3 iterations. You want to be slow against brute-force attack. So you should use some algorithm which is slow. For SHA512 I certainly wouldn't use less than 1000 iterations. | It's preferable to use an existing iteration scheme such as PBKDF2, bcrypt or scrypt. Mar 1, 2012 at 14:19
10

You forgot just one little thing:

Password strength.

Just 2 words which overweight whole your brilliant topic.

There are indeed hundreds of topics on Stackoverflow telling you to use this or that hashing algorithm and random salts.
And only very few explaining that with weak password all your eight-item-list protection, all extra secure hmac-chmak-bumblemak hashes with 2048 bytes-long-salt will be broken in a matter seconds.

As for the poor users who can't remember $#%H4df84a$%#R passwords - just make them use not a password but a passphrase.

Is it a good day today, Winkie? Uses different case letters as well as password of recommended complexity but much easier to remember.

Of course the phrase shouldn't be as common as common passwords like "Joe" or "123".
"Good morning", "Oh My God! They Killed Kenny!" phrases should be avoided.
But by adding some personality it would be okay:
Oh My God! They moved Cthulhu! looks quite enough

Another thing to mention is a secure communication between server and browser
Without it, a plain password can be easily "sniffed" out on the any of the routers involved in the communication.

SSH or some implementation of Digest authorization is no less essential.

3
  • +1 for the passphrase, that helps people and improves security.
    – martinstoeckli
    Feb 29, 2012 at 10:42
  • so, the passphrase is being used in addition to the password? I also saw sites, on which you first only enter your username. If this one was correct you see a security image and a security passphrase and need to enter your password... what is the idea behind it?
    – Chris
    Feb 29, 2012 at 10:47
  • 2
    I think Col means, that users tend to use weak passwords, because strong passwords are hard to remember. Then it will be better, if they use a whole phrase as password. You could encourage this, with a tip on your page.
    – martinstoeckli
    Feb 29, 2012 at 10:53
5

A general purpose hash function (MD5, SHA1, SHA256) with a good hash might be secure enough for most smaller web sites, given the current computing power. However, Moore's law will ensure that even good passwords will be exposed to brute force attacks in the near future. The issue is that hash functions can be computed much too quickly. The best solution is to use bcrypt or PBKDF2 with a high number of iterations. Bcrypt vs PBKDF2 was discussed at http://security.stackexchange.com.

Some people might think this is overkill for most sites but remember that passwords are reused all the time and that password storage is usually something you will not change until there is an issue.

Recommendations:

  1. Use bcrypt or PBKDF2. DO NOT USE SHA3 candidates. They might contain security holes that have not been discovered yet.
  2. Use a random salt to help protect against rainbow table attacks.
  3. Force users to select a passphrase.

More information

8
  • what if my salt is not random? wouldn't it protect from rainbow table?
    – Col. Shrapnel
    Feb 29, 2012 at 17:35
  • Its not ideal but much better than not using a salt. Do you mean something like a timestamp or a constant salt?
    – tony
    Feb 29, 2012 at 17:46
  • 1
    Salt ideally should be unique, long, and random, in that order in my opinion.
    – tony
    Feb 29, 2012 at 17:57
  • @tony so you recommend only using crypt or pbkdf2 is secure enough? The article you linked is very good, however, also hmac function is mentioned to be more secure than a simple hash. Secure enough? If you add iterations it is not yet slow enough? I've seen the wikipedia article about brute force attacks (en.wikipedia.org/wiki/Brute_force_attack), which mentions calculation times... what is your opinion on this? And: what is the difference for you between a unique and a random salt?
    – Chris
    Feb 29, 2012 at 18:57
  • +1 for bcrypt, although IIRC in most implementations, it sorts out the salt for you so you don't need to generate/store it yourself. stackoverflow.com/questions/6832445/… has a good description Feb 29, 2012 at 18:57
2

The hash_hmac() function would be a good choice, it can even overcome problems of a weaker hash algorithm. The only problem is, that it is too fast. That means with enough cpu-power (cloud), creation of different rainbow tables becomes possible, that's the reason for iterating. If you need this high security, then you can measure the time your iterations need, and then calculate the number of iterations needed for a given time.

Edit:

Iterating can solve this problem, it should be done in a way, that one can increase the number of iterations later, without making existing hashes invalid. This is necessary to adapt to new future hardware, but requires to store the hashing parameters together with the hash.

The bcrypt hash algorithm was designed to meet this demands, i wrote a small example of how to use bcrypt with PHP 5.3, i tried to comment it, so one can understand what's going on.

1
  • thanks for the info... and yes, this would be interesting if iteration is helpful, as there seem to be different opinions on it...
    – Chris
    Feb 29, 2012 at 11:47
-1

Well first of all, you are not inventing an own algorithm. You are using an existing one (sha512).

Secondly, you loop 5000 times, that will not do you any good. Only a couple of times will be sufficient.

Thirdly, if you are storing a password with sha512, and add a good seed, it is really really hard to get the password back. And unless you are with FBI or something, it should be considered safe enough as it will take ages to decrypt 1 password, let alone your entire user database.

10
  • Oh, OK... thanks Topender! So, what would be a better way not to overwrite the same variable then? Sorry, if this is a trivial question...
    – Chris
    Feb 29, 2012 at 9:33
  • 2
    "Secondly, you loop 5000 times, but you are overwriting the same variable, that will not do you any good." --- it will. It makes the computation slower
    – zerkms
    Feb 29, 2012 at 9:35
  • why do you loop in the first place?
    – Topener
    Feb 29, 2012 at 9:35
  • well, looping is being considered as strengthening, isn't it this term?
    – Chris
    Feb 29, 2012 at 9:36
  • 5
    @Topener: because it slows its computation. The slower the computation - the more difficult to brute force
    – zerkms
    Feb 29, 2012 at 9:37

Not the answer you're looking for? Browse other questions tagged .