来自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
});
从上面来看,如何在比较中不涉及盐值?我在这里缺少什么?
答案 0 :(得分:73)
盐被合并到散列中(作为明文)。 compare函数简单地将salt从哈希中拉出,然后使用它来哈希密码并执行比较。
答案 1 :(得分:22)
我也和原版海报一样有同样的问题,看了一下,尝试了不同的东西来理解机制。正如其他人已经指出的那样,盐被连接到最终的哈希值。所以这意味着一些事情:
这两件事通常在实施例中被硬编码,例如bcryptjs的bcrypt实现源将salt长度定义为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');
}
});
}
答案 2 :(得分:1)
因为我本人也有同样的问题,所以我确切地知道您在想什么。
在"Secret Key"算法中使用的Cryptographic与用于减慢加密过程并使黑客更难使用蛮力的“ Salt”之间存在误解。
当您使用普通密码和盐生成哈希时,此哈希将密码本身用作密钥!因此,下次您尝试将其与普通密码进行比较时,该普通密码必须与用于生成哈希的密码完全相同!所以这就是为什么您不必将其存储在其他地方的原因,因为它总是由用户在注册和登录步骤中提供的!
答案 3 :(得分:1)
Bcrypt比较不带盐字符串的哈希密码和纯文本密码,因为哈希密码包含我们在哈希时创建的盐字符串。
例如:
输入此普通密码:
546456546456546456456546111
使用Bcrypt加密上述纯文本密码:
$ 2b $ 10 $ uuIKmW3Pvme9tH8qOn / H7uZqlv9ENS7zlIbkMvCSDIv7aup3WNH9W
因此,在上面的哈希密码中,存在三个用 $ 符号分隔的字段。
i)第一部分 $ 2b $ 标识所使用的bcrypt算法版本。
ii)第二部分 $ 10 $ (是成本因素)(创建盐串时只进行盐舍入。如果进行15次舍入,则值将为 $ 15 $ < / strong>
iii)第三部分是前 22 个字符(只不过是盐串) 在这种情况下
uuIKmW3Pvme9tH8qOn / H7u
其余字符串为哈希密码。 因此,基本上来说,saltedHash = salt string + hashedPassword可以防止彩虹表攻击。
答案 4 :(得分: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
答案 5 :(得分:0)
将盐合并到哈希中。比较功能只是将盐从哈希表中提取出来,然后用它来哈希密码并执行比较。
当用户登录我们的系统时,我们应该检查输入的密码是否正确。与其他会解密数据库中的密码(如果已加密)并将其与用户输入的密码进行比较的其他系统不同,我对bcrypt所做的操作(假定它实现了单向哈希)是对由数据库输入的密码进行加密。用户。为此,我将密码传递给bcrypt来计算哈希值,还将密码存储在与用户(哈希)关联的数据库中。这是因为,如前所述,bcrypt算法使用随机段(盐)来生成与密码相关的哈希。这与密码一起存储,您需要它重新计算用户输入的密码的哈希值,并最终与注册时输入的密码进行比较,看看它们是否匹配。