nodejs 基于时间的动态验证码登录、验证等(离线模式可用)

大家或许都用过网银,部分银行有一个动态口令验证码,一般为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() + 60000, 'yyyy-mm-dd-HH:MM')
let words = start + mobile + end + "密码&……*&@..."
const code = GENERATE_SIX_CODE(sm3(words))
return res.json({err: 0, 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() + 60000, '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: 1, msg: '登录失败'})
            } else {
                return res.json({err: 0})
            }
        })
        }
    } else {
        return res.json({err: 1})
    }
})

以上验证code一般写于离线客户端中,密码需要与服务器密码保持同步

扩展使用

当登录有多种权限的时候,比如管理员、学生、访客、老师等,我们可以在生成code的时候在密码中协定,如果是某种角色用谋者密码来加密,在验证的时候,我们额外生成多个匹配即可。

函数补充

用来生成6位整数

const murmurhash = require('node-murmurhash')
module.exports = {
    GENERATE_SIX_CODE: (str) => {
        let allToSix = (num, length) => {
            return (new Array(length).join(0) + num).slice(-length)
        }
        let mhash = murmurhash(str)
        if (mhash < 0) mhash = mhash + 4294967296
        return allToSix(parseInt(mhash.toString().substr(4)), 6)
    },

}

你可能感兴趣的:(nodejs,动态验证码,sm3,OTP)