FastSitePHP\Security\Password

Class to hash a user-suppied password with a secure algorithm [bcrypt or Argon2]. This class includes additional password functionality such as the abilty to generate secure random passwords.

Código Fuente

GitHub

Código de Ejemplo

Security - Hash and Verify Passwords

// Saving User Passwords using a one-way hashing function is important for
// secure applications. FastSitePHP’s Password class provides support for
// bcrypt (default) and Argon2.

// Example of a User Password, this value should not be saved to a database
$password = 'Password123';

// Create a Password Object
$pw = new \FastSitePHP\Security\Password();

// Hash the Password, this will create hash text that looks like this:
//   '$2y$10$cDpu8TnONBhpBFPEKTTccu/mYhSppqNLDNCfOYLfBWI3K/FzFgC2y'
// The value will change everytime and is safe to save to a database.
$hash = $pw->hash($password);

// Verify a Password - returns [true] or [false]
$verified = $pw->verify($password, $hash);

// Create a randomly generated password that is 12 characters in length
// and contains the following:
//   4 Uppercase Letters (A - Z)
//   4 Lowercase Letters (a - z)
//   2 Digits (0 - 9)
//   2 Special Characters (~, !, @, #, $, %, ^, &, *, ?, -, _)
$strong_password = $pw->generate();

// Specify a different BCrypt Cost of 12 instead of the default value 10
$pw->cost(12);
$hash2 = $pw->hash($password);
$verified2 = $pw->verify($password, $hash2);

// When using PHP 7.2 or later Argon2 can be used
if (PHP_VERSION_ID >= 70200) {
    $pw->algo('Argon2');
    $argon_hash = $pw->hash($password);
    $argon_verified = $pw->verify($password, $argon_hash);
}

Métodos

__construct()

Class Constructor

If using PHP 5.3 or 5.4 then functions [password_hash() and password_verify()] are created with polyfills using [https://github.com/ircmaxell/password_compat].

If using PHP 5.3 then functions [bin2hex()] and [hex2bin()] are polyfilled.

hash($password)

Create a secure password hash from a user password using using a strong one-way hashing algorithm (bcrypt or Argon2). In a secure application the password itself must not be saved or logged but instead the resulting hash gets saved to the database or storage provider.

The resulting text will be 60 characters in length for bcrypt which would need to be the minimum field size in a database. Argon2 will be longer, at least 95 characters and can be larger when using different options.

Using default options this is equivalent to calling built-in PHP function:
    \password_hash($password, PASSWORD_BCRYPT, ['cost' => 10])

And for Argon2:
    \password_hash($password, PASSWORD_ARGON2I)

Returns: string

verify($password, $hash)

Verify a hashed password. Returns true/false.

Returns: bool

needsRehash($hash)

Return true if a verified password hash should be re-hashed. For example if bcrypt cost was increased after users started using the app.

Example Usage:

    if ($password->verify($submitted_password, $hash)) {
        if ($password->needsRehash($hash)) {
            $new_hash = $password->hash($submitted_password);
            // Save to db, etc

Returns: bool

generate()

Return a randomly generated password that is 12 characters in length and contains the following:

  4 Uppercase Letters (A - Z)
  4 Lowercase Letters (a - z)
  2 Digits (0 - 9)
  2 Special Characters (~, !, @, #, $, %, ^, &, *, ?, -, _)

For strong online password creation with options try:
  https://www.lastpass.com/password-generator

Returns: string

cost($new_value = null)

Propiedad Getter / Setter

Specify Cost to use when hashing the Password with bcrypt. Function [findCost()] shows how high the cost can be without slowing down your server.

Defaults to 10.

Returns: int | $this

findCost()

This code will benchmark your server to determine how high of a cost you can afford when using bcrypt. You want to set the highest cost that you can without slowing down your server too much. 8-10 is a good baseline, and more is good if your servers are fast enough. The code below aims for ≤ 50 milliseconds stretching time, which is a good baseline for systems handling interactive logins.

This function comes directly from the PHP Docs at: https://secure.php.net/manual/en/function.password-hash.php

Returns: int

algo($new_value = null)

Propiedad Getter / Setter

Get or set the Algorithm to use: ['bcrypt' or 'Argon2']. [bcrypt] is used by default and supported in all versions of PHP while [Argon2] requires PHP 7.2+.

Returns: string | $this

options($new_value = null)

Propiedad Getter / Setter

Specify options when using Argon2. For bcrypt use [cost()].

Defaults to:
  [
      'memory_cost' => PASSWORD_ARGON2_DEFAULT_MEMORY_COST,
      'time_cost'   => PASSWORD_ARGON2_DEFAULT_TIME_COST,
      'threads'     => PASSWORD_ARGON2_DEFAULT_THREAD,
  ]

Returns: array | $this

pepper($new_hex_value = null)

Propiedad Getter / Setter

Get or set an optional pepper value to use when hashing and verifying the password. For Password Hashing, Pepper is different than the Salt as Pepper is a secret value that is shared by all users. Salt is one of the primary security features of Passwords, while Pepper can be used in certain environments to provide an additional layer of security. If used the Pepper value MUST be saved outside of the database where the password hashes are saved and the pepper value must not be shared with end users. While it can provide an additional level of security it comes with significant complexity so using it requires careful consideration.

The pepper value must be a hexadecimal string and one can be generated from the [generatePepper()] function.

Advantages of Pepper:
- In a highly structured environment where a Developer would not have access
   to the database and the DBA would not have access to the source code then
   adding pepper limits the number of people would have required shared secrets.
- If a Database is compromised and hashes are stolen but the Application along
   with the Pepper is safe then Pepper can used to prevent dictionary attacks.
- Further Reading:
   https://security.stackexchange.com/questions/3272/password-hashing-add-salt-pepper-or-is-salt-enough/3701

Disadvantages of Pepper:
- The Pepper value can't be changed without requiring all users of the
   application to change their password. This can cause a lot of complexity
   for managing users of the app. If all password hashes are stolen then
   simply requiring users to change their password would likely be enough
   for most apps.
- If the Database and Application are on the same server then someone who
   obtains Database Access is more likely to get source code access as well
   which defeats the purpose of Pepper.
- The algorithms used in this class (bcrypt and Argon2 with proper salt)
   are well studied and known to be secure. Pepper only works in specific cases.
- Further Reading:
   https://stackoverflow.com/questions/16891729/best-practices-salting-peppering-passwords
   https://blog.ircmaxell.com/2012/04/properly-salting-passwords-case-against.html

Other Option:
- Another option instead of using Pepper would be to encrypt the password
   before hashing it or encrypt the hash. This has similar advantages and
   disadvantages compared to using pepper.

For an overview of Salt and Pepper see the following links:
   https://en.wikipedia.org/wiki/Salt_(cryptography)
   https://en.wikipedia.org/wiki/Pepper_(cryptography)

Returns: null | string | $this

generatePepper($bytes = 8)

Generate a random hex string for the [pepper()] function using cryptographically secure pseudo-random bytes.

Defaults to 8 bytes in length (16 characters in hex)

Returns: string