发布于 2026-01-06 1 阅读
0

使用 Nodejs crypto 模块 scrypt 对密码进行哈希处理。DEV 的全球展示与讲述挑战赛,由 Mux 呈现:展示你的项目!

使用 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