Day 27. B2E-密码加密

https://ithelp.ithome.com.tw/upload/images/20201013/20118686MAFtUUgy0k.jpg

还记得第2天在做专案规划时,有提到一个目标「加密敏感资料实现资安管理」吗?
目前我们的密码还是一样放在资料库上全裸

今天进度目标要来将密码加密存放,并实作比对密码
另外会多写一个重置密码的功能,让系统将密码重设


#bcryptjs套件安装

我们会用到 bcryptjs 此套件来做密码加密等动作,此套件的加密是不可逆的,所以没有办法从加密後的结果回推原始密码,相对安全性提高非常多

开启後端(b2e)专案,我们来安装它吧~

#Step 1

输入安装指令:

npm install bcryptjs

接着就等安装完罗~安装成功後会有这些讯息:

npm WARN optional SKIPPING OPTIONAL DEPENDENCY: [email protected] (node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for [email protected]: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})

+ [email protected]
added 1 package from 6 contributors and audited 250 packages in 3.382s

10 packages are looking for funding
  run `npm fund` for details

found 4 vulnerabilities (3 low, 1 critical)
  run `npm audit fix` to fix them, or `npm audit` for details


   ╭────────────────────────────────────────────────────────────────╮
   │                                                                │
   │      New patch version of npm available! 6.14.4 -> 6.14.8      │
   │   Changelog: https://github.com/npm/cli/releases/tag/v6.14.8   │
   │               Run npm install -g npm to update!                │
   │                                                                │
   ╰────────────────────────────────────────────────────────────────╯

#Step 2

开启 /modules/user.module.js 引用套件:

const bcrypt = require('bcryptjs');

安装的部份就完成罗!!


#重置密码API

接着要做一个API将原来的密码重设为加密後的密码~
可以将这个API的用途想像成Google的密码重设功能!!

#Step 1

开启 /routes/users/index.js 新增路由:

router.post('/resetpswd', userCtrl.userCtrlResetPswd);

#Step 2

开启 /controllers/users.controller.js 加上 userCtrlResetPswd,将要修改密码的帐号及新的密码传入module处理:

const userCtrlResetPswd = (req, res) => {
    userModule.userModuleResetPswd({
        accountId: req.body.accountId,
        newPassword: req.body.newPassword,
    }).then((moduleResult) => {
        res.send(Object.assign({ success: true }, moduleResult));
    }).catch((error) => {
        res.send(Object.assign({ success: false }, error));
    });
};

module.exports = {
    ...,
    userCtrlResetPswd,
}

#Step 3

开启 /modules/users.module.js 加上 userModuleResetPswd,前面的连线可以直接大绝招xD

const userModuleResetPswd = (values) => {
    return new Promise((resolve, reject) => {
        MongoClient.connect(mongoDBConnectionUrl, {
            useUnifiedTopology: true
        }).then((client) => {
            client.db(`${config.mongodb.DATABASE}`).collection("users", (error, collection) => {
                if (error) {
                    reject({ message: error });
                } else {
                    ...
                }
            });
        }).catch(error => {
            reject({ message: error });
        });
    });
};

#Step 4

连线成功後,会用到 findOneAndUpdate() 方法,找到对应的帐号资料後将该笔资料做密码更新:

collection.findOneAndUpdate(
    { accountId: values.accountId },
    { $set: { password: bcrypt.hashSync(values.newPassword, 10) } }
).then((result) => {
    if (result.value === null) {
        reject({ message: '无法重设密码' });
    } else {
        resolve({ message: '重设完成' });
    }
}).catch((error) => {
    reject({ message: error });
}).finally(() => {
    client.close();
});

重点在第3行: bcrypt.hashSync(values.newPassword, 10)
用到了 bcrypt 套件的 hashSync('加密值', 加盐次数) 方法

  • 加密值: 就是要加密的资料,这里当然就是传进来的新密码
  • 加盐次数: 加盐就是将内容加入特定字串打乱後的杂凑结果,就像炒菜加盐後味道更复杂一样,参考维基百科-盐(密码学)
    加盐的次数越多,味道越复杂,杂凑结果就越难破解,但相对的处理时间也会更长

#结果

到这边就完成重置密码罗!!
来用POSTMAN看一下结果吧~
gif已死QQ

从Compass可以看到密码已经重置成看似乱码的资料了!!
https://ithelp.ithome.com.tw/upload/images/20201005/20118686TIn2NKiWPr.jpg


#修改登入验证

最後在登入验证的部分需要改为 bcrypt套件的验证方式

#Step 1

开启 /modules/users.module.js 来到 userModuleSignin 方法
将原来验证密码的方式改为 bcrypt 的验证方法 compare(要比对的密码, 资料库的密码):

bcrypt.compare(values.password, user.password).then((result) => {
    if (result) {
        //验证成功
    } else {
        //验证失败
    }
});
  • result(true/false): 比对结果

根据比对结果判断验证是成功或失败

#Step 2

把原本的成功或失败的内容移进去:

collection.findOne({ accountId: values.accountId }).then((user) => {
    if (user) {
        bcrypt.compare(values.password, user.password).then((result) => {
            if (result) {
                const payload = {
                    accountId: user.accountId,
                    username: user.username,
                    exp: Math.floor(Date.now() / 1000) + config.jwt.exp
                };
                const token = jwt.sign(payload, config.jwt.tokensecret);
                resolve({ message: '登入成功', token });
            } else {
                reject({ message: '密码错误' });
            }
        });
    } else {
        reject({ message: '无此帐号' });
    }
    client.close();
});

这样就达成目标「加密敏感资料实现资安管理」罗!!


今日重点:

  • 密码加密使用 bcryptjs 套件
    • 使用 .hashSync() 方法做加密
    • 使用 .compare() 方法做加密资料比对

有需要改进或是任何意见建议欢迎下面留言~


<<:  拥抱「资料结构」的「演算法」(29) - 戴克斯特拉演算法求最短路径

>>:  Day28-移动侦测2

Vpn架设

我家使用的是大大宽频 没有固定ip 最近购入一台totolink的路由器想要架设vpn 但是设定完了...

Day 19 - 语音情绪辨识简介

语言除了能够传达字面上的讯息之外,也蕴含了说话者所要表达的情绪,情绪的展现能够让对方更清楚的了解讯息...

Day30. Blue Prism本届最终章 –BP幕後花絮

记忆犹深的痞客帮铁人赛第一天, 由於首次加入铁人赛的行列, 因此开了一篇不在铁人赛内的文章, 当天发...

Day6-Java反编译工具:javap

javap介绍 javap是jdk工具中自带的反编译工具,它是根据class位元组码档案,反解析出当...

Web服务器扫描工具-Nikto

前几天有练习了小蜘蛛和跳过鱼 今天还是持续练习Web的工具 透过这些工具可以辅助我们更顺利进行手动测...