Как node.bcrypt.js сравнивает хешированные пароли и пароли с открытым текстом без соли?


96

Из github :

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

var bcrypt = require('bcrypt');
bcrypt.genSalt(10, function(err, salt) {
    bcrypt.hash("B4c0/\/", salt, function(err, hash) {
        // Store hash in your password DB.
    });
});

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

// Load hash from your password DB.
bcrypt.compare("B4c0/\/", hash, function(err, res) {
    // res == true
});
bcrypt.compare("not_bacon", hash, function(err, res) {
    // res = false
});

Сверху, как могут не участвовать в сравнении значения соли? Что мне здесь не хватает?

Ответы:


99

Соль включается в хеш (в виде открытого текста). Функция сравнения просто извлекает соль из хеша, а затем использует ее для хеширования пароля и выполнения сравнения.


1
Я все еще не понимаю. Как во время сравнения узнать, какая часть хеша является солью, если вы не добавляете ей соль?
MondayPaper

7
bcrypt является стандартным и всегда объединяет соль с хешем в том же формате. Вы предоставляете соль при шифровании, и она включается в хеш. bcrypt сможет расшифровать только данные, которые были изначально зашифрованы с помощью bcrypt, в противном случае вы правы - у него не будет возможности узнать, какая часть является хешем, а какая - солью.
Билл

6
Хорошо, получаем: соль хранится вместе с хешем. bcrypt - это открытый исходный код, поэтому каждый знает, как именно он его хранит. Итак, вы знаете, как его извлечь или как сгенерировать хэш из простого текстового пароля. Как это помогает защитить пароли от сканирования радужных таблиц на предмет хэшей, что, по сути, является основной идеей соли?
Виталий Лебедев

13
Неважно, знает ли злоумышленник соль для какого-либо конкретного хэша, это не секрет. Использование разной соли для каждого пароля означает, что злоумышленник не может предварительно вычислить хэши с использованием общих значений. Имея различную соль для каждого из них, им придется пересчитывать любые таблицы для каждого пароля, что делает их бесполезными.
Bill

3
взгляд на этом пути, это имеет значение , если злоумышленник знает , соль для определенного пользователя в базе данных , как это: column_password = hash, column_salt = saltпротив column_password = hash_salt. у злоумышленника все еще есть та же информация. Суть в том, чтобы сделать каждый пароль настолько случайным и большим, что маловероятно, что кто-то его вычислил заранее.
Мухаммад Умер

27

У меня был тот же вопрос, что и у оригинального плаката, и мне потребовалось немного осмотреться и попробовать разные вещи, чтобы понять механизм. Как уже отмечалось другими, соль присоединяется к окончательному хешу. Это означает несколько вещей:

  1. Алгоритм должен знать длину соли
  2. Также необходимо знать положение соли в последней строке. например, если смещение на определенное число слева или справа.

Эти две вещи обычно жестко закодированы в реализации, например, источник реализации bcrypt для bcryptjs определяет длину соли как 16

/**
* @type {number}
* @const
* @private
*/

var BCRYPT_SALT_LEN = 16;

Итак, чтобы проиллюстрировать основную концепцию идеи, если кто-то хочет сделать это вручную, это будет выглядеть примерно так, как показано ниже. Я не рекомендую реализовывать подобные вещи самостоятельно, когда есть библиотеки, которые вы можете использовать для этого.

var salt_length = 16;
var salt_offset = 0;

var genSalt = function(callback)
{
    var alphaNum = '0123456789abcdefghijklmnopqurstuvwxyzABCDEFGHIJKLMNOPQURSTUVWXYZ';
    var salt = '';
    for (var i = 0; i < salt_length; i++) {
        var j = Math.floor(Math.random() * alphaNum.length);
        salt += alphaNum[j];
    }
    callback(salt);
}

// cryptographic hash function of your choice e.g. shar2
// preferably included from an External Library (dont reinvent the wheel)
var shar2 = function(str) {
    // shar2 logic here 
    // return hashed string;
}

var hash = function(passwordText, callback)
{
    var passwordHash = null;
    genSalt(function(salt){
        passwordHash = salt + shar2(passwordText + salt);
    });

    callback(null, passwordHash);
}

