Nunca armazene senhas
Parte da seção Autenticação e segurança do Journey de Node.js da Coddy. Lição 4 de 24.
As pessoas reutilizam senhas, então uma senha em texto simples que vaza pode expor contas em outros lugares. Armazene um hash de senha com salt: um valor derivado que você verifica recalculando-o, em vez de decodificá-lo.
const salt = randomBytes(16).toString('hex');
const key = await scryptAsync(inviteCode, salt, 32);
const saved = salt + '.' + key.toString('hex');Este exemplo combina um salt e uma chave derivada para um código de convite. O delimitador permite que a verificação recupere o salt e derive outra chave com os mesmos parâmetros. Sua tarefa de senha usa seu próprio delimitador e comprimento de chave. Gere o salt para cada nova senha, derive a chave e, em seguida, armazene ambos. Hashes com salt ainda exigem senhas fortes, pois um invasor pode tentar adivinhá-las.
Desafio
FácilNo momento, o cadastro salva cada senha exatamente como foi digitada. Faça com que ele salve um hash com salt, para que um vazamento do banco de dados não revele as senhas.
- Em
passwords.js, alterehashPassword(password)para que retorne o texto que o cadastro salva, no formato salt, dois-pontos, hash:- O salt tem 16 bytes aleatórios, gerados novamente a cada chamada e escritos em hexadecimal: 32 caracteres de 0 a 9 e de a a f.
- O hash é uma chave de 64 bytes que
scryptcria a partir da senha e desse salt, também escrita em hexadecimal: 128 caracteres. O terceiro argumento descryptAsyncé o comprimento da chave em bytes. - Junte os dois com dois-pontos. Um valor salvo fica assim:
f2bba0669d9fa2d203afc7e61bf8f065:c3f7cae352e023a8d4766da9a316b5a2c844100efff22c4079f89a8ab8512ac91c33227481c3afa88c3ba0e88347f9e3e0c22dad9d55f19688a350f71be8dbd2
- Você não precisa alterar
server.js. OPOST /signupjá chamahashPassworde salva o que ela retorna. Ele também temGET /debug/users/:username, que mostra o que foi salvo para um usuário. Essa rota existe apenas para você conferir; um aplicativo real nunca tem essa rota.
Experimente: Pressione Executar. Envie POST /signup com {"username": "ada", "password": "correct horse"}. Você recebe o status 201 e {"username": "ada"}. Envie o mesmo corpo com "username": "bob". Agora envie GET /debug/users/ada e, em seguida, GET /debug/users/bob. Cada passwordHash tem 32 caracteres, dois-pontos e mais 128 caracteres. Os dois valores são diferentes, embora ada e bob tenham escolhido a mesma senha.
Experimente você mesmo
import { randomBytes, scrypt } from 'node:crypto';
import { promisify } from 'node:util';
const scryptAsync = promisify(scrypt);
// Converte uma senha no texto que signup armazena.
// Por enquanto, mantém a senha como foi digitada.
export async function hashPassword(password) {
return password;
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Autenticação e segurança
Pratique por conta própria: Playground de Express