Hashing de contraseñas

Para garantizar la seguridad de nuestros usuarios, no almacenamos sus contraseñas en forma legible, sino que guardamos solo su huella (el llamado hash). A partir de la huella no se puede reconstruir la forma original de la contraseña. Es importante utilizar un algoritmo seguro para crear la huella. Con esto nos ayuda la clase Nette\Security\Passwords.

Instalación y requisitos

El framework añade automáticamente al contenedor DI un servicio de tipo Nette\Security\Passwords bajo el nombre security.passwords, al que puedes acceder solicitándolo mediante inyección de dependencias.

use Nette\Security\Passwords;

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

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

Elegimos qué algoritmo seguro usar para generar el hash y configuramos sus parámetros.

Por defecto se usa PASSWORD_DEFAULT, es decir, la elección del algoritmo se deja a PHP. El algoritmo puede cambiar en versiones más recientes de PHP si aparecen algoritmos de hashing más nuevos y fuertes. Por lo tanto, debes ser consciente de que la longitud del hash resultante puede cambiar, y deberías almacenarlo de una manera que pueda acomodar suficientes caracteres, 255 es el ancho recomendado.

Ejemplo de configuración de la velocidad de hashing con el algoritmo bcrypt cambiando el parámetro cost: (en 2020 el valor predeterminado es 10, el hashing de la contraseña tarda aproximadamente 80ms, para cost 11 es aprox. 160ms, para cost 12 aprox. 320ms, cuanto más lento, mejor protección, considerándose ya suficiente una velocidad de 10–12)

// hashearemos las contraseñas con 2^12 (2^cost) iteraciones del algoritmo bcrypt
$passwords = new Passwords(PASSWORD_BCRYPT, ['cost' => 12]);

Mediante inyección de dependencias:

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

hash (string $passwords): string

Genera el hash de la contraseña.

$res = $passwords->hash($password); // Hashea la contraseña

El resultado $res es una cadena que, además del propio hash, contiene también el identificador del algoritmo utilizado, su configuración y la sal criptográfica (datos aleatorios que aseguran que para la misma contraseña se genere un hash diferente). Por lo tanto, es compatible hacia atrás, si por ejemplo cambias los parámetros, también se podrán verificar los hashes guardados con la configuración anterior. Todo este resultado se guarda en la base de datos, por lo que no es necesario guardar la sal o la configuración por separado.

verify (string $password, string $hash)bool

Verifica si la contraseña dada corresponde a la huella dada. Obtén $hash de la base de datos según el nombre de usuario o la dirección de correo electrónico introducidos.

if ($passwords->verify($password, $hash)) {
	// contraseña correcta
}

needsRehash (string $hash): bool

Verifica si el hash corresponde a las opciones especificadas en el constructor.

Es útil usarlo en el momento en que, por ejemplo, cambias la velocidad de hashing. La verificación se realiza según la configuración guardada y si needsRehash() devuelve true, entonces es necesario volver a crear el hash, esta vez con los nuevos parámetros, y guardarlo de nuevo en la base de datos. De esta manera, los hashes guardados se “actualizan” automáticamente al iniciar sesión los usuarios.

if ($passwords->needsRehash($hash)) {
	$hash = $passwords->hash($password);
	// guardar $hash en la base de datos
}
versión: 4.0