nodejs中使用bcrypt加密

bcrypt算法简介

  1. bcrypt算法相对来说是运算比较慢的算法,在密码学界有句常话:越慢的算法越安全。算法越算,黑客破解成本越高.通过salt和const这两个值来减缓加密过程,ta的加密时间(百ms级)远远超过md5(大概1ms左右)。对于计算机来说,Bcrypt 的计算速度很慢,但是对于用户来说,这个过程不算慢。bcrypt是单向的,而且经过salt和cost的处理,使其受rainbow攻击破解的概率大大降低,同时破解的难度也提升不少,相对于MD5等加密方式更加安全,而且使用也比较简单.
  2. bcrypt加密后的字符串形如: 2a 10 asdjflkaydgigadfahgl.asdfaoygoqhgasldhf 是分割符,无意义;2a是bcrypt加密版本号;10是cost的值;而后的前22位是salt值;再然后的字符串就是密码的密文了;这里的const值即下面代码中的saltRounds,生成salt的迭代次数,默认值是10,推荐值12。

使用npm bcrypt模块的两种方式:

sync同步写法(同步写起来简单,没太大影响)
//引入bcrypt模块
var bcrypt = require('bcrypt');

//POST /signup用户注册
router.post('/', checkNotLogin, function(req, res, next){
    let password = req.fields.password   //获取注册页面上表单输入的密码

    //生成salt的迭代次数
    const saltRounds = 10;
    //随机生成salt
    const salt = bcrypt.genSaltSync(saltRounds);
    //获取hash值
    var hash = bcrypt.hashSync(password, salt);
     //把hash值赋值给password变量
    password = hash;

    storeUInfo();
    //存储用户信息
    function storeUInfo(){
        let user = {
            name: name,
            password: password,     //把加密后的密码存入数据库
            gender: gender,
            avatar: avatar,
            bio: bio
        }
        //用户信息写入数据库
        UserModel.create(user)
            .then(function(result){
                //此时user是插入mongodb后的值,包含_id
                user = result.ops[0];
                //删除密码这种敏感信息,将用户信息存入session
                delete user.password
                //注册成功后跳转到首页
                res.redirect('/posts')
            })
            .catch(function(e){
                //用户名被占用则跳回注册页,而不是错误页
                if(e.message.match('duplicate key')){
                    req.flash('error','用户名已被占用')
                    return res.redirect('/signup')
                }
                next(e)
            })
} 


//POST /signin  用户登录
router.post('/', checkNotLogin, function(req, res, next){
    const password = req.fields.password  //获取登录页面上表单输入的密码

    UserModel.getUserByName(name)
    .then(function(user){
        //检查数据库里的密码和用户输入的密码是否匹配,user.password为数据库里存储的密码
        const pwdMatchFlag =bcrypt.compareSync(password, user.password);
        if(pwdMatchFlag){
            ...
            res.redirect('/posts')   //匹配成功跳转到主页
        }else{
            ...
            return res.redirect('back') //匹配失败返回之前的页面
        }
    })
    .catch(next)
})
async异步写法(稍微麻烦些,推荐)
//引入bcrypt模块
var bcrypt = require('bcrypt');

//POST /signup用户注册
router.post('/', checkNotLogin, function(req, res, next){
    let password = req.fields.password   //获取注册页面上表单输入的密码

    //生成salt的迭代次数
    const saltRounds = 10;
     //生成salt并获取hash值
    bcrypt.genSalt(saltRounds, function(err, salt){
        bcrypt.hash(password,salt, function(err, hash){
            //把hash值赋值给password变量
            password = hash;
            storeUInfo();
        })
    })

    //存储用户信息
    function storeUInfo(){
        let user = {
            name: name,
            password: password,     //把加密后的密码存入数据库
            gender: gender,
            avatar: avatar,
            bio: bio
        }
        //用户信息写入数据库
        UserModel.create(user)
            .then(function(result){
                //此时user是插入mongodb后的值,包含_id
                user = result.ops[0];
                //删除密码这种敏感信息,将用户信息存入session
                delete user.password
                //注册成功后跳转到首页
                res.redirect('/posts')
            })
            .catch(function(e){
                //用户名被占用则跳回注册页,而不是错误页
                if(e.message.match('duplicate key')){
                    req.flash('error','用户名已被占用')
                    return res.redirect('/signup')
                }
                next(e)
            })
} 


//POST /signin  用户登录
router.post('/', checkNotLogin, function(req, res, next){
    const password = req.fields.password  //获取登录页面上表单输入的密码

    UserModel.getUserByName(name)
    .then(function(user){
       //检查数据库里的密码和用户输入的密码是否匹配,user.password为数据库里存储的密码
       bcrypt.compare(password, user.password,function(err,res){
           const pwdMatchFlag = res;
           tryLogin(pwdMatchFlag);
        })
        // 尝试登录
        function tryLogin(pwdMatchFlag){
            if(pwdMatchFlag){
                ...
                res.redirect('/posts')   //匹配成功跳转到主页
            }else{
                ...
                return res.redirect('back') //匹配失败返回之前的页面
            }
        }
    })
    .catch(next)
})

为什么建议使用异步模式?

如果你在一个简单的脚本上使用bcrypt,使用同步模式是非常好的。
但是,如果您在服务器上使用bcrypt,则建议使用异步模式。
这是因为bcrypt完成的散列是CPU密集型的,所以同步版本将阻止事件循环,并阻止你的应用程序服务于任何其他入站请求或事件。

参考阅读

  • npm bcrypt
  • 如何防范密码被破解
  • bcrypt加密算法

你可能感兴趣的:(node)