大家或許都用過網銀,部分銀行有一個動态密碼驗證碼,一般為6位數字,其實其原理較為簡單,即銀行方保留了一個Key,同時動态密碼生成器的機器中的key與銀行方保持一緻,通過OPT等協定算法生成6位code,其過程很難被逆轉以及破解,因為通過算法,隻要key設定得足夠複雜,那麼驗證碼幾乎不可能被破解,同時基于時間政策,更難破解
準備工作
了解原理
- step1 時間範圍(一般為1分鐘) + 有效且複雜的 Key (字元串)
- step2 将字元串進行hash
- step3 轉換為6位整數
- step4 伺服器與用戶端保持時間與算法以及key同步一緻即可 (時間)
伺服器端生成
通過伺服器擷取動态驗證code,或通過離線加密程式擷取動态驗證code,如動态碼生成機器、加密程式(無法看到加密密碼即可)
const sm3 = require('sm3')
const dateFormat = require('dateformat')
const mobile = req.body.mobile
let start = dateFormat(Date.now(), 'yyyy-mm-dd-HH:MM')
let end = dateFormat(Date.now() + , 'yyyy-mm-dd-HH:MM')
let words = start + mobile + end + "密碼&……*&@..."
const code = GENERATE_SIX_CODE(sm3(words))
return res.json({err: , code: code})
上面的時間段誤差允許在1分鐘之内,即驗證碼每分鐘更新一次
離線用戶端驗證(主機應與伺服器保持同步)
如果在docker中部署,需要注意的是,docker中的時間可能與主控端不一樣,是以需要先同步一下主控端與docker時間,讓虛拟機與主控端時間一緻;如果直接安裝于主控端,則讓主控端與伺服器時間保持同步即可。
const sm3 = require('sm3')
const dateFormat = require('dateformat')
const code = req.body.code
const mobile = req.body.mobile
const start = dateFormat(Date.now(), 'yyyy-mm-dd-HH:MM')
const end = dateFormat(Date.now() + , 'yyyy-mm-dd-HH:MM')
let words1 = start + mobile + end + "密碼&……*&@..."
User.findOne({mobile}, (err, user) => {
if (user) {
const code1 = GENERATE_SIX_CODE(sm3(words1))
if (code1 === code) {
req.logIn(user, function (err) {
if (err) {
return res.json({err: , msg: '登入失敗'})
} else {
return res.json({err: })
}
})
}
} else {
return res.json({err: })
}
})
以上驗證code一般寫于離線用戶端中,密碼需要與伺服器密碼保持同步
擴充使用
當登入有多種權限的時候,比如管理者、學生、訪客、老師等,我們可以在生成code的時候在密碼中協定,如果是某種角色用謀者密碼來加密,在驗證的時候,我們額外生成多個比對即可。
函數補充
用來生成6位整數
const murmurhash = require('node-murmurhash')
module.exports = {
GENERATE_SIX_CODE: (str) => {
let allToSix = (num, length) => {
return (new Array(length).join() + num).slice(-length)
}
let mhash = murmurhash(str)
if (mhash < ) mhash = mhash +
return allToSix(parseInt(mhash.toString().substr()), )
},
}