Подтвердить что ты не робот

Пароль SALT и HASH в nodejs w/crypto

Я пытаюсь выяснить, как солить и хешировать пароль в nodejs, используя крипто-модуль. Я могу создать хешированный пароль, делая это:

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;
    next();
  });
});

Однако я смущен тем, как позже проверить пароль.

UserSchema.methods.validPassword = function(password) {    
  // need to salt and hash this password I think to compare
  // how to I get the salt?
}
4b9b3361

Ответ 1

В любом механизме сохранения (базы данных), который вы используете, вы сохраните полученный хэш вместе с солью и количеством итераций, оба из которых будут являться открытым текстом. Если каждый пароль использует различную соль (что вы должны делать), вы также должны сохранить эту информацию.

Затем вы сравните новый пароль обычного текста, хэш, который использует ту же соль (и итерации), а затем сравните последовательность байтов с сохраненной.

Чтобы сгенерировать пароль (псевдо)

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);
}

Ответ 2

На основе документации nodejs (http://nodejs.org/api/crypto.html) не похоже, что существует специальный метод, который будет проверять пароль для вы. Чтобы проверить его вручную, вам нужно будет вычислить хэш текущего предоставленного пароля и сравнить его с сохраненным для равенства. В принципе, вы сделаете то же самое с паролем вызова, который вы сделали с оригиналом, но используйте соль, хранящуюся в базе данных, вместо генерации новой, а затем сравните два хэша.

Если вы не слишком уверены в использовании встроенной крипто-библиотеки, я бы рекомендовал вместо этого использовать bcrypt. Они примерно равны на фронте безопасности, но я думаю, что bcrypt имеет более удобный интерфейс. Пример того, как его использовать (взятый непосредственно из документов bcrypt на странице, приведенной выше), будет следующим:

Создайте хэш:

var bcrypt = require('bcrypt');
var salt = bcrypt.genSaltSync(10);
var hash = bcrypt.hashSync("B4c0/\/", salt);
// Store hash in your password DB.

Чтобы проверить пароль:

// Load hash from your password DB.
bcrypt.compareSync("B4c0/\/", hash); // true
bcrypt.compareSync("not_bacon", hash); // false

Изменить для добавления:

Другим преимуществом bcrypt является то, что вывод функции genSalt содержит как хэш, так и соль в одной строке. Это означает, что вы можете сохранить только один элемент в своей базе данных вместо двух. Существует также метод, который будет генерировать соль в то же время, когда происходит хеширование, поэтому вам не нужно беспокоиться об управлении солью.

Изменить для обновления:

В ответ на комментарий Питера Лайона: вы на 100% правильны. Я предположил, что модуль bcrypt, который я рекомендовал, был реализацией javascript, и поэтому его использование асинхронно не сильно ускорило бы работу на модели с одним потоком node. Оказывается, это не так; модуль bcrypt использует собственный код С++ для его вычислений и будет работать быстрее асинхронно. Питер Лайонс прав, вы должны сначала использовать асинхронную версию метода и только при необходимости выбрать синхронный. Асинхронный метод может быть таким же медленным, как и синхронный, но синхронный всегда будет медленным.

Ответ 3

Как хранить пароль и соль в отдельных столбцах в базе данных, так и (мой предпочтительный метод), хранить свои пароли в своей базе данных в формате, совместимом с RFC 2307, раздел 5.3. Пример: {X-PBKDF2}base64salt:base64digest. Вы также можете сохранить счетчик итераций там, что позволит увеличить счетчик итераций в будущем для новых учетных записей и учетных записей, которые обновляют ваши пароли, не нарушая логинов для всех остальных.

Пример хэша из моего собственного модуля PBKDF2 для Perl выглядит как {X-PBKDF2}HMACSHA1:AAAD6A:8ODUPA==:1HSdSVVwlWSZhbPGO7GIZ4iUbrk=, который включает в себя специальный алгоритм хеширования, а также количество итераций, соль и полученный ключ.

Ответ 5

Столкнувшись с тем же вопросом, я собрал все вместе в один модуль: https://www.npmjs.org/package/password-hash-and-salt

Он использует pbkdf2 и сохраняет хэш, соль, алгоритм и итерации в одном поле. Надеюсь, что это поможет.

Ответ 6

Это модифицированная версия ответа @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'; // this could be base64, for instance

/**
 * The information about the password that is stored in the database
 */
interface PersistedPassword {
    salt: string;
    hash: string;
    iterations: number;
}

/**
 * Generates a PersistedPassword given the password provided by the user. This should be called when creating a user
 * or redefining the password
 */
export async 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) {
                reject(error);
            } else {
                accept({
                    salt,
                    hash: hash.toString(BYTE_TO_STRING_ENCODING),
                    iterations: ITERATIONS,
                });
            }
        });
    });
}

/**
 * Verifies the attempted password against the password information saved in the database. This should be called when
 * the user tries to log in.
 */
export async 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) {
                reject(error);
            } else {
                accept(persistedPassword.hash === hash.toString(BYTE_TO_STRING_ENCODING));
            }
        });
    });
}

Ответ 7

В этом сценарии участвуют два важных шага

1) Создание и сохранение пароля

Здесь вам нужно будет сделать следующее.

  • Введите пароль пользователя
  • Сгенерировать строку случайных символов (соли)
  • Объединить соль с введенным пользователем паролем
  • Хешировать объединенную строку.
  • Сохраните хэш и соль в базе данных.

2) Проверка пароля пользователя

Этот шаг потребуется для аутентификации пользователя.

  • Пользователь вводит имя пользователя/адрес электронной почты и пароль.

  • Извлеките хэш и соль на основе введенного имени пользователя

  • Объедините соль с паролем пользователя

  • Хешируйте комбинацию с тем же алгоритмом хэширования.

  • Сравните результат.

В этом руководстве содержится подробное объяснение того, как это сделать с помощью nodejs crypto. Именно то, что вы ищете. Пароли Solt Hash с использованием шифрования NodeJS