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

来源:互联网 发布:毕向东25java视频 编辑:程序博客网 时间:2024/06/15 13:42

大家或许都用过网银,部分银行有一个动态口令验证码,一般为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.mobilelet 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.codeconst mobile = req.body.mobileconst 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)    },}
原创粉丝点击