Password Hashing

To ensure the security of our users, we never store their passwords in readable form, but only store their imprint (called hash). The hash cannot be reverse-engineered back to the original password. It is important to use a secure algorithm to create the hash. The class Nette\Security\Passwords helps us with this.

Installation and requirements

The framework automatically adds a service of type Nette\Security\Passwords to the DI container under the name security.passwords. You can get by having it passed to you using dependency injection.

use Nette\Security\Passwords;

class Foo
{
	public function __construct(
		private Passwords $passwords,
	) {
	}
}

__construct ($algo=PASSWORD_DEFAULT, array $options=[])string

We choose which secure algorithm to use for generating the hash and configure its parameters.

The default is PASSWORD_DEFAULT, meaning the choice of algorithm is left up to PHP. The algorithm may change in newer PHP versions if newer, stronger hashing algorithms appear. Therefore, you should be aware that the length of the resulting hash may change, and you should store it in a way that can accommodate enough characters; 255 is the recommended width.

Example of setting the hashing speed for the bcrypt algorithm by changing the cost parameter: (in 2020, the default is 10, hashing a password takes roughly 80ms; for cost 11, it's approx. 160ms; for cost 12, approx. 320ms; the slower, the better the protection, with speed 10–12 is already considered sufficient protection)

// we will hash passwords with 2^12 (2^cost) iterations of the bcrypt algorithm
$passwords = new Passwords(PASSWORD_BCRYPT, ['cost' => 12]);

Using dependency injection:

services:
	security.passwords: Nette\Security\Passwords(::PASSWORD_BCRYPT, [cost: 12])

hash (string $password): string

Generates the password hash.

$res = $passwords->hash($password); // Hashes the password

The result $res is a string that, in addition to the hash itself, contains the identifier of the algorithm used, its settings, and a cryptographic salt (random data ensuring that a different hash is generated for the same password). It is therefore backward compatible; for example, if you change the parameters, hashes stored using previous settings can still be verified. This entire result is stored in the database, so there is no need to store the salt or settings separately.

verify (string $password, string $hash)bool

Finds out if the given password matches the given hash. $hash obtain from the database according to the entered username or e-mail address.

if ($passwords->verify($password, $hash)) {
	// correct password
}

needsRehash (string $hash): bool

Finds out whether the hash matches the options specified in the constructor.

It is useful to use it when, for example, you change the hashing cost. Verification takes place according to the stored settings, and if needsRehash() returns true, it is necessary to create the hash again, this time with the new parameters, and save it again in the database. This automatically “upgrades” stored hashes when users log in.

if ($passwords->needsRehash($hash)) {
	$hash = $passwords->hash($password);
	// store $hash into database
}
version: 4.0 3.x 2.x