Verificando uma senha
Parte da seção Autenticação e segurança do Journey de Node.js da Coddy. Lição 2 de 17.
Um hash não pode ser revertido, então um login nunca lê a senha armazenada. Você aplica hash à tentativa da mesma maneira e compara as duas chaves. Da mesma maneira significa com o mesmo salt: divida o salt:hash armazenado e reutilize o salt.
Compare com timingSafeEqual, não com ===. === para no primeiro byte diferente, então um invasor que cronometra muitas tentativas aprende quanto de um palpite estava certo. timingSafeEqual sempre leva o mesmo tempo. Ele compara dois Buffers do mesmo tamanho e lança um erro quando os tamanhos diferem.
import { timingSafeEqual } from 'node:crypto';
const expected = Buffer.from(process.env.API_KEY);
const given = Buffer.from(req.get('x-api-key') ?? '');
const ok = given.length === expected.length && timingSafeEqual(given, expected);Buffer.from(hex, 'hex') transforma o texto hexadecimal novamente em bytes.
Desafio
Fácil- Em
passwords.js, adicione e exporteverifyPassword(password, stored): verdadeiro quando a senha gerou aquele valor armazenado. - Em
server.js, adicionePOST /logincom{ username, password }: 200{ username }ou 401{ "error": "Wrong username or password" }para uma senha incorreta ou um nome desconhecido.
Cadastre ada, faça login e, em seguida, faça login com uma senha incorreta.
Experimente você mesmo
import { randomBytes, scrypt } from 'node:crypto';
import { promisify } from 'node:util';
const scryptAsync = promisify(scrypt);
// Transforma uma senha no texto que signup armazena.
export async function hashPassword(password) {
const salt = randomBytes(16).toString('hex');
const key = await scryptAsync(password, salt, 64);
return `${salt}:${key.toString('hex')}`;
}