带有加密的 nodejs 中的 SALT 和 HASH 密码
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17201450/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
SALT and HASH password in nodejs w/ crypto
提问by lostintranslation
I am trying to figure out how to salt and hash a password in nodejs using the crypto module. I am able to create the hashed password doing this:
我想弄清楚如何使用加密模块在 nodejs 中对密码进行加盐和散列。我能够创建哈希密码这样做:
UserSchema.pre('save', function(next) {
var user = this;
var salt = crypto.randomBytes(128).toString('base64');
crypto.pbkdf2(user.password, salt, 10000, 512, function(err, derivedKey) {
user.password = derivedKey;
next();
});
});
However I am confused about how to later validate the password.
但是,我对以后如何验证密码感到困惑。
UserSchema.methods.validPassword = function(password) {
// need to salt and hash this password I think to compare
// how to I get the salt?
}
回答by Matthew
In whatever persistence mechanism (database) you're using, you would store the resulting hash alongside the salt and number of iterations, both of which would be plaintext. If each password uses different salt (which you should do), you must also save that information.
在您使用的任何持久性机制(数据库)中,您都可以将结果散列与盐和迭代次数一起存储,这两者都是明文。如果每个密码使用不同的盐(您应该这样做),您还必须保存该信息。
You would then compare the new plain text password, hash that using the same salt (and iterations), then compare the byte sequence with the stored one.
然后,您将比较新的纯文本密码,使用相同的盐(和迭代)对其进行散列,然后将字节序列与存储的进行比较。
To generate the password (pseudo)
生成密码(伪)
function hashPassword(password) {
var salt = crypto.randomBytes(128).toString('base64');
var iterations = 10000;
var hash = pbkdf2(password, salt, iterations);
return {
salt: salt,
hash: hash,
iterations: iterations
};
}
To validate password (pseudo)
验证密码(伪)
function isPasswordCorrect(savedHash, savedSalt, savedIterations, passwordAttempt) {
return savedHash == pbkdf2(passwordAttempt, savedSalt, savedIterations);
}
回答by TwentyMiles
Based on the nodejs documentation (http://nodejs.org/api/crypto.html), it doesn't look like there is a specific method that will validate a password for you. To validate it manually, you will need to compute the hash of the currently provided password and compare it to the stored one for equality. Basically, you will do the same thing with the challenge password that you did with the original, but use the salt stored in the database instead of generating a new one, and then compare the two hashes.
根据 nodejs 文档 ( http://nodejs.org/api/crypto.html),看起来没有一种特定的方法可以为您验证密码。要手动验证它,您需要计算当前提供的密码的哈希值并将其与存储的密码进行比较以确保相等性。基本上,您将对挑战密码执行与原始密码相同的操作,但使用存储在数据库中的盐而不是生成新的盐,然后比较两个哈希值。
If you aren't too committed to using the built in crypto library, I might recommend using bcryptinstead. The two are about equal on the security front, but I think bcrypt has a more user-friendly interface. An example of how to use it (taken directly from the bcrypt docs on the page linked above) would be this:
如果您不太愿意使用内置的加密库,我可能会建议您改用bcrypt。两者在安全性方面大致相同,但我认为 bcrypt 具有更用户友好的界面。如何使用它的一个例子(直接取自上面链接页面上的 bcrypt 文档)是这样的:
Create a hash:
创建哈希:
var bcrypt = require('bcrypt');
var salt = bcrypt.genSaltSync(10);
var hash = bcrypt.hashSync("B4c0/\/", salt);
// Store hash in your password DB.
To check a password:
要检查密码:
// Load hash from your password DB.
bcrypt.compareSync("B4c0/\/", hash); // true
bcrypt.compareSync("not_bacon", hash); // false
Edit to add:
编辑添加:
Another advantage of bcrypt is that the output of the genSalt function contains both the hash and the salt in one string. This means that you can store just the single item in your database, instead of two. There is also a method provided that will generate a salt at the same time that the hashing occurs, so you don't have to worry about managing the salt at all.
bcrypt 的另一个优点是genSalt 函数的输出在一个字符串中同时包含哈希值和盐值。这意味着您可以只在数据库中存储单个项目,而不是两个。还提供了一种方法,可以在散列发生的同时生成盐,因此您完全不必担心管理盐。
Edit to update:
编辑更新:
In response to the comment from Peter Lyons: you're 100% correct. I had assumed that the bcrypt module that I had recommended was a javascript implementation, and therefor using it asynchronously wouldn't really speed things up on node's single threaded model. It turns out that this is not the case; the bcrypt module uses native c++ code for it's computations and will run faster asynchronously. Peter Lyons is right, you should use the asynchronous version of the method first and only pick the synchronous one when necessary. The asynchronous method mightbe as slow as the synchronous one, but the synchronous one will alwaysbe slow.
回应 Peter Lyons 的评论:您 100% 正确。我假设我推荐的 bcrypt 模块是一个 javascript 实现,因此异步使用它不会真正加快节点单线程模型的速度。事实证明,情况并非如此。bcrypt 模块使用本机 C++ 代码进行计算,并且异步运行速度更快。Peter Lyons 是对的,您应该首先使用该方法的异步版本,只有在必要时才选择同步版本。异步方法可能和同步方法一样慢,但同步方法总是很慢。
回答by hobbs
Either store password and salt in separate columns in your database, or (my preferred method), store your passwords in your database in a format that's compatible with RFC 2307section 5.3. An example would be {X-PBKDF2}base64salt:base64digest. You could also store your iteration count in there, which allows you to increase the iteration count in the future for new accounts and accounts that update your passwords, without breaking logins for everyone else.
将密码和盐存储在数据库中的单独列中,或者(我的首选方法)以与RFC 2307第 5.3 节兼容的格式将密码存储在数据库中。一个例子是{X-PBKDF2}base64salt:base64digest。您还可以在其中存储您的迭代计数,这样您就可以在未来为新帐户和更新密码的帐户增加迭代计数,而不会中断其他人的登录。
An example hash from my own PBKDF2 module for Perllooks like{X-PBKDF2}HMACSHA1:AAAD6A:8ODUPA==:1HSdSVVwlWSZhbPGO7GIZ4iUbrk=which includes the specific hash algorithm used, as well as the number of iterations, the salt, and the resulting key.
来自我自己的 Perl PBKDF2 模块的示例散列看起来像{X-PBKDF2}HMACSHA1:AAAD6A:8ODUPA==:1HSdSVVwlWSZhbPGO7GIZ4iUbrk=它包括使用的特定散列算法,以及迭代次数、salt 和结果密钥。
回答by florian
Faced with the same question I brought everything together into one module: https://www.npmjs.org/package/password-hash-and-salt
面对同样的问题,我将所有内容整合到一个模块中:https: //www.npmjs.org/package/password-hash-and-salt
It uses pbkdf2 and stores hash, salt, algorithm, and iterations in a single field. Hope it helps.
它使用 pbkdf2 并将哈希、盐、算法和迭代存储在单个字段中。希望能帮助到你。
回答by André Pena
This is a modified version of @Matthews answer, using TypeScript
这是@Matthews 答案的修改版本,使用 TypeScript
import * as crypto from 'crypto';
const PASSWORD_LENGTH = 256;
const SALT_LENGTH = 64;
const ITERATIONS = 10000;
const DIGEST = 'sha256';
const BYTE_TO_STRING_ENCODING = 'hex'; // this could be base64, for instance
/**
* The information about the password that is stored in the database
*/
interface PersistedPassword {
salt: string;
hash: string;
iterations: number;
}
/**
* Generates a PersistedPassword given the password provided by the user. This should be called when creating a user
* or redefining the password
*/
export async function generateHashPassword(password: string): Promise<PersistedPassword> {
return new Promise<PersistedPassword>((accept, reject) => {
const salt = crypto.randomBytes(SALT_LENGTH).toString(BYTE_TO_STRING_ENCODING);
crypto.pbkdf2(password, salt, ITERATIONS, PASSWORD_LENGTH, DIGEST, (error, hash) => {
if (error) {
reject(error);
} else {
accept({
salt,
hash: hash.toString(BYTE_TO_STRING_ENCODING),
iterations: ITERATIONS,
});
}
});
});
}
/**
* Verifies the attempted password against the password information saved in the database. This should be called when
* the user tries to log in.
*/
export async function verifyPassword(persistedPassword: PersistedPassword, passwordAttempt: string): Promise<boolean> {
return new Promise<boolean>((accept, reject) => {
crypto.pbkdf2(passwordAttempt, persistedPassword.salt, persistedPassword.iterations, PASSWORD_LENGTH, DIGEST, (error, hash) => {
if (error) {
reject(error);
} else {
accept(persistedPassword.hash === hash.toString(BYTE_TO_STRING_ENCODING));
}
});
});
}
回答by Saransh Mohapatra
I think this tutorial would be most apt for you. Just go through it, its the best I have found yet. Passport Tutorial with Node.js and Crypto
我认为本教程最适合您。只是通过它,它是我发现的最好的。 使用 Node.js 和 Crypto 的 Passport 教程
Hope You Find it helpful.
希望你觉得它有帮助。
回答by rahil471
There are two major steps involved in this scenario
这个场景有两个主要步骤
1) Creating and Storing password
1) 创建和存储密码
Here you will have to do the following.
在这里,您必须执行以下操作。
- Take the user password
- Generate a string of random chars (salt)
- Combine the salt with the user entered password
- Hash the combined string.
- Store the hash and the salt in the database.
- 获取用户密码
- 生成一串随机字符(盐)
- 将盐与用户输入的密码结合起来
- 散列组合字符串。
- 将哈希值和盐值存储在数据库中。
2) Validating user password
2) 验证用户密码
This step would be required to authenticate the user.
需要此步骤来验证用户。
The user will enter the username/email and the password.
Fetch the hash and the salt based on the username entered
Combine the salt with the user password
Hash the combination with the same hashing algorithm.
Compare the result.
用户将输入用户名/电子邮件和密码。
根据输入的用户名获取哈希值和盐值
将盐与用户密码结合
使用相同的散列算法对组合进行散列。
比较结果。
This tutorial has a detailed explaination on how to do it with nodejs crypto. Exactly what you are looking for. Salt Hash passwords using NodeJS crypto
本教程详细解释了如何使用 nodejs 加密。正是您正在寻找的。 使用 NodeJS 加密的 Salt Hash 密码

