背景
前兩天項目有個類似動態口令的功能要實現,團隊最終決定使用OTP算法來實現:前端先向后端請求獲取用戶的密鑰(secret),將之保存在緩存中,之后前端根據該secret,使用OTP算法中的TOTP方式生成6位動態密碼,將6位動態密碼傳到后臺驗證。
OTP
1.1 簡介
OTP(One-Time-Password):一次性密碼,也稱為動態口令。是使用密碼技術實現的在客戶端和服務端之間通過共享密鑰的一種認證技術,是一種強認證技術,是增強目前靜態密碼口令認證的一種非常方便的技術手段,是一種重要的雙因素認證技術。
1.2 OTP認證原理
動態口令的基本認證原理是在認證雙方共享密鑰,也稱種子密鑰,并使用同一個種子密鑰對某一個事件計數、或時間值、或異步挑戰數進行密碼算法計算,使用的算法有對稱算法、HASH、HMAC,之后比較計算值是否一致進行認證。可以做到一次一個動態口令,使用后作廢,口令長度通常為6-8個數字,使用方便,與通常的靜態口令認證方式類似。
1.3 OTP實現方式
- 時間同步(TOTP)
- 事件同步(HOTP)
- 挑戰/應答(OCRA)
本文內容主要是小程序使用OTP算法踩坑總結,不對OTP算法的三種實現方式的工作原理進行詳細介紹,有興趣的朋友自行查找相關資料。
踩坑記錄
2.1 后端使用的otp庫說明
opt算法有許多現成的庫可以直接調用,后端使用的是aerogear-otp-java這個庫,問題不在后端,這里就不對這個庫進行講解,有興趣的朋友可以自己查看:
github地址: https://github.com/aerogear/aerogear-otp-java
2.2 踩坑前提
我們的微信小程序項目目前不支持引用第三方的npm包,所以要使用第三方的js庫,需要將其js文件下載放到小程序目錄中,通過require去引入。還有一點就是小程序項目還不支持node.js,如果js庫有相關的node.js代碼,還需要做一些改造。以上兩點背景給我挖了一個大坑往里跳。
2.3 跳入第一個坑
我們先找可用的otp的js庫,上github一搜,還是很多的,先選一個start數量比較的的:https://github.com/yeojz/otplib。
我們現在node.js環境上對 otplib 這個進行測試:
const authenticator = require('otplib/authenticator');
const crypto = require('crypto');
authenticator.options = { crypto };
const secret = 'BYYHJ5R6C3DNZJX3'
const token = authenticator.generate(secret);
console.log(token);
執行上面的代碼,可以獲得6位動態密碼,拿到后端驗證,驗證不通過...各種嘗試和排查后,放棄了,這個庫和后端的aerogear-otp-java不兼容,尷尬。。。
2.4 跳入第二個坑
又到github上一通找,各種嘗試,終于找到一個可以與aerogear-otp-java兼容的js庫:node-lib-otp
github地址: https://github.com/JCloudYu/node-lib-otp
const otp = require( 'lib-otp' );
let otpObj = otp({
secret:'BYYHJ5R6C3DNZJX3'
});
console.log(otpObj.totp(6));
將生成的6位動態密碼傳到后臺驗證,通過。
心想終于找到能用的了,有種勝利就在眼前的喜悅,馬不停蹄下載相關js,著手修改其中的node.js代碼,改到一半發現該庫引用了太多node.js的寫法和庫,短時間內無法完成修改并保證可用,放棄該庫了。。。
2.5 出坑
在github上搜索許久仍舊未找到合適的js庫,突然靈光一閃上碼云找一下,搜索結果第一個superzlc/otp有寫小程序,嘗試一下。
地址:https://gitee.com/superzlc/otp/tree/master
下載js,引入該庫生成動態密碼
const otp = require('./libs/otp')
const TOTP = otp.TOTP
const token = new TOTP('BYYHJ5R6C3DNZJX3', 3, 30).gen()
console.log(token)
驗證通過,還不用修改代碼,終于爬出坑了。
總結
OTP算法中的TOTP方式生成6位動態密碼可用庫如下:
- 后端java : https://github.com/aerogear/aerogear-otp-java
- node.js: https://github.com/JCloudYu/node-lib-otp
- 小程序純js:https://gitee.com/superzlc/otp/tree/master
注意點:前后端的計數值應一致,否則無法驗證通過