iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 9
0
Modern Web

30天Vue出Google SSO系列 第 27

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: 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!                │
   │                                                                │
   ╰────────────────────────────────────────────────────────────────╯

#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() 方法做加密資料比對

有需要改進或是任何意見建議歡迎下面留言~


上一篇
Day 26. F2E-完善選擇帳戶
下一篇
Day 28. F2E-過渡動畫
系列文
30天Vue出Google SSO30

尚未有邦友留言

立即登入留言