Secure Password

Introduction

“Since 2017, NIST recommends using a secret input when hashing memorized secrets such as passwords. By mixing in a secret input (commonly called a "pepper"), one prevents an attacker from brute-forcing the password hashes altogether, even if they have the hash and salt. For example, an SQL injection typically affects only the database, not files on disk, so a pepper stored in a config file would still be out of reach for the attacker. A pepper must be randomly generated once and can be the same for all users. Many password leaks could have been made completely useless if site owners had done this.

Since there is no pepper parameter for password_hash (even though Argon2 has a "secret" parameter, PHP does not allow to set it), the correct way to mix in a pepper is to use hash_hmac().” php.net

How to use

Solital uses the SecurePassword package to validate passwords and prevent attacks. That is, even if someone manages to access the hash created with this package, using only the native password_verify function WILL NOT return true.

Solital has two password helpers:

  • Generate password hash
pass_hash($password, int $cost = 10)
  • Checks the hash generated by the pass_hash helper
pass_verify($password, string $hash)

Unlike just using password_hash function, these helpers adds a secret entry (commonly called a pepper) to make it difficult to break the generated hash.

Customizing the password

To change the type of algorithm used in encryption, the cost, among other options, you can edit the auth.yaml file.

password:
  algorithm: default # default - argon2 - argon2d
  pepper: b3f952d5d9adea6f63bee9d4c6fceeaa
  cost: 10
  memory_cost: ''
  time_cost: ''
  threads: ''
  crypt_type: openssl
  wait_microseconds: 25000

In the algorithm key, you can add the following values: default, argon2 and argon2d. For more information about other PHP constants, see this link.

Changing the value of “pepper”

As mentioned in the introduction, the SecurePassword package uses a “pepper” value. To change the value of this pepper, you can edit the value of the peeper key in the auth.yaml file. However, it is recommended to use the APP_HASH variable. If this variable does not exist in your project, run the command php vinci generate:hash.

If this variable is present in the .env file, then you can delete the peeper in the auth.yaml file.

Changing Peeper encryption

By default, peeper is encrypted using OpenSSL. You can switch to Sodium encryption by changing the value of the crypt_type variable in the auth.yaml file.

crypt_type: sodium

Password Policy

You can set some requirements when creating a password, such as password length, special characters, etc.

use Solital\Core\Auth\Password;

$password = new Password();
$password->setMinimumLength(15);
$password->requireUppercase();
$password->requireDigits();
$password->requireSpecialChars();
$password->setSpecialChars('!@#%');
$result = $password->validatePassword('strongpassword');

if ($result === true) {
    echo "Password meets the policy requirements.";
    // Go and do things with it
} else {
    echo "Password validation failed. Errors:\n";
    print_r($result);
    // Go and display these error messages to your user
}

Customizing error messages

To customize error messages, you should use the setCustomErrorMessages method. Using the example from the previous topic, the code would look like this:

use Solital\Core\Auth\Password;

$customErrorMessages = [
    'min_length' => 'Your password is too short. It must be at least 15 characters long.',
    'uppercase' => 'Your password must contain at least one uppercase letter.',
];

$password = new Password();
$password->setMinimumLength(15);
$password->requireUppercase();
$password->requireDigits();
$password->requireSpecialChars();
$password->setSpecialChars('!@#%');
$password->setCustomErrorMessages($customErrorMessages);
$result = $password->validatePassword('strongpassword');

if ($result === true) {
    echo "Password meets the policy requirements.";
    // Go and do things with it
} else {
    echo "Password validation failed. Errors:\n";
    print_r($result);
    // Go and display these error messages to your user
}

What to see next?


Built with MkDocs.