var compare = function(passwordText, passwordHash, callback)
{
    var salt = passwordHash.substr(salt_offset, salt_length);
    validatedHash = salt + shar2(passwordText + salt);

    callback(passwordHash === validatedHash);   
}

// sample usage
var encryptPassword = function(user)
{
    // user is an object with fields like username, pass, email
    hash(user.pass, function(err, passwordHash){
        // use the hashed password here
        user.pass = passwordHash;
    });

    return user;
}

var checkPassword = function(passwordText, user)
{
    // user has been returned from database with a hashed password
    compare(passwordText, user.pass, function(result){
        // result will be true if the two are equal
        if (result){
            // succeeded
            console.log('Correct Password');
        }
        else {
            // failed
            console.log('Incorrect Password');
        }
    });
}

1

Поскольку у меня самого был такой же вопрос, я точно знаю, о чем вы думаете.

У вас есть неправильное представление между «секретным ключом», который используется в криптографических алгоритмах, и «солью», которая используется для замедления процесса шифрования и усложнения хакерам использования грубой силы.

Когда вы используете простой пароль и соль для генерации хэша, этот хеш использует в качестве секретного ключа сам пароль ! Поэтому в следующий раз, когда вы попытаетесь сравнить его с простым паролем, этот простой пароль должен быть точно таким же, который вы использовали для генерации хэша! Вот почему вам не нужно хранить его где-то еще, потому что он всегда предоставляется пользователем как при регистрации, так и при входе в систему!


1

Bcrypt сравнивает хешированные пароли и пароли с открытым текстом без солтной строки, потому что хешированный пароль содержит солтную строку, которую мы создали во время хеширования.

Например :

Возьмите этот простой пароль:

546456546456546456456546111

Хешированный пароль указанного выше простого текста с использованием Bcrypt:

$ 2 млрд $ 10 $ uuIKmW3Pvme9tH8qOn / H7uZqlv9ENS7zlIbkMvCSDIv7aup3WNH9W

Итак, в хешированном пароле выше есть три поля, разделенных символом $ .

i) Первая часть $ 2b $ определяет используемую версию алгоритма bcrypt.

ii) Вторая часть 10 долларов 10 долларов - фактор стоимости (ничего, кроме раундов соли, пока мы создаем цепочку соли. Если мы сделаем 15 раундов, то стоимость будет 15 долларов.

iii) Третья часть - первые 22 символа (это не что иное, как строка соли). В данном случае это

uuIKmW3Pvme9tH8qOn / H7u

Оставшаяся строка - это хешированный пароль. По сути, saltedHash = salt string + hashedPassword для защиты от атак радужной таблицы.


1

Это просто строка фиксированной длины.

console.log("");
var salt = bcrypt.genSaltSync(10);
console.log(salt);
hash = bcrypt.hashSync("foobar", salt);
console.log(hash);

console.log("");
var salt = bcrypt.genSaltSync(10);
console.log(salt);
hash = bcrypt.hashSync("foobar", salt);
console.log(hash);

console.log("");
var salt = bcrypt.genSaltSync(10);
console.log(salt);
hash = bcrypt.hashSync("foobar", salt);
console.log(hash);
$2a$10$onmcKV.USxnoQAsQwBFB3e
$2a$10$onmcKV.USxnoQAsQwBFB3eytL3UZvZ5v/SudaWyaB9Vuq9buUqGO2

$2a$10$mwQfdyVS9dsO4SuxoR5Ime
$2a$10$mwQfdyVS9dsO4SuxoR5ImeG7atz7RXGRXb.c0VHp5zSn1N2VOA.Vq

$2a$10$uVUuJr6LryjchhKEg6PH7u
$2a$10$uVUuJr6LryjchhKEg6PH7unTw8aJGK0i3266c5kqDBLJkf80RHEpq

$2a$10$Y.upG5/54zvJyZacRxP17O
$2a$10$Y.upG5/54zvJyZacRxP17OH60BC0hQRMNfQjJxSWE77fyBrbzalmS

0

Соль включается в хэш. Функция сравнения просто извлекает соль из хеша, а затем использует ее для хеширования пароля и выполнения сравнения.

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.