還記得第2天在做專案規劃時,有提到一個目標「加密敏感資料實現資安管理」嗎?
目前我們的密碼還是一樣放在資料庫上全裸
今天進度目標要來將密碼加密存放,並實作比對密碼
另外會多寫一個重置密碼的功能,讓系統將密碼重設
我們會用到 bcryptjs 此套件來做密碼加密等動作,此套件的加密是不可逆的,所以沒有辦法從加密後的結果回推原始密碼,相對安全性提高非常多
開啟後端(b2e)專案,我們來安裝它吧~
輸入安裝指令:
npm install bcryptjs
接著就等安裝完囉~安裝成功後會有這些訊息:
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@2.1.3 (node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.1.3: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})
+ bcryptjs@2.4.3
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! │
│ │
╰────────────────────────────────────────────────────────────────╯
開啟 /modules/user.module.js 引用套件:
const bcrypt = require('bcryptjs');
安裝的部份就完成囉!!
接著要做一個API將原來的密碼重設為加密後的密碼~
可以將這個API的用途想像成Google的密碼重設功能!!
開啟 /routes/users/index.js 新增路由:
router.post('/resetpswd', userCtrl.userCtrlResetPswd);
開啟 /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,
}
開啟 /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 });
});
});
};
連線成功後,會用到 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看一下結果吧~
從Compass可以看到密碼已經重置成看似亂碼的資料了!!
最後在登入驗證的部分需要改為 bcrypt套件的驗證方式
開啟 /modules/users.module.js 來到 userModuleSignin 方法
將原來驗證密碼的方式改為 bcrypt 的驗證方法 compare(要比對的密碼, 資料庫的密碼)
:
bcrypt.compare(values.password, user.password).then((result) => {
if (result) {
//驗證成功
} else {
//驗證失敗
}
});
根據比對結果判斷驗證是成功或失敗
把原本的成功或失敗的內容移進去:
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();
});
這樣就達成目標「加密敏感資料實現資安管理」囉!!
今日重點:
.hashSync()
方法做加密.compare()
方法做加密資料比對有需要改進或是任何意見建議歡迎下面留言~