使用内置“crypto”在nodejs中进行密码散列

dis*_*ted 9 javascript cryptography password-hash node.js scrypt

仅使用内置crypto模块在 Node.js 中实现密码哈希和验证的最佳方法是什么?基本上需要什么:

function passwordHash(password) {} // => passwordHash
function passwordVerify(password, passwordHash) {} // => boolean
Run Code Online (Sandbox Code Playgroud)

人们通常使用bcrypt或其他第三方库来实现此目的。我想知道内置crypto模块是否足够大,至少可以满足所有基本需求?

似乎scrypt()是实现此目的的合适人选,但没有经过验证的对应者,似乎没有人关心

Yil*_*maz 18

import { scrypt, randomBytes, timingSafeEqual } from "crypto";
import { promisify } from "util";

// scrypt is callback based so with promisify we can await it
const scryptAsync = promisify(scrypt);
Run Code Online (Sandbox Code Playgroud)

散列过程有两种方法。第一种方法,您对密码进行哈希处理,第二种方法,您需要将新的登录密码与存储的密码进行比较。我用打字稿详细写下所有内容

export class Password {

  static async hashPassword(password: string) {
    const salt = randomBytes(16).toString("hex");
    const buf = (await scryptAsync(password, salt, 64)) as Buffer;
    return `${buf.toString("hex")}.${salt}`;
  }

  static async comparePassword(
    storedPassword: string,
    suppliedPassword: string
  ): Promise<boolean> {
    // split() returns array
    const [hashedPassword, salt] = storedPassword.split(".");
    // we need to pass buffer values to timingSafeEqual
    const hashedPasswordBuf = Buffer.from(hashedPassword, "hex");
    // we hash the new sign-in password
    const suppliedPasswordBuf = (await scryptAsync(suppliedPassword, salt, 64)) as Buffer;
    // compare the new supplied password with the stored hashed password
    return timingSafeEqual(hashedPasswordBuf, suppliedPasswordBuf);
  }
}
Run Code Online (Sandbox Code Playgroud)

测试一下:

Password.hashPassword("123dafdas")
  .then((res) => Password.comparePassword(res, "123edafdas"))
  .then((res) => console.log(res));
Run Code Online (Sandbox Code Playgroud)

  • 您可能想使用“crypto.timingSafeEqual”进行比较 (4认同)
  • 那不应该是“randomBytes(16)”,而不是“8”吗?甚至 Node 官方文档本身也推荐使用 16 字节(最小)的 salt。 (3认同)

Pra*_*ddy 0

const password = "my_password"; 

// Creating a unique salt for a particular user
const salt = crypto.randomBytes(16).toString('hex'); 
  
// Hash the salt and password with 1000 iterations, 64 length and sha512 digest 
const hash = crypto.pbkdf2Sync(password, salt, 1000, 64, 'sha512').toString('hex');
Run Code Online (Sandbox Code Playgroud)

将用户的salt和存储在数据库中。hash

const re_entered_password = "my_password";

// To verify the same - salt (stored in DB) with same other parameters used while creating hash (1000 iterations, 64 length and sha512 digest)
const newHash = crypto.pbkdf2Sync(re_entered_password, salt, 1000, 64, 'sha512').toString('hex');

// check if hash (stored in DB) and newly generated hash (newHash) are the same
hash === newHash;
Run Code Online (Sandbox Code Playgroud)