Проверка пароля
Часть раздела Аутентификация и безопасность путешествия по Node.js на Coddy. Урок 2 из 17.
Хеш нельзя обратить, поэтому при входе сохранённый пароль никогда не считывается обратно. Хешируй введённый пароль тем же способом и сравнивай два ключа. Тот же способ означает ту же соль: раздели сохранённое значение salt:hash и повторно используй его соль.
Сравнивай с помощью timingSafeEqual, а не ===. === останавливается на первом различающемся байте, поэтому злоумышленник, замеряя время для множества ответов, узнаёт, насколько верной была догадка. timingSafeEqual всегда выполняется за одно и то же время. Она сравнивает два буфера одинаковой длины и выдаёт ошибку, если их длины различаются.
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') преобразует шестнадцатеричный текст обратно в байты.
Задание
Легко- В
passwords.jsдобавь и экспортируйverifyPassword(password, stored): функция возвращает true, если пароль соответствует сохранённому значению. - В
server.jsдобавьPOST /loginс{ username, password }: ответ 200{ username }или ответ 401{ "error": "Wrong username or password" }при неверном пароле или неизвестном имени.
Зарегистрируй ada, войди в систему, а затем попробуй войти с неверным паролем.
Попробуйте сами
import { randomBytes, scrypt } from 'node:crypto';
import { promisify } from 'node:util';
const scryptAsync = promisify(scrypt);
// Преобразует пароль в текст, который сохраняет signup.
export async function hashPassword(password) {
const salt = randomBytes(16).toString('hex');
const key = await scryptAsync(password, salt, 64);
return `${salt}:${key.toString('hex')}`;
}