Password Hashing

To manage the security of our users, we never store their passwords in plaintext format, we store the password´s hash instead. Hashing is not a reversible operation, the password cannot be recovered. The password can be cracked though and to make cracking as hard as possible we have to use a secure algorithm. Class Nette\Security\Passwords will help us with that.

Installation:

composer require nette/utils

The framework automatically adds a Nette\Security\Passwords service to the DI container under the name security.passwords, which you get by passing it using dependency injection:

use Nette\Security\Passwords;

class Foo
{
	/** @var Passwords */
	private $passwords;

	public function __construct(Passwords $passwords)
	{
		$this->passwords = $passwords;
	}
}

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

Chooses which secure algorithm is used for hashing and how to configure it.

The default is PASSWORD_DEFAULT, so the algorithm choice is left to PHP. Algorithm may change in newer PHP releases when newer, stronger hashing algorithms are supported. Therefore you should be aware that the length of the resulting hash can change. Therefore you should store the resulting hash in a way that can store enough characters, 255 is the recommended width.

This is how you'd use the bcrypt algorithm and change the hashing speed using the cost parameter from the default 10. In year 2020, with cost 10, the hashing of one password takes roughly 80ms, cost 11 takes 160ms, cost 12 then 320ms, the scale is logarithmic. The slower the better, cost 10–12 is considered slow enough for most use cases:

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

With dependency injection:

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

hash(string $passwords): string

Generates password´s hash.

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

The result $res contains the algorithm identifier and its settings, cryptographical salt and the hash itself. The full hash is backwards compatible, when you change the hashing parameters, you'd still be able to verify passwords hashed using previous settings. Store the full result to database, so there is no need to store salt or settings separately.

verify(string $password, string $hash)bool

Finds out, whether the given password matches the given hash. Get the $hash from database by username or email address.

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

needsRehash(string $hash): bool

Finds out if the hash matches the options given in constructor.

Use this method when you're for example changing hashing parameters. Password verification will use parameters stored with the hash and if needsRehash() returns true, you have to calculate the hash again, this time with the updated parameters, and again store it in database. This ensures that passwords hashes will be automatically “upgraded” when users are signing in.

if ($passwords->needsRehash($hash)) {
	$hash = $passwords->hash($password);
	// store $hash to database
}
Improve this page