Java使用OTP動(dòng)態(tài)口令(每分鐘變一次)進(jìn)行登錄認(rèn)證
GIT地址:https://github.com/suyin58/otp-demo
動(dòng)態(tài)碼截圖:
在對(duì)外網(wǎng)開放的后臺(tái)管理系統(tǒng)中,使用靜態(tài)口令進(jìn)行身份驗(yàn)證可能會(huì)存在如下問題:
(1) 為了便于記憶,用戶多選擇有特征作為密碼,所有靜態(tài)口令相比動(dòng)態(tài)口令而言,容易被猜測(cè)和破解;
(2) 黑客可以從網(wǎng)上或電話線上截獲靜態(tài)密碼,如果是非加密方式傳輸,用戶認(rèn)證信息可被輕易獲取;
(3) 內(nèi)部工作人員可通過合法授權(quán)取得用戶密碼而非法使用;
靜態(tài)口令根本上不能確定用戶的身份,其結(jié)果是,個(gè)人可以輕松地偽造一個(gè)假身份或者盜用一個(gè)已有使用者的身份,給企業(yè)造成巨大的經(jīng)濟(jì)和聲譽(yù)損失。本文主要介紹并實(shí)現(xiàn)了一種動(dòng)態(tài)口令(OTP)的實(shí)現(xiàn)方式。
動(dòng)態(tài)口令(OTP,One-Time Password)又稱一次性密碼,是使用密碼技術(shù)實(shí)現(xiàn)的在客戶端和服務(wù)器之間通過共享秘密的一種認(rèn)證技術(shù),是一種強(qiáng)認(rèn)證技術(shù),是增強(qiáng)目前靜態(tài)口令認(rèn)證的一種非常方便技術(shù)手段,是一種重要的雙因素認(rèn)證技術(shù),動(dòng)態(tài)口令認(rèn)證技術(shù)包括客戶端用于生成口令產(chǎn)生器的,動(dòng)態(tài)令牌,是一個(gè)硬件設(shè)備,和用于管理令牌及口令認(rèn)證的后臺(tái)動(dòng)態(tài)口令認(rèn)證系統(tǒng)組成。
otp從技術(shù)來分有三種形式,時(shí)間同步、事件同步、挑戰(zhàn)/應(yīng)答。
(1)時(shí)間同步
原理是基于動(dòng)態(tài)令牌和動(dòng)態(tài)口令驗(yàn)證服務(wù)器的時(shí)間比對(duì),基于時(shí)間同步的令牌,一般每60秒產(chǎn)生一個(gè)新口令,要求服務(wù)器能夠十分精確的保持正確的時(shí)鐘,同時(shí)對(duì)其令牌的晶振頻率有嚴(yán)格的要求,這種技術(shù)對(duì)應(yīng)的終端是硬件令牌。
(2)事件同步
基于事件同步的令牌,其原理是通過某一特定的事件次序及相同的種子值作為輸入,通過HASH算法中運(yùn)算出一致的密碼。
(3)挑戰(zhàn)/應(yīng)答
常用于的網(wǎng)上業(yè)務(wù),在網(wǎng)站/應(yīng)答上輸入服務(wù)端下發(fā)的挑戰(zhàn)碼,動(dòng)態(tài)令牌輸入該挑戰(zhàn)碼,通過內(nèi)置的算法上生成一個(gè)6/8位的隨機(jī)數(shù)字,口令一次有效,這種技術(shù)目前應(yīng)用最為普遍,包括刮刮卡、短信密碼、動(dòng)態(tài)令牌也有挑戰(zhàn)/應(yīng)答形式。
使用阿里云身份寶(或者Google Authenticator)時(shí)間同步實(shí)現(xiàn)OTP動(dòng)態(tài)口令
如上圖,是一種基于時(shí)間同步的OTP計(jì)算方式,是通過客戶端和服務(wù)器持有相同的密鑰并基于時(shí)間基數(shù),服務(wù)端和客戶端采用相同的Hash算法,計(jì)算出長度為六位的校驗(yàn)碼。當(dāng)客戶端和服務(wù)端計(jì)算出的校驗(yàn)碼相同是,那么驗(yàn)證通過。
由于客戶端需要存儲(chǔ)密鑰和計(jì)算校驗(yàn)碼的載體,阿里云的身份寶(或者Google 的Authenticator)提供了手機(jī)端的APP進(jìn)行密鑰存儲(chǔ)和校驗(yàn)碼計(jì)算。下面我們以這兩款客戶端為例,實(shí)現(xiàn)在應(yīng)用采用OTP進(jìn)行權(quán)限驗(yàn)證,主要流程如下圖:
流程關(guān)鍵代碼如下,(更詳細(xì)代碼,請(qǐng)Git下載:https://github.com/suyin58/otp-demo)
1 用戶注冊(cè):
1.1 生成OTP密鑰:
String secretBase32 = TotpUtil.getRandomSecretBase32(64); oper.setOtpSk(secretBase32);
1.2 生成OTP掃描用字符串:
約定字符串格式如下:
otpauth://totp/[客戶端顯示的賬戶信息]?secret=[secretBase32]
String totpProtocalString = TotpUtil.generateTotpString(operCode, host, secretBase32);
1.3 將1.2中生成的字符串生成二維碼,通過郵件發(fā)送給用戶
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>" +"系統(tǒng)使用密碼 + 動(dòng)態(tài)口令雙因素認(rèn)證的方式登錄。</br>請(qǐng)按以下方式激活手機(jī)動(dòng)態(tài)口令:</br>安卓用戶請(qǐng)點(diǎn)擊<a +"</br>蘋果手機(jī)在AppStore中搜索【身份寶】(Alibaba)。下載安裝后,通過掃描以下二維碼激活動(dòng)態(tài)口令。</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 將用戶注冊(cè)信息與1.1的OTP密鑰存儲(chǔ)到數(shù)據(jù)庫中
數(shù)據(jù)存儲(chǔ)代碼(略)
2 客戶端工具使用
2.1 下載APP
安卓用戶下載地址:http://otp.aliyun.com/updates/shenfenbao.apk
蘋果手機(jī)在AppStore中搜索【身份寶】(Alibaba),或者Google Authenticator
2.2 掃描二維碼
使用下載的APP,掃描1.3郵件中的二維碼,客戶端獲取密鑰。APP使用密鑰基于時(shí)間算出6位校驗(yàn)碼(每分鐘變化)。
1 用戶登錄
客戶端輸入登錄用戶名、用戶密碼,以及2.2客戶端工具中的6位校驗(yàn)碼。
1.1 服務(wù)端根據(jù)用戶名和用戶密碼獲取用戶信息和密鑰
代碼參考略
1.2 服務(wù)端使用密鑰基于時(shí)間算出6位校驗(yàn)碼
String secretHex = ""; try { secretHex = HexEncoding.encode(Base32String.decode(secretBase32)); } catch (Base32String.DecodingException e) { LOGGER.error("解碼" + secretBase32 + "出錯(cuò),", e); throw new RuntimeException("解碼Base32出錯(cuò)"); } 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("生成動(dòng)態(tài)口令出錯(cuò):" + secretBase32, e); throw new RuntimeException("生成動(dòng)態(tài)口令出錯(cuò)"); }
1.3 比較客戶端和客戶端校驗(yàn)碼是否一致
代碼參考略
其他,Demo中的例子可以使用身份 + 密碼,先進(jìn)行密碼驗(yàn)證,在通過動(dòng)態(tài)口令進(jìn)行二次驗(yàn)證,使系統(tǒng)登錄更加安全可靠。
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Java均攤復(fù)雜度和防止復(fù)雜度的震蕩原理分析
這篇文章主要介紹了Java均攤復(fù)雜度和防止復(fù)雜度的震蕩,結(jié)合實(shí)例形式分析了Java均攤復(fù)雜度和防止復(fù)雜度的震蕩相關(guān)概念、原理、實(shí)現(xiàn)方法與注意事項(xiàng),需要的朋友可以參考下2020-03-03SpringMVC 傳日期參數(shù)到后臺(tái)的實(shí)例講解
下面小編就為大家分享一篇SpringMVC 傳日期參數(shù)到后臺(tái)的實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2017-12-12Java源碼解析CopyOnWriteArrayList的講解
今天小編就為大家分享一篇關(guān)于Java源碼解析CopyOnWriteArrayList的講解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-01-01通過java備份恢復(fù)mysql數(shù)據(jù)庫的實(shí)現(xiàn)代碼
這篇文章主要介紹了如何通過java備份恢復(fù)mysql數(shù)據(jù)庫,其實(shí)一般情況下通過bat或sh就可以,這里主要是介紹了java的實(shí)現(xiàn)思路,喜歡的朋友可以參考下2013-09-09Java郵件發(fā)送程序(可以同時(shí)發(fā)給多個(gè)地址、可以帶附件)
不錯(cuò)的功能比較齊全的郵件發(fā)送程序源碼2008-07-07Java如何將Excel數(shù)據(jù)導(dǎo)入到數(shù)據(jù)庫
這篇文章主要為大家詳細(xì)介紹了Java將Excel數(shù)據(jù)導(dǎo)入到數(shù)據(jù)庫的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10MyBatis查詢數(shù)據(jù),賦值給List集合時(shí),數(shù)據(jù)缺少的問題及解決
這篇文章主要介紹了MyBatis查詢數(shù)據(jù),賦值給List集合時(shí),數(shù)據(jù)缺少的問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01