Verificar una contraseña
Parte de la sección Autenticación y seguridad del Journey de Node.js de Coddy. Lección 2 de 17.
Un hash no se puede revertir, así que al iniciar sesión nunca se vuelve a leer la contraseña almacenada. Calculas el hash del intento de la misma manera y comparas las dos claves. De la misma manera significa con la misma sal: separa el salt:hash almacenado y reutiliza su sal.
Compara con timingSafeEqual, no con ===. === se detiene en el primer byte que difiere, así que un atacante que mide el tiempo de muchas respuestas averigua qué parte de una conjetura era correcta. timingSafeEqual siempre tarda lo mismo. Compara dos búferes de la misma longitud y lanza un error cuando las longitudes difieren.
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') convierte el texto hexadecimal de nuevo en bytes.
Desafío
Fácil- En
passwords.js, agrega y exportaverifyPassword(password, stored): devuelve verdadero cuando la contraseña generó ese valor almacenado. - En
server.js, agregaPOST /logincon{ username, password }: devuelve 200{ username }o 401{ "error": "Wrong username or password" }si la contraseña es incorrecta o el nombre es desconocido.
Registra a ada, inicia sesión y después inicia sesión con una contraseña incorrecta.
Pruébalo tú mismo
import { randomBytes, scrypt } from 'node:crypto';
import { promisify } from 'node:util';
const scryptAsync = promisify(scrypt);
// Convierte una contraseña en el texto que almacena signup.
export async function hashPassword(password) {
const salt = randomBytes(16).toString('hex');
const key = await scryptAsync(password, salt, 64);
return `${salt}:${key.toString('hex')}`;
}