使用 Nodejs crypto 模块和 scrypt 对密码进行哈希处理
由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!
从 Node.js v10 开始,crypto 模块内置了scrypt算法的实现,可以用作密码哈希算法。据我所知,Node.js 中最先进的密码哈希和存储算法是bcrypt。bcrypt是 NPM 上非常流行的模块,每周下载量接近 50 万次。我不是安全专家,无法判断哪个更好,但如果您想使用 Scrypt 作为另一种强大的哈希算法,方法很简单:
哈希密码
Scrypt 是一种加盐哈希算法。要使用 Scrypt 对密码进行哈希处理,需要为每个哈希值创建一个唯一的盐值。
盐值应尽可能独特。建议盐值应为随机值,且长度至少为 16 字节。详情请参阅NIST SP 800-132 。
const crypto = require("crypto")
async function hash(password) {
return new Promise((resolve, reject) => {
// generate random 16 bytes long salt
const salt = crypto.randomBytes(16).toString("hex")
crypto.scrypt(password, salt, 64, (err, derivedKey) => {
if (err) reject(err);
resolve(salt + ":" + derivedKey.toString('hex'))
});
})
}
将生成的盐值与哈希值一起保存非常重要,因为如果没有盐值,就无法验证密码,而且,您可以将盐值存储在 plaintex 中。
检查密码
正如我之前所说,我们需要盐值来验证密码。盐值可以从hash函数结果中提取出来。
async function verify(password, hash) {
return new Promise((resolve, reject) => {
const [salt, key] = hash.split(":")
crypto.scrypt(password, salt, 64, (err, derivedKey) => {
if (err) reject(err);
resolve(key == derivedKey.toString('hex'))
});
})
}
综合起来
const crypto = require("crypto")
async function hash(password) {
return new Promise((resolve, reject) => {
const salt = crypto.randomBytes(8).toString("hex")
crypto.scrypt(password, salt, 64, (err, derivedKey) => {
if (err) reject(err);
resolve(salt + ":" + derivedKey.toString('hex'))
});
})
}
async function verify(password, hash) {
return new Promise((resolve, reject) => {
const [salt, key] = hash.split(":")
crypto.scrypt(password, salt, 64, (err, derivedKey) => {
if (err) reject(err);
resolve(key == derivedKey.toString('hex'))
});
})
}
(async function run () {
const password1 = await hash("123456")
const password2 = await hash("123456")
console.log("password1", await verify("123456", password1));
console.log("password2", await verify("123456", password2));
console.log("password1 == password2", password1 == password2);
})()
结果如下:
password1 true
password2 true
password1 == password2 false
从结果可以看出,使用不同的盐值对单个字符串进行哈希处理会产生不同的输出,但它们都可以得到验证。
文章来源:https://dev.to/farnabaz/hash-your-passwords-with-scrypt-using-nodejs-crypto-module-316k