Як node.bcrypt.js порівнює хешовані та відкритий текст паролів без солі?


95

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

Зверху, як не може бути ніяких значень солі, залучених до порівнянь? Чого мені тут не вистачає?

Відповіді:


98

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


1
Я досі не розумію. Під час порівняння, як він знає, яка частина хешу є сіллю, якщо ви не надаєте їй сіль?
Понеділок Папір

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

6
Гаразд, ми розуміємо: сіль зберігається разом з хешем. bcrypt є відкритим кодом, тож це означає, що всі знають, як саме він його зберігає. Отже, ви знаєте, як його витягти або як генерувати хеш із простого тексту пароля. Як це допомагає захистити паролі від сканування райдужних таблиць на наявність хешів, що в основному є основною ідеєю солі?
Віталій Лебедєв

13
Неважливо, чи знає зловмисник сіль для будь-якого конкретного хешу, це не секрет. Використання різної солі для кожного пароля означає, що зловмисник не може попередньо обчислити хеші, використовуючи загальні значення. Маючи різну сіль на кожному, їм потрібно буде перерахувати будь-які таблиці для кожного пароля, що робить їх марними.
Білл

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

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

Наприклад :

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

546456546456546456456546111

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

$ 2b $ 10 $ uuIKmW3Pvme9tH8qOn / H7uZqlv9ENS7zlIbkMvCSDIv7aup3WNH9W

Отже, у наведеному вище хешованому паролі є три поля, розділені символом $ .

i) Перша частина $ 2b $ визначає використовувану версію алгоритму bcrypt.

ii) Друга частина $ 10 $ 10 - це фактор витрат (нічого, крім сольових раундів під час створення соляної нитки. Якщо ми зробимо 15 раундів, тоді значення буде 15 $

iii) Третя частина - це перші 22 символи (це не що інше, як соляна струна). У цьому випадку це так

uuIKmW3Pvme9tH8qOn / H7u

Залишився рядок - хешований пароль. Отже, в основному, saltedHash = соляний рядок + hashedPassword для захисту від атак на райдужний стіл.


0

Оскільки й у мене було таке саме запитання, я точно знаю, про що ви думаєте.

У вас неправильне уявлення між "Секретним ключем", який використовується в криптографічних алгоритмах, і "Соллю", який використовується для уповільнення процесу шифрування та ускладнення хакерами застосування грубої сили.

Коли ви використовуєте звичайний пароль і сіль для створення хешу, цей хеш використовує як секретний ключ сам пароль ! Отже, наступного разу, коли ви спробуєте порівняти його з простим паролем, цей звичайний пароль повинен бути точно таким самим, який ви використовували для створення хешу! Ось чому вам не потрібно зберігати його десь в іншому місці, оскільки він завжди надається користувачем як на етапі реєстрації, так і на вході!


0

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

Коли користувач увійде в нашу систему, ми повинні перевірити правильність введеного пароля чи ні. На відміну від інших систем, які розшифровують пароль у базі даних (якщо він зашифрований) і порівнює його з паролем, введеним користувачем, те, що я роблю з bcrypt (за умови реалізації одностороннього хешування), шифрує той, який вводить користувач. Для цього я передам пароль bcrypt для обчислення хешу, а також пароль, що зберігається в базі даних, пов’язаній з користувачем (хеш). Це пояснюється тим, що, як уже згадувалося раніше, алгоритм bcrypt використовував випадковий сегмент (сіль) для генерування хешу, пов'язаного з паролем. Це було збережено разом із паролем, і він вам потрібен, щоб перерахувати хеш пароля, введеного користувачем, і, нарешті, порівняти з тим, який був введений під час реєстрації, і перевірити, чи вони збігаються.


0

Це просто рядок фіксованої довжини.

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.