

Creating and Verifying Hashes in PHP 5.5 - Jeremy1026
http://www.jcurcio.com/posts/creating-and-verifying-hashes-in-php-the-easy-way/

======
bpatrianakos
This is a great addition to PHP. Before, most new devs would either skip
hashing passwords altogether or use `md5()` or `sha1()`. So you'd end up with
databases with passwords in plaintext or easily cracked. Bcrypt frameworks for
PHP were too confusing for beginners. If you were lucky you were using a
framework that took care of hashing and salting passwords and if you were
extremely lucky you had bcrypt available on your PHP install and that
framework used it.

But that didn't always happen. There do exist experienced PHP devs who would
do password storage the right way but PHP up until now neither made it easy
nor encourage these practices as they relate to passwords. Now I hope word
gets out about this and people stop using md5() thinking their passwords are
safe. Not that md5 is necessarily bad, but most people don't realize there are
better tools for maintaining secure passwords.

Also, this reminds me a little bit of `has_secure_password` method in Rails
minus some of the automation that comes with it.

~~~
maratd
> There do exist experienced PHP devs who would do password storage the right
> way but PHP up until now neither made it easy nor encourage these practices
> as they relate to passwords.

As much as I welcome these features, I don't think that's true. PHP has made
it extremely easy to use the core operating system's hashing features.

[http://us3.php.net/manual/en/function.crypt.php](http://us3.php.net/manual/en/function.crypt.php)

And after 5.3, even if for whatever reason your operating system is lacking,
they were built in for convenience.

~~~
nikic
crypt() is not extremely easy to use. Actually, it's fairly hard and easy to
get wrong. The two things that people usually get wrong is a) salt generation
and b) fixed-time comparison.

------
masklinn
> 'salt' => password_hash("MySalt",PASSWORD_BCRYPT)]

This is really, really dumb and pointless. In fact it makes absolutely no
sense, it tells password_hash to use a bcrypted "MySalt" as a salt.

Not only is there no reason to explicitly provide a salt _unless_ you already
have bcrypted passwords in a non-standard format, (in which case you'd pass
the existing $salt directly, you wouldn't bcrypt it) this is an inane way to
generate one.

If you want to generate your salt by hand, don't do it. If you really, really,
really want to, use mcrypt_create_iv.

~~~
bpatrianakos
Adding that salt is optional. I'm pretty sure the author just added it to the
post so people know it exists.

I don't think it's dumb and pointless at all, really. Generally you wouldn't
generate a salt yourself if you're using bcrypt however I'm sure there would
be cases where it would be needed or even preferred for some reason. I would
advocate for flexibility and education rather than rigidity and simplicity.
That is to say, rather than make the function useless to those who'd need
their own salt I think it's a better idea to allow these options while making
sure developers know that they should only be used in certain situations. A
function like this isn't bad because it can be misused.

~~~
masklinn
> Adding that salt is optional. I'm pretty sure the author just added it to
> the post so people know it exists.

I have nothing against adding a salt manually to show how it works, I have
things against adding stupid salts.

> I don't think it's dumb and pointless at all, really.

You're missing the criticism. The problem isn't the ability to inject a salt
(it is useful e.g. when the (cost, salt, hash) triple is in a format other
than MCF), it is the way the salt is obtained.

------
chrisguitarguy
There's also a library for PHP >= 5.3.7 that provides the same API if PHP 5.5
isn't an option yet.

[https://github.com/ircmaxell/password_compat](https://github.com/ircmaxell/password_compat)

Written by Anthony Ferrara, the same guy behind the `password_*` API in PHP
5.5

~~~
fein
There's also PHPass from OpenWall:

[http://www.openwall.com/phpass/](http://www.openwall.com/phpass/)

~~~
kijin
If you use PHPass, remember to check your hashes to make sure they're actually
hashed with bcrypt. PHPass falls back to a less secure algorithm if bcrypt is
not available in your PHP version. Most of the CMS's that claim to use PHPass
actually use the "portable" option, which is based on MD5, because they want
to remain compatible with PHP versions lower than 5.3 (the first version that
is guaranteed to support bcrypt).

~~~
chrisguitarguy
> Most of the CMS's that claim to use PHPass actually use the "portable"
> option

This is true for WordPress, which uses PHPass. You have to replace
`wp_hash_password` to get WP to use bcrypt: [http://wptip.me/wordpress-
bcrypt](http://wptip.me/wordpress-bcrypt)

------
pmtarantino
If you are using a PHP < 5.5, use this library:
[https://github.com/ircmaxell/password_compat](https://github.com/ircmaxell/password_compat)

------
cryptbe
If the password hashing APIs asks developers to generate a salt on their own
it's neither easy nor safe.

I've worked on password hashing recently, and I think the best interfaces
should take only a password, and return a hash. Modern password hashing
algorithms, e.g., bcrypt, scrypt, etc., usually also need a set of local
parameters. The API should hide them as well, and expose only a set of
interfaces with safe and sound preconfigured parameters, which in turn
determine how much CPU time and memory space will be used. One disadvantage of
this approach is that it exposes the local parameters, hence make it a little
bit easier for attackers.

This is exactly how crypto primitives have been designed. If the designers of
AES ever let people choose the key size, sooner or later some people would
shoot themselves in the foot, and set the key size to 1-bit. If you think this
is an extreme example, it actually has happened, not in some obscure API that
nobody uses, but in the very XMLDsig standard published by W3C [1].

Regarding password hashing standards, I found many misuses of libscrypt that
would make it extremely easy to recover passwords. But I'll save the details
for another blog post or something.

[1]
[http://www.w3.org/QA/2009/07/hmac_truncation_in_xml_signatu....](http://www.w3.org/QA/2009/07/hmac_truncation_in_xml_signatu.html)

------
chunsaker
This is an awesome improvement. I agree with BPatrianakos that hashing has not
been easy enough for the average PHP dev - we hear that a lot.

As another option, you can also just not build any password infrastructure. We
do all the hashing and authorization as a secure service and there are PHP
devs of all levels using it...
[http://www.stormpath.com/docs/php/quickstart](http://www.stormpath.com/docs/php/quickstart)

------
showerst
Just noting if you're new to this you don't have to add a salt, by default
password_hash with bcrypt will add a random one to each password.

~~~
nly
Assuming the RNG isn't duff, which PHP has stumbled on a few times in the
past, with session keys and such.

~~~
ircmaxell
Check it out for yourself. Here's the random generating parts, pulled out for
you: [http://stackoverflow.com/questions/14673005/how-does-phps-
pa...](http://stackoverflow.com/questions/14673005/how-does-phps-password-
hash-generate-the-salt)

------
baby
Can someone explain to me what the "cost" option is?

~~~
cabirum
Increasing cost by 1 doubles the time needed to create a hash.

A simple benchmark with results:
[http://pastebin.com/NiqKEAVm](http://pastebin.com/NiqKEAVm)

------
workhere-io
It certainly makes handling passwords easier. Another option, though, would be
to use Persona, in which case you don't store passwords at all.

------
jimwalsh
Thanks for easily explaining this for everyone.

