Current Location: Home> Latest Articles> How to safely compare passwords with hash_equals() using PHP's crypt() function to avoid common security vulnerabilities?

How to safely compare passwords with hash_equals() using PHP's crypt() function to avoid common security vulnerabilities?

M66 2025-05-20

When building a user authentication system, safe handling of passwords is an issue that developers must pay attention to. Comparing passwords incorrectly may cause the system to be subject to security threats such as Timing Attacks. PHP provides some built-in functions that can help us handle password verification securely. Among them, the combination of crypt() and hash_equals() is a relatively safe way of practice.

1. What is the crypt() function?

crypt() is a encryption function of PHP, which is used to hash encryption passwords based on some algorithm (such as bcrypt , SHA-512 , etc.). Its syntax is as follows:

 string crypt(string $string, string $salt)

The salt parameter determines the encryption algorithm and its behavior. For modern applications, bcrypt is recommended, and the appropriate salt can be automatically generated by the following methods:

 $salt = '$2y$10$' . substr(strtr(base64_encode(random_bytes(16)), '+', '.'), 0, 22);
$hash = crypt('mypassword', $salt);

2. Why can’t you directly use == or == to compare password hashes?

Many beginners will write the following code to verify passwords:

 if (crypt($inputPassword, $storedHash) == $storedHash) {
    // Login successfully
}

This seems feasible in function, but there is a serious security risk - Timing Attack . An attacker can gradually guess the correct password hash by measuring the slight difference in program response time.

3. Safe practice: use hash_equals()

To solve the problem of timing attacks, PHP provides hash_equals() function since 5.6 to safely compare two hash values:

 bool hash_equals(string $known_string, string $user_string)

It uses a constant time algorithm and does not return in advance based on the content of the string, avoiding time difference leakage.

4. A complete example combining crypt() and hash_equals()

 <?php
// Suppose we get the encrypted password hash from the database
$storedHash = '$2y$10$9YzyYtVht3tcGEn.7PiF2OlRM0HDTrM7Z5D.yPi8hdm0fJeFVKH4K'; // Depend on crypt() Generated bcrypt Hash
$inputPassword = $_POST['password'] ?? '';

// use crypt() 对use户输入的密码进行Hash,使use存储Hash作为 salt
$inputHash = crypt($inputPassword, $storedHash);

// 使use hash_equals() Safety comparison
if (hash_equals($storedHash, $inputHash)) {
    echo "Login successfully!";
} else {
    echo "Error password!";
}
?>

5. Recommended modern practices (supplement)

Although crypt() is still safe to use, PHP official recommends using password_hash() and password_verify() because they encapsulate the algorithm selection and security comparison process, making it easier and safer to use. For example:

 // 创建密码Hash
$hash = password_hash('mypassword', PASSWORD_BCRYPT);

// Verify password
if (password_verify($inputPassword, $hash)) {
    echo "Verification passed";
}

However, in some scenarios (such as maintaining old systems or having special needs), the combination of crypt() and hash_equals() is still an acceptable and safe solution.

6. Summary

  • Avoid using == or === compare password hashes;

  • When using crypt() hash password, you must correctly select salt and algorithm (bcrypt is recommended);

  • Use hash_equals() for safe comparisons to prevent timing attacks;

  • If there is no specific reason, it is recommended to use password_hash() and password_verify() instead of low-level encapsulation.

Security is not an option but a requirement when processing user passwords. The correct approach can not only protect user privacy, but also improve the attack resistance of the entire system.