Verifying with password_verify()
Learn to compare a plain password against a hash with password_verify().
How does password_verify work?
password_verify($password, $hash) compares a plain password against a hash and returns true or false. The salt and cost embedded in the hash are read automatically; you do nothing extra.
Verification uses a constant-time comparison to prevent timing attacks. So never write your own check with ==; always use password_verify.
What is hash_equals for?
Sometimes you need to compare two strings safely: a CSRF token, an OTP code. The == operator compares characters in order and stops at the first difference; this timing leaks information to an attacker.
hash_equals($known, $userInput) always runs in the same time, so timing attacks are blocked. password_verify uses a similar method internally.
Exercise Write a verify function
Define a verify($password, $hash) function. Inside it, use password_verify to check the password and return a bool. The $hash variable is already defined. Call verify("gizli123", $hash) and verify("wrong", $hash); print each result as "valid" or "invalid".
Show example solution
"invalid") . "\n"; and echo (verify("wrong", $hash) ? "valid" : "invalid") . "\n";.
Example solution:
<?php
$hash = password_hash("gizli123", PASSWORD_DEFAULT);
function verify($password, $hash) {
return password_verify($password, $hash);
}
echo (verify("gizli123", $hash) ? "valid" : "invalid") . "\n";
echo (verify("wrong", $hash) ? "valid" : "invalid") . "\n";
Test yourself
-
Complete the password_verify call
$valid = ____($password, $hash);Show answer
$valid = password_verify($password, $hash); -
Why is comparing two hashes with == risky?
- It is open to timing attacks
- It can give a wrong result
- It is slower
- PHP throws an error
Show answer
It is open to timing attacks — Correct. == stops at the first difference; this timing leaks info.
-
Match the verification concepts
- password_verify
- Compares against a hash
- hash_equals
- Constant-time comparison
- true
- Match succeeded
- false
- No match