Wie vergleicht node.bcrypt.js Hash- und Klartext-Passwörter ohne Salt?

95

Vom Github :

So hacken Sie ein Passwort:

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

So überprüfen Sie ein Passwort:

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

Wie können von oben keine Salzwerte in die Vergleiche einbezogen werden? Was vermisse ich hier?

SChang
quelle

Antworten:

95

Das Salz wird in den Hash eingearbeitet (als Klartext). Die Vergleichsfunktion zieht einfach das Salz aus dem Hash und verwendet es dann, um das Passwort zu hashen und den Vergleich durchzuführen.

Rechnung
quelle
1
Ich verstehe immer noch nicht. Woher weiß es während des Vergleichs, welcher Teil des Hash das Salz ist, wenn Sie es nicht mit dem Salz versorgen?
MondayPaper
6
bcrypt ist ein Standard und verkettet das Salz immer mit dem Hash im gleichen Format. Sie geben das Salz beim Verschlüsseln an und dieses wird in den Hash aufgenommen. bcrypt kann nur Daten entschlüsseln, die ursprünglich mit bcrypt verschlüsselt wurden. Andernfalls haben Sie Recht - es gibt keine Möglichkeit zu wissen, welcher Teil der Hash und welcher Teil das Salz ist.
Bill
4
Ok, wir verstehen es: Salz wird mit dem Hasch gespeichert. bcrypt ist Open Source, das heißt, jeder weiß, wie genau es gespeichert wird. Sie wissen also, wie Sie es extrahieren oder wie Sie Hash aus einem Nur-Text-Passwort generieren. Wie hilft dies, Passwörter vor dem Scannen von Regenbogentabellen nach Hashes zu schützen, was im Grunde die Hauptidee hinter Salt ist?
Vitaliy Lebedev
13
Es spielt keine Rolle, ob der Angreifer das Salz für einen bestimmten Hash kennt, es ist kein Geheimnis. Die Verwendung eines anderen Salt für jedes Kennwort bedeutet, dass der Angreifer Hashes nicht mit gemeinsamen Werten vorberechnen kann. Mit einem anderen Salt auf jedem müssten sie alle Tabellen für jedes Passwort neu berechnen, was sie unbrauchbar macht.
Bill
3
Blick auf diese Art und Weise, macht es aus , wenn Angreifer Salz für bestimmte Benutzer in der Datenbank wie dies weiß: column_password = hash, column_salt = saltvs column_password = hash_salt. Angreifer hat immer noch die gleichen Informationen. Der springende Punkt ist, jedes Passwort so zufällig und größer zu machen, dass es unwahrscheinlich wird, dass jemand es vorberechnet hat.
Muhammad Umer
27

Ich hatte auch die gleiche Frage wie das Originalplakat und es dauerte ein bisschen, bis ich mich umgesehen und verschiedene Dinge ausprobiert hatte, um den Mechanismus zu verstehen. Wie bereits von anderen erwähnt, wird das Salz zum endgültigen Hash verkettet. Das bedeutet also ein paar Dinge:

  1. Der Algorithmus muss die Länge des Salzes kennen
  2. Muss auch die Position des Salzes in der letzten Saite kennen. zB wenn durch eine bestimmte Zahl von links oder rechts versetzt.

Diese beiden Dinge sind in der Implementierung normalerweise fest codiert, z. B. definiert die bcrypt-Implementierungsquelle für bcryptjs die Salt-Länge als 16

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

var BCRYPT_SALT_LEN = 16;

Um das Grundkonzept hinter der Idee zu veranschaulichen, wenn man es manuell machen möchte, würde es ähnlich wie das folgende aussehen. Ich empfehle nicht, solche Dinge selbst zu implementieren, wenn es Bibliotheken gibt, die Sie dazu bekommen können.

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

Da ich selbst die gleiche Frage hatte, weiß ich genau, woran Sie denken.

Sie haben ein Missverständnis zwischen "Secret Key", das in kryptografischen Algorithmen verwendet wird, und "Salt", das verwendet wird, um den Verschlüsselungsprozess zu verlangsamen und Hackern die Anwendung von Brute Force zu erschweren.

Wenn Sie das einfache Passwort und das Salt verwenden, um den Hash zu generieren, verwendet dieser Hash das Passwort selbst als geheimen Schlüssel ! Wenn Sie das nächste Mal versuchen, es mit einem einfachen Passwort zu vergleichen, muss dieses einfache Passwort genau das gleiche sein, das Sie zum Generieren des Hashs verwendet haben! Deshalb müssen Sie es nicht woanders speichern, da es vom Benutzer immer sowohl bei der Registrierung als auch bei der Anmeldung bereitgestellt wird!

Babaliaris
quelle