I am using password_hash
for password encryption. However there is a strange question, password_hash
cost very long time. Here is a sample code.
this code will cost more than 1 second. Is that normal?
<?php
$startTime = microtime(TRUE);
$password='123456';
$cost=13;
$hash=password_hash($password, PASSWORD_DEFAULT, ['cost' => $cost]);
password_verify($password,$hash);
$endTime = microtime(TRUE);
$time = $endTime - $startTime;
echo $time;
?>
the result is :1.0858609676361
After running on 3v4l that seems perfectly normal.
Password hashing is not something you want optimize. In the words of Leigh on the
hash
documentation:Yes, it's normal. That's what the
cost
parameter is for: it allows you to tweak the iteration count, making the hash slower or faster as needed.You should always make the hash as slow as possible and as fast as necessary. The reason being that the only feasible attack on a password hash is brute force. You want to make the cost so large that it takes prohibitively long to simple brute force all possible values. That's your only real defence against attackers with password hashing to begin with.
One whole second seems prohibitively for your own use. You should lower that cost a bit to stay within a few hundred milliseconds at most. Adjust to your target systems as needed.
To begin,
password_hash
is not encryption.A hash is one-way, and whatever you pass into it will always have the same end-result, however there is no way for you get the original string from the hash. This is ideal for passwords because you want to store an obfuscated version of the user's password that you can easily compare at login without actually storing what the password is. This means if the database is compromised, so long as the passwords were hashed, the attacker wouldn't get the passwords, they would get the hashed passwords which are essentially useless (you can use rainbow tables and I'm sure other techniques to get the resulting hashes, but it takes a decent amount of effort).
This leads into your original question. Why are password hashes slow? They are slow because one of the only ways to get the original string from a hash is to re-generate that hash. So if it takes 1 second to generate each hash it becomes a bigger time sink than it would have been had you used a fast hash such as
md5
of a version ofsha
. Fast hashes are great for pretty much everything except for password storage.Hopefully this answers your question. Just as an aside, I would strongly recommend generating a unique salt for each user and passing that in as one of the options into
password_hash
. This salt can be stored as plain-text in the database alongside the hashed password. Using a different salt for each password will add that into the password so a would-be attacker would have to generate a rainbow table for every salt that's in the database. At this point the attacker would likely utilize other techniques to get the passwords instead of a database breach.The default algorithm for
password_hash
,bcrypt
, is designed to be slow.http://en.wikipedia.org/wiki/Key_stretching
http://en.wikipedia.org/wiki/Rainbow_table#Defense_against_rainbow_tables
A full second is probably a little long - you could experiment with dropping
$cost
by one or two to bring it more to something like a tenth of a second, which will retain the effective protection while making the delay unnoticeable to your users.