stella-maris/nist-password

Handle password according to the NIST

dev-main 2024-04-13 07:26 UTC

This package is not auto-updated.

Last update: 2024-12-21 10:26:58 UTC


README

A library to use passwords in an NIST-compliant way.

This library implements all relevant points mentioned in section 5.1.1 of the NIST Special Publication 800-63B

codecov

Why?

The NIST advises national bodies of the US in digital questions. One of them is Authentication and authorization. So in essence the NIST advises national bodies like the NSA regarding (amongst other things) what makes a safe password and what makes a safe authentication mechanism.

This library converts those written rules into a library that you can use within your code. But the code is not everything as the NIST recommendations also need to be applied to your processes. More in the Chapter on Processes.

How?

Require the library via composer

$ composer require stella-maris/nist-password

Now you can use the following code to verify whether a password is compliant with the NIST rules like this:

use StellaMaris\NistPassword\Validate;
use StellaMaris\Password\Filters\FilterListFactory;
use StellaMaris\Password\Validate\ValidatorListFactory;

$validator = new Validate(
    ValidatorListFactory::create(),
	FilterListFactory::create(),
);
$feedback = $validator->validate($password);
if (! $feedback->isValid()) {
	var_Dump($feedback->getViolations());
}

The getViolations()-method will return a list of Violation-objects that can then be queried for further informations.

Once you have verified that a new password is valid, you can get the password-hash for storage from the validator like this:

$password = $feedback->getPassword();

echo $password;

The password is stored within an object that is pretty safe against accidentally leaking the cleartext password.

For that the Password-object stores the cleartext-password in a symterically encrypted way using a predefined salt and a password that is discarded at the end of the scripts runtime. Casting the object to string will only reveal the hashes password. The password hash is created using PHPs password-hasing library.

Should you - for whatever reason - need the password again in cleartext you can get access to it via the yesIDoNeedThePasswordInCleartextAndIKnowOfTheImplicationsThatMightHave()-method. Be warned that the return value of this method will again expose the cleartext-password! You should use it as fast as possible and destroy the variable immediately afterwards like so:

$password = $feedback->getPassword();

// No intermediary variable!
ldap_bind($ldap_connection, $user, $password->yesIDoNeedThePasswordInCleartextAndIKnowOfTheImplicationsThatMightHave());

// immediately unset the variable after usage!
$pass = $password->yesIDoNeedThePasswordInCleartextAndIKnowOfTheImplicationsThatMightHave();
ldap_bind($ldap_connection, $user, $pass);
unset($pass);

To do an actual authentication you can then use this process:

use StellaMaris\NistPasword\Authenticator;

$authenticator = new Authenticator();
$result = $authenticator->authenticate($password, $hashFromDatabase);
if (! $result->isValid()) {
	echo "The login credentials are invalid"
}

if ($result->isRehashed()) {
	// The existing credentials are not considered strong enough any more so the
	// password has been rehasehd with a stronger algorithm and now needs to be
	// persisted again
	$pdo->query(`UPDATE users SET password=:password WHERE user = :user`, [
		'password' => (string) $result->getPassword(),
		'user' => $user,
	]);
}

if ($needsNewPassword) {
    // The whole password set has been compromized so the users have to create a new
    // password at login.
    // You should implement this logic right from the start, hoping that you will never need it
    // Make sure that you can somehow verify that a user is actually the user they claim to be
    // by using some verification mechanism (like sending an email to their registered address)
    // Think about that the emails might have been compromized. Make sure that you detect
    // unwanted tampering with that data!
    // Do NOT - I repeat: NOT! - use "security questions". Those are considered bad practice
}

Should you need to come up with a new Password for a user, you can create one like this:

use StellaMaris\NistPassword\PasswordCreator;

$password = new PasswordCreator();

echo sprintf(
    "The password for %s is %s",
    $user,
    $password->yesIDoNeedThePasswordInCleartextAndIKnowOfTheImplicationsThatMightHave()
);

$pdo->query(`UPDATE users SET password=:password WHERE user = :user`, [
		'password' => (string) $result->getPassword(),
		'user' => $user,
	]);

Processes

You might need to adapt your processes to be NIST-compliant.

General Requirements

Depending on the Authenticator Assurance Level you will need other factors besides the here mentioned Memorized Secret. Check the documentation for your requirements.

This package only takes care of the Memorizted Secret!

Password-Recovery

You should not use security questions to regain access to a locked account!