在当今的网络安全环境中,两步验证已成为提高账户安全性的重要手段。一次性密码(OTP)是两步验证中常用的一种方式,它通过动态生成的密码来增强安全性。本文将介绍如何在移动设备上实现一个具有自定义用户界面的OTP生成器。
OTP生成器通常是一个运行在移动设备上的应用程序,无论是基于iOS还是Android系统,它们都对HTML5有很好的支持。这使得能够以纯HTML/JavaScript的形式实现OTP生成器,作为一个单页应用程序。
要实现一个自定义UI的OTP生成器,需要解决以下几个挑战:
根据之前的文章,需要以下组件来实现算法:
倾向于选择MIT或LGPL许可证的库,以便能够将解决方案作为商业用途免费许可。对于base32实现,强烈推荐Nibbler库:
http://www.tumuski.com/2010/04/nibbler/
对于SHA1算法和其他JavaScript中的加密算法,推荐使用Google的CryptoJS库:
http://code.google.com/p/crypto-js/
CryptoJS是一个不断增长的标准和安全的加密算法集合,使用最佳实践和模式在JavaScript中实现。它们快速,并且具有一致且简单的接口。库目前仍在支持和开发中。可以在那里找到sha1和hmac的实现。
对于OTP算法,可以使用NodeJS模块作为基础:
https://github.com/guyht/notp/
问题是该模块专为NodeJS环境设计,因此需要消除所有不必要的依赖,以允许该模块在浏览器环境中工作。MIT许可证允许进行这样的修改。
在这种情况下,不得不进行Buffer对象的端口,使用Nibbler实现base32,并模拟NodeJS crypto模块:
var cryptoFAKE = {
createHmac: function(algorithm, key) {
var _key = key.value();
return new HMacBasicImpl(_key);
}
};
结果采用了NOTP类,它提供了计算一次性密码的方式:
Notp.getTOTP(args, err, cb)
参数:包含所需字段K(私钥字符串)的对象。
对于UI,需要回答以下问题:
幸运的是,HTML5允许网页在客户端设备上持久化数据 - DOM存储:
var CLUE = localStorage.getItem('CLUE');
if (typeof(CLUE) === "undefined") {
CLUE = null;
}
对于单页应用程序,最喜欢的库是KnockoutJS。它允许专注于开发逻辑,并将绑定到Knockout标记的HTML元素外包。
模型:
var Model = {
existsclue: ko.observable(CLUE !== null),
clue: ko.observable(CLUE),
token: ko.observable('XXXXXXX'),
notp: new Notp(),
UpdateTokenCallback: function(code) {
this.token(code);
},
UpdateToken: function() {
var args = {
K: CLUE
};
this.notp.getTOTP(args, function(err) { alert(err); }, Model.UpdateTokenCallback.bind(Model));
}
};
视图:
<header aria="company logo">
<div class="center">
<img src="im/logo.gif"/>
</div>
</header>
<div id="main" role="main" class="center">
<p data-bind="text:token" id="code">LOADING...</p>
<p data-bind="text:clue" id="clue">CLUE</p>(
<span data-bind="text:existsclue"></span>)
<p data-bind="visible:(!existsclue())" id="syncro">
<a href="setup.php">Please navigate to this link to setup your device!</a>
</p>
<p>
<a href="#" onclick="window.applicationCache.update()">Debug: cache.swapCache()</a>
</p>
</div>
检测本地存储中是否存在CLUE,如果不存在,则建议客户进行设置(“请导航到此链接以设置设备”)。在真实场景中,可能希望用户使用某种安全方法登录,但为了演示目的,使用简单的方法:将CLUE放入会话并显示QR码,客户设备只需扫描QR码即可配置OTP应用程序。
客户在每次需要OTP值时不需要互联网访问。这是利用另一种HTML5技术:离线缓存的地方:
<html class="no-js" lang="en" manifest="appcache.php">
在真实场景中,可能希望清单文件是紧凑的,但再次为了演示目的,让将所有项目脚本包含在离线模式中。
将通过一系列屏幕截图来演示代码。
请确保缓存清单以正确的MIME类型提供:
AddType text/cache-manifest appcache
AddType text/cache-manifest .appcache
如果克隆了仓库 - 则调整appcache.php代码,或删除.git文件夹和子文件夹。
https://github.com/Voronenko/JSOTP