Secure Password Storage in PHP: Encryption Techniques

In this comprehensive guide, We will cover the basics of password encryption, hashing algorithms, salting, and best practices for password security.

Passwords are the first line of defense in securing your application. Password security is crucial for the safety of user data. In this article, we will discuss how to securely store passwords in PHP using various encryption techniques.

Why Secure Password Storage is Important?

Passwords are the keys to the user's sensitive data. If these passwords are stored in plain text or in a way that can be easily hacked, then it can lead to a security breach. Password security is important because it provides an additional layer of security to user data.

Encryption Techniques for Password Storage:

There are various encryption techniques available for password storage in PHP. Some of them are:

  1. Hashing
  2. Salting
  3. Key Stretching
  4. Argon2

In this article, we will discuss these techniques in detail and learn how to implement them in PHP.

Hashing:

Hashing is a technique that converts the plain text password into a fixed-length string of characters. This technique is irreversible, meaning once the password is hashed, it cannot be converted back to its original form. Hashing algorithms used for password storage include MD5, SHA1, SHA256, and SHA512. However, MD5 and SHA1 are no longer considered secure and should be avoided.

Here's an example PHP code that demonstrates how to hash a password using the password_hash() function in PHP:

 $password = "mySecurePassword";
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);

// Store the hashed password in the database
// ...

In the code above, we first define a variable $password that holds the plain text password that we want to hash. We then use the password_hash() function to hash the password using the default algorithm. The hashed password is stored in the variable $hashedPassword.

It is important to note that the password_hash() function automatically generates a random salt for each password that is hashed. This salt is then included in the resulting hash, which makes the password more secure.

To verify a password, we can use the password_verify() function. Here's an example:

 $storedHashedPassword = "..." // Retrieve the hashed password from the database
$userPassword = "mySecurePassword";

if (password_verify($userPassword, $storedHashedPassword)) {
    echo "Password is correct!";
} else {
    echo "Password is incorrect.";
}

In the code above, we retrieve the hashed password from the database and store it in the variable $storedHashedPassword. We then define a variable $userPassword that holds the plain text password that the user entered. We use the password_verify() function to verify that the entered password matches the stored hashed password. If the password is correct, we output "Password is correct!". Otherwise, we output "Password is incorrect.".

By using the password_hash() and password_verify() functions in PHP, we can easily implement secure password hashing in our applications.

Salting:

Salting is a technique that adds a random string of characters to the password before it is hashed. This adds an additional layer of security to the password. Even if an attacker gains access to the hashed password, they would not be able to guess the salt.

Here's an example PHP code that demonstrates how to add salt to a password before hashing it:

 $password = "mySecurePassword";
$salt = "randomSalt123"; // Generate a random salt
$hashedPassword = hash('sha256', $password . $salt);

// Store the salt and hashed password in the database
// ...

In the code above, we first define a variable $password that holds the plain text password that we want to hash. We then generate a random salt and store it in the variable $salt. We use the hash() function to hash the password and salt using the SHA256 algorithm. The resulting hash is stored in the variable $hashedPassword.

To verify a password, we need to retrieve the stored salt and hashed password from the database and use the same salt to hash the entered password. Here's an example:

 $storedSalt = "randomSalt123"; // Retrieve the salt from the database
$storedHashedPassword = "..." // Retrieve the hashed password from the database
$userPassword = "mySecurePassword";

$hashedPassword = hash('sha256', $userPassword . $storedSalt);

if ($hashedPassword === $storedHashedPassword) {
    echo "Password is correct!";
} else {
    echo "Password is incorrect.";
}

In the code above, we retrieve the stored salt and hashed password from the database and store them in the variables $storedSalt and $storedHashedPassword, respectively. We define a variable $userPassword that holds the plain text password that the user entered. We use the same salt to hash the entered password and store the result in the variable $hashedPassword. We then compare the hashed password with the stored hashed password. If the two hashes match, we output "Password is correct!". Otherwise, we output "Password is incorrect.".

By adding salt to a password before hashing it, we can make it more difficult for attackers to crack the password using rainbow tables and other precomputed attacks. However, it is still recommended to use the password_hash() and password_verify() functions in PHP for secure password hashing.

Key Stretching:

Key stretching is a technique that slows down the hashing process by adding a delay between each hashing attempt. This makes it more difficult for attackers to guess the password.

 <?php

// Define the original key and the number of iterations to perform
$original_key = "my_secret_key";
$num_iterations = 10000;

// Perform key stretching
for ($i = 0; $i < $num_iterations; $i++) {
  $original_key = hash('sha256', $original_key);
}

// The stretched key is the final value of $original_key
$stretched_key = $original_key;

// Use the stretched key for encryption/decryption or other cryptographic purposes
// ...

?>

In this example, we start with an original key and a number of iterations to perform. We then use a loop to perform the key stretching, which involves repeatedly hashing the key using a secure hashing algorithm (in this case, SHA-256) for the specified number of iterations. The stretched key is the final value of the original key after all iterations have been performed.

Note that the number of iterations used for key stretching should be chosen carefully to balance security and performance considerations. A value of 10,000 is commonly used, but this may be adjusted based on the specific requirements of your application. Additionally, it is recommended to use a secure random salt value along with key stretching for added security.

Argon2:

Argon2 is a key derivation function that is designed to be resistant to attacks from GPUs and ASICs. It is considered to be one of the most secure password storage techniques available today.

 <?php

// Define the password to be hashed and the salt
$password = "my_secret_password";
$salt = random_bytes(SODIUM_CRYPTO_PWHASH_SALTBYTES);

// Hash the password using Argon2
$hash = sodium_crypto_pwhash_str(
  $password, 
  SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE,
  SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE
);

// Verify a password against the hash
$is_valid = sodium_crypto_pwhash_str_verify($hash, $password);

// Output the hash and verification result
echo "Hash: " . $hash . "\n";
echo "Password is " . ($is_valid ? "valid" : "invalid");

?>

In this example, we start by defining the password to be hashed and generating a random salt value using the random_bytes function from the sodium library. We then use the sodium_crypto_pwhash_str function to hash the password using Argon2. This function takes the password, the number of iterations (SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE), and the memory limit (SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE) as input, and returns the hashed password as a string.

To verify a password against the hash, we use the sodium_crypto_pwhash_str_verify function, which takes the hash and the password as input and returns a boolean value indicating whether the password matches the hash.

Note that the sodium library is included in PHP 7.2 and later, so you'll need to ensure that your PHP installation includes this library in order to use Argon2. Additionally, you should adjust the OPSLIMIT and MEMLIMIT values based on the specific requirements of your application to balance security and performance considerations.

Conclusion:

In this article, we have discussed various encryption techniques for secure password storage in PHP. We have learned about hashing, salting, key stretching, and Argon2. By implementing these techniques, we can ensure that user passwords are stored securely, which helps to protect user data from unauthorized access.