GIT地址:https://github.com/suyin58/otp-demogit
动态码截图:github
在对外网开放的后台管理系统中,使用静态口令进行身份验证可能会存在以下问题:算法
(1) 为了便于记忆,用户多选择有特征做为密码,全部静态口令相比动态口令而言,容易被猜想和破解;数据库
(2) 黑客能够从网上或电话线上截获静态密码,若是是非加密方式传输,用户认证信息可被轻易获取;安全
(3) 内部工做人员可经过合法受权取得用户密码而非法使用;服务器
静态口令根本上不能肯定用户的身份,其结果是,我的能够轻松地伪造一个假身份或者盗用一个已有使用者的身份,给企业形成巨大的经济和声誉损失。本文主要介绍并实现了一种动态口令(OTP)的实现方式。dom
动态口令(OTP,One-Time Password)又称一次性密码,是使用密码技术实现的在客户端和服务器之间经过共享秘密的一种认证技术,是一种强认证技术,是加强目前静态口令认证的一种很是方便技术手段,是一种重要的双因素认证技术,动态口令认证技术包括客户端用于生成口令产生器的,动态令牌,是一个硬件设备,和用于管理令牌及口令认证的后台动态口令认证系统组成。工具
otp从技术来分有三种形式, 时间同步、事件同步、挑战/应答。网站
(1) 时间同步阿里云
原理是基于 动态令牌和 动态口令验证服务器的时间比对,基于 时间同步的 令牌,通常每60秒产生一个新口令,要求服务器可以十分精确的保持正确的时钟,同时对其令牌的晶振频率有严格的要求,这种技术对应的终端是硬件令牌。
(2)事件同步
基于事件同步的令牌,其原理是经过某一特定的事件次序及相同的种子值做为输入,经过HASH算法中运算出一致的密码。
(3)挑战/应答
经常使用于的网上业务,在网站/应答上输入 服务端下发的 挑战码, 动态令牌输入该挑战码,经过内置的算法上生成一个6/8位的随机数字,口令一次有效,这种技术目前应用最为广泛,包括刮刮卡、短信密码、动态令牌也有挑战/应答形式。
使用阿里云身份宝(或者Google Authenticator)时间同步实现OTP动态口令
如上图,是一种基于时间同步的OTP计算方式,是经过客户端和服务器持有相同的密钥并基于时间基数,服务端和客户端采用相同的Hash算法,计算出长度为六位的校验码。当客户端和服务端计算出的校验码相同是,那么验证经过。
因为客户端须要存储密钥和计算校验码的载体,阿里云的身份宝(或者Google 的Authenticator)提供了手机端的APP进行密钥存储和校验码计算。下面咱们以这两款客户端为例,实如今应用采用OTP进行权限验证,主要流程以下图:
流程关键代码以下,(更详细代码,请Git下载:https://github.com/suyin58/otp-demo)
1 用户注册:
1.1 生成OTP密钥:
String secretBase32 = TotpUtil.getRandomSecretBase32(64);
oper.setOtpSk(secretBase32);
1.2 生成OTP扫描用字符串:
约定字符串格式以下:
String totpProtocalString = TotpUtil.generateTotpString(operCode, host, secretBase32);
1.3 将1.2中生成的字符串生成二维码,经过邮件发送给用户
String host = "otptest@wjs.com"; // 自定义 String totpProtocalString = TotpUtil.generateTotpString(operCode, host, secretBase32); String filePath = f_temp; String fileName = Long.toString(System.currentTimeMillis()) + ".png"; try{ QRUtil.generateMatrixPic(totpProtocalString, 150, 150, filePath, fileName); }catch (Exception e){ throw new RuntimeException("生成二维码图片失败:" + e.getMessage()); } String content = "用户名:"+operCode+"</br>" +"系统使用密码 + 动态口令双因素认证的方式登陆。</br>请按如下方式激活手机动态口令:</br>安卓用户请点击<a href='http://otp.aliyun.com/updates/shenfenbao.apk'>下载</a>," +"</br>苹果手机在AppStore中搜索【身份宝】(Alibaba)。下载安装后,经过扫描如下二维码激活动态口令。</br>" +"<img src=\"cid:image\">"; EmailBaseLogic emailBaseLogic = new EmailBaseLogic(); // String to, String title, String content, String imagePath emailBaseLogic.sendWithPic(email,"帐户开立通知", content, filePath + "/" + fileName);
1.4 将用户注册信息与1.1的OTP密钥存储到数据库中
数据存储代码(略)
2 客户端工具使用
2.1 下载APP
安卓用户下载地址:http://otp.aliyun.com/updates/shenfenbao.apk
苹果手机在AppStore中搜索【身份宝】(Alibaba),或者Google Authenticator
2.2 扫描二维码
使用下载的APP,扫描1.3邮件中的二维码,客户端获取密钥。APP使用密钥基于时间算出6位校验码(每分钟变化)。
1 用户登陆
客户端输入登陆用户名、用户密码,以及2.2客户端工具中的6位校验码。
1.1 服务端根据用户名和用户密码获取用户信息和密钥
代码参考略
1.2 服务端使用密钥基于时间算出6位校验码
String secretHex = ""; try { secretHex = HexEncoding.encode(Base32String.decode(secretBase32)); } catch (Base32String.DecodingException e) { LOGGER.error("解码" + secretBase32 + "出错,", e); throw new RuntimeException("解码Base32出错"); } long X = 30; String steps = "0"; DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); df.setTimeZone(TimeZone.getTimeZone("UTC")); long currentTime = System.currentTimeMillis() / 1000L; try { long t = currentTime / X; steps = Long.toHexString(t).toUpperCase(); while (steps.length() < 16) steps = "0" + steps; return generateTOTP(secretHex, steps, "6", "HmacSHA1"); } catch (final Exception e) { LOGGER.error("生成动态口令出错:" + secretBase32, e); throw new RuntimeException("生成动态口令出错"); }
1.3 比较客户端和客户端校验码是否一致
代码参考略
其余,Demo中的例子可使用身份 + 密码,先进行密码验证,在经过动态口令进行二次验证,使系统登陆更加安全可靠。