4

Starting note: After going through some articles and answers posted on SO related to storing secured passwords I'm still not sure whether my way of thinking is applicable to todays reality.

I'm currently thinking of a way to provide a secure structure for storing and retrieving passwords needed for authentication of a user on a webpage. While browsing the net and digging through pages of answers I've found myself stuck at some point. First of all, time goes on and not every article/answer is up to date. Secondly, there are many ambiguities as of what actually should be done.

I'm using PHP5 and Postgres database. While being aware of existance of pg_crypto module to me it seems like doing those computations on database level does not seem secure due to logging and passing plain password to database query.

So I decided to get the job done in application code (PHP). Since PHP5 there is a native password hashing API providing functions like password_hash() and password_verify().

What I'm asking for is advice whether or not I'm on the right track or any improvements that could be done supported by strong security-related arguments (please refrain from advising on iterating milion times). Also, is this possible using PHP5 or am I missing any theoretical knowledge as well (considering my way of thinking for this process).

My way of thinking for this process is to:

  1. Get the password from user
  2. Apply a randomly generated salt for each user (preferably constant length for every salt), that is independent of any data stored in database
  3. Store that salt in table where users and their hashed passwords are going to be
  4. "Hashinng"
    • Hash the salt concatenated with password using SHA512 algorithm
    • password_hash with bcrypt
  5. Store hash in db

So as you can see my main consideration is whether to use SHA-512 or bcrypto, but I feel like I lack the capacity in this field and thus am asking for general advices to my entire process.

Particularly my attention to which "hashing" process to use was brought by erickson's answer on comparing SHA vs Bcrypt. I'm aware of SHA3 existance, but doesn't that prove there were things that should be improved as compared with SHA2 family (this is a question of type for now)?

What I've read already:

Non-random salt for password hashes

SHA512 vs. Blowfish and Bcrypt

Secure hash and salt for PHP passwords

Passwords storage, hash() with sha-512 or crypt() with blowfish (bcrypt)?

PHP Reference Manual - FAQ - Passwords

  • 2
    Welcome to [security.se]. Is there anything in your question that is not answered by [How to securely hash passwords?](http://security.stackexchange.com/q/211/33)? – AviD Apr 15 '15 at 13:18
  • @AviD thank you for your kind respond. The answer you mention definitely is a solid source of information, though it lacks references to `PHP5` I need. – Kamil Gosciminski Apr 15 '15 at 14:54
  • Right, but I'm trying to figure out what part of your question is actually PHP-specific. Could you perhaps focus your question accordingly? – AviD Apr 15 '15 at 15:04
  • I feel like everything that's following paragraph after `What I'm asking for` is relevant. I'm asking for opinion about my process and viability of it using PHP "best practice". I already got an answer - if you still think that I should rephrase anything, let me know. – Kamil Gosciminski Apr 16 '15 at 07:19
  • Thanks ConsiderMe. But most of that, especially the process etc, is not PHP specific, and already well answered elsewhere. So are you asking specifically about this particular set of functions, or which method to use? Or something else? – AviD Apr 16 '15 at 07:38

1 Answers1

4

I think many of your questions (eg SHA-512 vs bcrypt) are answered in the guide linked to by AviD. But it doesn't actually say anything about PHP, so I'll answer that part.

Hashing a Password in PHP5

It's good that you want to understand the underlying concepts, but actually securely hashing a password in PHP5 is quite easy:

$hashedPassword = password_hash($plainPassword, PASSWORD_DEFAULT);

That's it. Store it in the database, use password_verify to compare, and you're done. password_hash will create a per-user salt for you, so you don't need your step 2 or 3[*]. You also don't need the first part of your step 4 (it's enough to hash once).

The result of this will be of the form $hashFunctionId$options$saltHash. The hashFunctionId and options (the cost) are used to store information on how the hash was created.

[*] I can see why it's confusing though, because so many guides explicitly mention the important of per-user salts, so it might seem odd that PHP actually does the work for you

password_hash options

So what is the use of the other options of password_hash if hashing is that simple?

PASSWORD_DEFAULT means that currently bcrypt will be used, but if there are better methods in the future, those will be used. If for some reason you do want control over this, replace it with PASSWORD_BCRYPT.

You can pass a salt which replaces the auto-generation of a salt. This is useful if you want to get the same output when hashing the same password, or if you want to include a pepper.

And you can pass a cost, if you think that the default cost of 10 is not enough for you.

tim
  • 29,018
  • 7
  • 95
  • 119
  • Thank you for your answer. Do you happen to know of what length is the automatically generated salt? And which bytes are representing this salt in a string stored in database? I've checked http://php.net/manual/en/function.password-hash.php but it seems to lack information about this. Also, how does it internally work? Does it apply the salt, then feeds it into bcrypt and then append the salt once again to create the `$saltHash` you're reffering to in form `$hashFunctionId$options$saltHash`? I guess this is how it's going to be stored in database, right? – Kamil Gosciminski Apr 15 '15 at 14:51
  • @ConsiderMe The default salt is 22 characters long. The documentation of `password_hash` is indeed unclear about how to differentiate between salt and hash (what I called `$saltHash`, by which I meant the salt, appended by the hash). You can read about it in articles about bcrypt though (see eg [here](https://stackoverflow.com/questions/5881169); the hash is a constant length). And yes, the whole `$hashFunctionId$options$saltHash` will be stored in the database (all of it is needed to hash and compare a password the same way the original password was hashed). – tim Apr 15 '15 at 15:29