"SALT и HASH паролей в Node.js с использованием crypto"
Проблема с валидацией пароля после хеширования в Node.js с использованием модуля crypto
Я пытаюсь реализовать механизм хеширования и соль для паролей в Node.js, используя модуль crypto
. У меня успешно получается создать хешированный пароль следующим образом:
UserSchema.pre('save', function(next) {
var user = this;
var salt = crypto.randomBytes(128).toString('base64');
crypto.pbkdf2(user.password, salt, 10000, 512, function(err, derivedKey) {
user.password = derivedKey;
user.salt = salt; // Сохраняю соль для дальнейшего использования
next();
});
});
Однако я испытываю трудности с валидацией пароля. Я не знаю, как правильно использовать соль для проверки пароля при входе. Я предполагаю, что нужно снова применить соль и хеширование к введённому паролю, но как именно мне это сделать?
Вот мой текущий метод для проверки пароля:
UserSchema.methods.validPassword = function(password) {
// здесь нужно взять соль и выполнить хеширование пароля для сравнения
// как мне получить соль?
}
Помогите, пожалуйста, понять, как правильно осуществить валидацию пароля после его хеширования.
3 ответ(ов)
В зависимости от механизма хранения данных (базы данных), который вы используете, необходимо хранить полученный хеш вместе с солью и числом итераций — все эти данные должны храниться в открытом виде. Если каждая параоль использует различную соль (что рекомендуется), важно сохранить эту информацию.
Чтобы проверить введенный пароль, вам нужно будет сравнить его с хешем: вы берете новый открытый пароль, хешируете его с использованием той же соли (и количества итераций), а затем сравниваете полученную последовательность байтов с сохраненной.
Для генерации пароля (псевдокод)
function hashPassword(password) {
var salt = crypto.randomBytes(128).toString('base64'); // Генерация соли
var iterations = 10000; // Количество итераций
var hash = pbkdf2(password, salt, iterations); // Хеширование пароля
return {
salt: salt,
hash: hash,
iterations: iterations
};
}
Для проверки пароля (псевдокод)
function isPasswordCorrect(savedHash, savedSalt, savedIterations, passwordAttempt) {
return savedHash == pbkdf2(passwordAttempt, savedSalt, savedIterations); // Сравнение хешей
}
Таким образом, убедитесь, что вы храните соль и количество итераций в открытом виде, и что каждый пароль использует уникальную соль для обеспечения большей безопасности.
Вот модифицированная версия ответа @Matthews с использованием TypeScript на вопрос о хэшировании паролей:
import * as crypto from "crypto";
const PASSWORD_LENGTH = 256; // длина генерируемого пароля
const SALT_LENGTH = 64; // длина соли
const ITERATIONS = 10000; // количество итераций
const DIGEST = "sha256"; // алгоритм хэширования
const BYTE_TO_STRING_ENCODING = "hex"; // кодировка: может быть и base64, например
/**
* Интерфейс, содержащий информацию о пароле, которая хранится в базе данных
*/
interface PersistedPassword {
salt: string;
hash: string;
iterations: number;
}
/**
* Генерирует PersistedPassword на основе пароля, предоставленного пользователем.
* Эта функция должна вызываться при создании пользователя или изменении пароля.
*/
export function generateHashPassword(
password: string
): Promise<PersistedPassword> {
return new Promise<PersistedPassword>((accept, reject) => {
const salt = crypto
.randomBytes(SALT_LENGTH)
.toString(BYTE_TO_STRING_ENCODING);
crypto.pbkdf2(
password,
salt,
ITERATIONS,
PASSWORD_LENGTH,
DIGEST,
(error, hash) => {
if (error) {
return reject(error);
}
accept({
salt,
hash: hash.toString(BYTE_TO_STRING_ENCODING),
iterations: ITERATIONS,
});
}
);
});
}
/**
* Проверяет, соответствует ли введённый пароль информации о пароле, сохраненной в
* базе данных. Эта функция должна вызываться, когда пользователь пытается войти в систему.
*/
export function verifyPassword(
persistedPassword: PersistedPassword,
passwordAttempt: string
): Promise<boolean> {
return new Promise<boolean>((accept, reject) => {
crypto.pbkdf2(
passwordAttempt,
persistedPassword.salt,
persistedPassword.iterations,
PASSWORD_LENGTH,
DIGEST,
(error, hash) => {
if (error) {
return reject(error);
}
accept(
persistedPassword.hash === hash.toString(BYTE_TO_STRING_ENCODING)
);
}
);
});
}
В этом коде реализованы функции для генерации и проверки паролей с использованием алгоритма PBKDF2 и SHA-256. Первая функция generateHashPassword
генерирует соль и хэш для заданного пароля, а вторая функция verifyPassword
проверяет, соответствует ли введённый пароль сохранённым данным. Убедитесь, что вы используете безопасные методы при хранении паролей в вашей базе данных.
Столкнувшись с такой же задачей, я собрал все в одном модуле: https://www.npmjs.org/package/password-hash-and-salt.
Он использует pbkdf2 и хранит хеш, соль, алгоритм и количество итераций в одном поле. Надеюсь, это поможет!
Как узнать версию установленного npm пакета?
Как в Node.js "подключить" функции из других файлов?
Как задать переменные окружения из файла package.json?
Самый быстрый способ скопировать файл в Node.js
Как остановить Babel от трансформации 'this' в 'undefined' и добавления "use strict"