web-dev-qa-db-fra.com

Comment node.bcrypt.js compare-t-il les mots de passe hachés et en clair sans le sel?

De github :

Pour hacher un mot de passe:

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

Pour vérifier un mot de passe:

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

D'en haut, comment ne peut-il y avoir aucune valeur de sel dans les comparaisons? Qu'est-ce que j'oublie ici?

77
SChang

Le sel est incorporé dans le hachage (sous forme de texte en clair). La fonction de comparaison extrait simplement le sel du hachage, puis l'utilise pour hacher le mot de passe et effectuer la comparaison.

78
Bill

J'avais aussi la même question que l'affiche originale et il a fallu un peu regarder en regardant autour et essayer différentes choses pour comprendre le mécanisme. Comme cela a déjà été souligné par d'autres, le sel est concaténé au hachage final. Cela signifie donc deux ou trois choses:

  1. L'algorithme doit connaître la longueur du sel
  2. Doit également connaître la position du sel dans la chaîne finale. par exemple. si compensé par un nombre spécifique de gauche ou de droite.

Ces deux choses sont généralement codées en dur dans la mise en œuvre, par exemple la source d'implémentation de bcrypt pour bcryptjs définit la longueur du sel comme 16

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

var BCRYPT_SALT_LEN = 16;

Donc, pour illustrer le concept de base derrière l'idée si l'on voulait le faire manuellement, cela ressemblerait à ce qui suit. Je ne recommande pas d'implémenter ce genre de choses vous-même quand il y a des bibliothèques que vous pouvez obtenir pour le faire.

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');
        }
    });
}
23
Alappin