Hashing de senhas
Para garantir a segurança de nossos usuários, não armazenamos suas senhas em formato legível, mas armazenamos apenas uma impressão digital (o chamado hash). A partir da impressão digital, não é possível reconstruir a forma original da senha. É importante usar um algoritmo seguro para criar a impressão digital. A classe Nette\Security\Passwords nos ajuda com isso.
O framework adiciona automaticamente ao contêiner DI um serviço do tipo Nette\Security\Passwords
com o nome
security.passwords
, ao qual você pode acessar solicitando-o através de injeção de dependência.
use Nette\Security\Passwords;
class Foo
{
public function __construct(
private Passwords $passwords,
) {
}
}
__construct ($algo=PASSWORD_DEFAULT, array $options=[]): string
Escolhemos qual algoritmo seguro usar para gerar o hash e configuramos seus parâmetros.
Por padrão, usa-se PASSWORD_DEFAULT
, ou seja, a escolha do algoritmo é deixada para o PHP. O algoritmo pode
mudar em versões mais recentes do PHP, se algoritmos de hashing mais novos e mais fortes aparecerem. Portanto, você deve estar
ciente de que o comprimento do hash resultante pode mudar, e você deve armazená-lo de forma que possa acomodar caracteres
suficientes, 255 é a largura recomendada.
Exemplo de configuração da velocidade de hashing com o algoritmo bcrypt alterando o parâmetro cost: (em 2020, o padrão é 10, o hashing da senha leva cerca de 80ms, para cost 11 é cerca de 160ms, para cost 12 cerca de 320ms, quanto mais lento, melhor a proteção, sendo que a velocidade 10–12 já é considerada proteção suficiente)
// vamos hashear as senhas com 2^12 (2^cost) iterações do algoritmo bcrypt
$passwords = new Passwords(PASSWORD_BCRYPT, ['cost' => 12]);
Usando injeção de dependência:
services:
security.passwords: Nette\Security\Passwords(::PASSWORD_BCRYPT, [cost: 12])
hash (string $passwords): string
Gera o hash da senha.
$res = $passwords->hash($password); // Gera o hash da senha
O resultado $res
é uma string que, além do próprio hash, contém também o identificador do algoritmo usado,
suas configurações e o sal criptográfico (dados aleatórios que garantem que para a mesma senha seja gerado um hash
diferente). É, portanto, retrocompatível; se, por exemplo, você alterar os parâmetros, os hashes armazenados usando as
configurações anteriores ainda poderão ser verificados. Todo esse resultado é armazenado no banco de dados, portanto, não é
necessário armazenar o sal ou as configurações separadamente.
verify (string $password, string $hash): bool
Verifica se a senha fornecida corresponde à impressão digital fornecida. Obtenha $hash
do banco de dados de
acordo com o nome de usuário ou endereço de e-mail fornecido.
if ($passwords->verify($password, $hash)) {
// senha correta
}
needsRehash (string $hash): bool
Verifica se o hash corresponde às opções especificadas no construtor.
É útil usar quando, por exemplo, você altera a velocidade de hashing. A verificação ocorre de acordo com as
configurações armazenadas e, se needsRehash()
retornar true
, é necessário criar novamente o hash,
desta vez com os novos parâmetros, e armazená-lo novamente no banco de dados. Desta forma, os hashes armazenados são
“atualizados” automaticamente durante o login dos usuários.
if ($passwords->needsRehash($hash)) {
$hash = $passwords->hash($password);
// armazenar $hash no banco de dados
}