密码的 Node.js 散列

Posted

技术标签:

【中文标题】密码的 Node.js 散列【英文标题】:Node.js hashing of passwords 【发布时间】:2012-12-10 12:59:21 【问题描述】:

我目前正在使用以下方法对密码进行哈希处理:

var pass_shasum = crypto.createHash('sha256').update(req.body.password).digest('hex');

您能否提出改进建议以使项目更安全?

【问题讨论】:

无盐 SHA 不安全。使用 bcrypt。 感谢您的评论,我会检查一下。 codahale.com/how-to-safely-store-a-password 每个开发者都应该阅读的关于保护密码安全的好文章:crackstation.net/hashing-security.htm 【参考方案1】:

我使用以下代码对密码进行加盐和哈希处理。

var bcrypt = require('bcrypt');

exports.cryptPassword = function(password, callback) 
   bcrypt.genSalt(10, function(err, salt) 
    if (err) 
      return callback(err);

    bcrypt.hash(password, salt, function(err, hash) 
      return callback(err, hash);
    );
  );
;

exports.comparePassword = function(plainPass, hashword, callback) 
   bcrypt.compare(plainPass, hashword, function(err, isPasswordMatch)    
       return err == null ?
           callback(null, isPasswordMatch) :
           callback(err);
   );
;

【讨论】:

return 后不要使用 else,它只是没有意义。干杯! 您能否添加一个指向您正在使用的 bcrypt 库的链接(如果可能,请使用 github)?谢谢。 @Tadej 很久以前了,但我想是:npmjs.com/package/bcrypt 谢谢。我什至没有检查日期。对不起。 :// 有两个模块 bcrypt 和 bcryptjs 用于此目的,如果有人能详细介绍这两个模块,那就太好了。【参考方案2】:

bcrypt 也可以同步调用。示例咖啡脚本:

bcrypt = require('bcrypt')

encryptionUtil = 
    encryptPassword: (password, salt) ->
        salt ?= bcrypt.genSaltSync()
        encryptedPassword = bcrypt.hashSync(password, salt)
        salt, encryptedPassword

    comparePassword: (password, salt, encryptedPasswordToCompareTo) ->
        encryptedPassword = @encryptPassword(password, salt)
        encryptedPassword == encryptedPasswordToCompareTo

module.exports = encryptionUtil

【讨论】:

【参考方案3】:

节点也有 bcrypt-nodejs 模块。 https://github.com/shaneGirish/bcrypt-nodejs。

之前我使用了这里已经提到的 bcrypt 模块,但是在 win7 x64 上遇到了问题。另一方面,bcrypt-nodejs 是 bcrypt 的纯 JS 实现,完全没有任何依赖关系。

【讨论】:

会很好,但不再维护了。【参考方案4】:

bcrypt 与打字稿

npm i bcrypt
npm i -D @types/bcrypt
 import * as bcrypt from 'bcrypt';

export const Encrypt = 

    cryptPassword: (password: string) =>
        bcrypt.genSalt(10)
        .then((salt => bcrypt.hash(password, salt)))
        .then(hash => hash),
    
        comparePassword: (password: string, hashPassword: string) =>
            bcrypt.compare(password, hashPassword)
            .then(resp => resp)
    
    

示例:加密

const myEncryptPassword = await Encrypt.cryptPassword(password);

示例:比较

const myBoolean = await Encrypt.comparePassword(password, passwordHash);

【讨论】:

【参考方案5】:

您可以使用 bcrypt-js 包对密码进行加密。

    试试 npm i bcryptjs var bcrypt = require('bcryptjs') 在顶部。 散列密码:
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
);

您可以访问https://www.npmjs.com/package/bcryptjs 了解有关 bcryptjs 的更多信息。

【讨论】:

【参考方案6】:

尝试使用 Bcrypt,它使用哈希来保护密码。

bcrypt.hash(req.body.password, salt, (err, encrypted) => 
    user.password = encrypted
    next()
)

其中 salt 是指定散列强度的成本值。 登录时,使用 bcrypt.compare 方法比较密码:

 bcrypt.compare(password, user.password, (err, same) => 
      if (same) 
           req.session.userId = user._id
           res.redirect('/bloglist')
       else 
           res.end('pass wrong')
      
 )

有关更多信息,请参阅此博客:https://medium.com/@nitinmanocha16/bcrypt-and-nodejs-e00a0d1df91f

【讨论】:

【参考方案7】:

Bcrypt 是个不错的选择,但是there are a few gotchas:

    它将截断NUL 字节。 它将在 72 个字符后截断。如果您使用密码短语,这可能会意外削弱您的密码。

截至 2019 年 10 月,Argon2id 是最佳选择。

与 Argon2id 交互的首选方式是通过 libsodium(一个提供许多功能的密码库)。有多种绑定可供选择,但最简单的可能是sodium-plus。

const SodiumPlus = require('sodium-plus').SodiumPlus;
let sodium;
(async function()
    if (!sodium) sodium = await SodiumPlus.auto(); // Autoload the backend

    let password = 'Your example password goes here. Provided by the user.';

    // Hashing...
    let hash = await sodium.crypto_pwhash_str(
        password,
        sodium.CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE,
        sodium.CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE
    );
    // You can safely store hash in a database.

    // Checking that a stored hash is still up to snuff...
    let stale = await sodium.crypto_pwhash_str_needs_rehash(
        hash,
        sodium.CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE,
        sodium.CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE
    );
    if (stale) 
        // Rehash password, update database
    

    // Password verification
    let valid = await sodium.crypto_pwhash_str_verify(password, hash);
    if (valid) 
        // Proceed...
    
)();

Github 上的 documentation for sodium-plus 包括密码哈希和存储。

【讨论】:

以上是关于密码的 Node.js 散列的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法将我的 MySQL 密码安全地存储在 Node.JS 中?

Node.js 密码重置

如何使用 Passport.js 在 Node.js 中重置/更改密码?

Node.JS webapp:身份验证、创建帐户、忘记密码和更改密码

node.js 哈希字符串?

在 node.js 中生成受密码保护的 ZIP 文件