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 Fonte

GitHub

Código de Exemplo

Segurança - Hash e Verifique Senhas

// Salvando Senhas de Usuário utilizando uma função hash unidirecional é
// importante para segurar aplicações. A classe Password do FastSitePHP
// provê suporte para bcypt (padrão) e Argon2.

// Exemplo de uma Senha de Usuário. Este valor não deveria ser gravado em
// um banco de dados
$password = 'Password123';

// Crie um Objeto Password
$pw = new \FastSitePHP\Security\Password();

// Hash de Senha. Isto criará uma hash textual que parece que isso:
//   '$2y$10$cDpu8TnONBhpBFPEKTTccu/mYhSppqNLDNCfOYLfBWI3K/FzFgC2y'
// O valor mudará toda vez e é seguro gravá-lo em um banco de dados.
$hash = $pw->hash($password);

// Verifique a Senha - retorna [true] ou [false]
$verified = $pw->verify($password, $hash);

// Cria uma senha aleatoriamente gerada que tem 12 caracteres de
// comprimento e contém o seguinte:
//   4 Letras Maiúsculas (A - Z)
//   4 Letras Minúsculas (a - z)
//   2 Dígitos (0 - 9)
//   2 Caracteres Especiais (~, !, @, #, $, %, ^, &, *, ?, -, _)
$strong_password = $pw->generate();

// Especifique um custo BCrypt de 12 ao invés do valor padrão 10
$pw->cost(12);
$hash2 = $pw->hash($password);
$verified2 = $pw->verify($password, $hash2);

// Ao utilizar PHP 7.2 ou mais recente, Argon2 pode ser utilizada
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)

Retorna: string

verify($password, $hash)

Verify a hashed password. Returns true/false.

Retorna: 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

Retorna: 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

Retorna: string

cost($new_value = null)

Propriedade 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.

Retorna: 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

Retorna: int

algo($new_value = null)

Propriedade 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+.

Retorna: string | $this

options($new_value = null)

Propriedade 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,
  ]

Retorna: array | $this

pepper($new_hex_value = null)

Propriedade 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)

Retorna: 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)

Retorna: string