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