繆 蕊 ,鐘志賢 ,劉 珺 ,包愛民 ,姜 維,申小琦
(1.昆明冶金高等專科學校網絡管理與信息化部,云南 昆明 650033; 2.吉林省明日科技有限公司,吉林 長春 130000)
隨著國家大力開展數字化經濟,虛擬賬號的數量呈指數上升,隨之而來的就是與日俱增的數據安全問題。因為互聯網有著極強的匿名性,所以服務商很難分辨當前進行遠程操作的是客戶本人還是冒名頂替的不法分子。為了保證電子商務交易安全和電子支付安全,服務商推出了多種身份驗證方式。其中最常使用的是靜態密碼驗證,用戶通過輸入用戶名與密碼進行身份認證,密碼是靜態的,可重復使用。但使用靜態密碼進行認證存在巨大風險,服務商為了維護這些密碼以獲得更高的安全性,需要耗費大量的人力、物力。用戶會為了方便管理而使用弱密碼或低強度密碼(例如自己的電話號碼、生日、樓棟號等)。這樣的靜態密碼極易被盜用或破解。密碼被盜用后,非法用戶即可登錄應用平臺對用戶數據進行肆意篡改,從而造成財產損失。
隨著網絡應用的復雜化、攻擊手段的多樣化,靜態密碼驗證的安全缺陷也越來越明顯,已經不再適用于安全性要求較高的網絡應用系統。為了解決靜態密碼存在的缺陷,一次性動態口令的認證方式應運而生。但是,目前現有的一次性口令認證方案也并不十分完善,有的需要安裝第三方插件,有的平臺兼容性與可移植性較差,各種方案在執行性能和安全性能上還存在一定缺陷。設計更加完善的一次性口令認證方案,可以為更多的網絡系統提供更加安全可靠的身份認證,保障用戶在使用平臺時的安全性、私密性。
本文將介紹基于Java語言的一次性動態口令算法,采用更加完善的認證,增強認證口令的隨機性,做到真正的一次一密,并更加容易地部署到網絡應用系統中。
在網絡安全開展的早期,為了防止他人盜取數據,服務商提供“2套密碼”服務:登錄用一個密碼,辦理業務用另外一個密碼。但很快這種方案也出現漏洞,不法分子只需同時捕捉到2套密碼就可以非法竊取網絡數據。之后服務商又推出了非常多的加密方案,銀行作為金融機構,對于網絡操作都十分敏感,所以銀行對于身份驗證的要求最為嚴格。
隨著網絡銀行的業務開展,銀行為了保證用戶資金的安全性,要求用戶在進行網絡支付時,除了驗證登錄密碼外,還要完成另一套驗證操作。最早銀行推出了口令卡業務,用戶需到銀行申請一個可刮擦、數字隨機的二維矩陣卡,如圖1所示。用戶每次進行網絡支付時,銀行都會要求輸入口令卡中指定行、列的數字,由此來驗證用戶真實身份。雖然口令卡用起來非常方便,但也存在著被盜取的安全隱患,并且口令卡上的密碼數量有限,一旦用戶刮完所有數字,就需要重新申請。

圖1 工商銀行口令卡Fig.1 ICBC password card
為了提高賬戶安全性,銀行推出了網銀盾業務,俗稱U盾,如圖2所示。這是一個寫有固定加密程序的U盤,具有不可復制性,所以安全性極高。但U盾也存在一個缺陷,就是必須在已安裝銀行驅動程序的計算機上操作,對使用場景的要求極高。
所以U盾已成為網銀加密的主要產品,但為了簡化用戶的操作過程,銀行又推出了一次性動態口令令牌產品。這是一款小巧的自帶電池、液晶屏的數碼產品,通常液晶屏中會隨機顯示6個數字,這6個數字就是一次性動態口令,如圖3所示。動態口令雖然是隨機數字,但卻和銀行的服務器保持了一致性,用戶在任意一臺計算機上進行網絡支付時,只需輸入當前令牌顯示的一次性口令就可以完成支付操作,這樣就解除了使用場景的限制。

圖2 建設銀行一代網銀U盾 圖3 中國銀行的動態口令令牌Fig.2 CCB generation I E-bank USBkey Fig.3 BOC dynamic password token

圖4 QQ安全中心界面示意圖Fig.4 QQ security center interface diagram
隨著智能手機的普及,很多開發商將動態口令令牌由硬件產品轉移到了智能手機軟件上,這樣極大地降低了推廣成本。很多銀行也將口令令牌功能轉移到手機軟件上,用戶直接安裝官方軟件即可激活,無需再到柜臺申請。除了銀行以外,各大互聯網公司也推出了各自的動態口令軟件,例如圖4所示的騰訊QQ安全中心軟件。
一次性口令也叫一次性密碼(One Time Password,OTP)。OTP 的計算公式為:OTP(K,C) = Truncate[HMAC-SHA-1(K,C)],其中,K表示明文;C是加密算法對明文進行簽名的秘鑰;HMAC-SHA-1是從 SHA1 哈希函數構造的一種鍵控哈希算法加密算法,可以根據任意字符串生成一個160 位的哈希值;Truncate 是截取加密結果的方法。一次性口令的特點是用戶可以根據服務商提供的動態口令程序生成的數字來輸入動態口令,而且每個登錄服務器的口令均只能使用一次,這樣可使竊聽者或黑客無法通過竊聽和破解口令來偽造登錄。同時利用單向散列函數的不可逆性,防止密碼被竊聽或破解后進行二次登錄。
HOTP 的全稱是HMAC-based One-Time Password,表示根據某一特定的事件及相同的種子值作為參數,通過哈希算法運算出一致的密碼。
HOTP的計算公式為HOTP(K,C) = Truncate[HMAC-SHA-1(K,C)],其中,C是一個與事件同步的隨機值,在HOTP的基礎之上,將當前時間作為參數C,就發展出了TOTP算法。
TOTP的全稱是Time-based One-time Password ,原理同HOTP一致,只是將其中的參數C變成了時間,計算公式為:TOTP(K,C) = Truncate[HMAC-SHA-1(K,C)]。
在Java語言中,時間戳可以采用System.currentTimeMillis()方法返回的當前時間毫秒數,這是一個long類型整數,每一次調用都會基于時間的不同而得到不同的數值。
公式中的K參數可以采用“用戶唯一標志 + token”的方式拼接。用戶的唯一標志可以是用戶的身份證號、電話號、郵箱等,也可以是服務端提供用戶的認證證書,例如電子證書號碼、用戶ID等。明文在加密之前要在末尾拼接token參數,這樣可以極大地增加破譯難度。token即鹽值,其本身是一個無序、無語義的字符串,服務端和客戶端每隔一段時間就更換并同步token參數,這樣可以極大提高一次性口令的安全性。
獲得6位一次性動態口令需要進行以下計算過程:
1)將K參數和C參數進行HmacSHA1加密,得到加密后的字節數組;
2)取出字節碼數組的后4個字節;
3)為了加大加密算法的復雜度,翻轉取出的4個字節的順序;
4)按照翻轉之后的順序,將4個字節拼接成1個32位的整數;
5)截取此32位整數的最后6位數字,這6位數字就是算法生成的一次性動態口令。其計算過程如圖5所示。

圖5 計算動態口令的過程Fig.5 Dynamic password calculation process
使用Java代碼開發一次性動態口令算法,首先要實現HmacSHA1加密算法。JDK的javax.crypto包已提供了該算法的API。用Java編寫的程序不但簡潔、代碼少,而且可讀性較強。Java與平臺無關,可移植性強,并自帶豐富的網絡類庫,功能強大。基于以上原因,項目中選擇采用Java來實現動態口令身份認證。
本方案應用于學校智慧教室控制系統的教師身份認證,通過認證后,教師登錄移動智能終端,并獲得智慧教室設備的控制權限。
為方便教師使用,設計遵循以下原則:1)不需要在智慧教室控制端安裝其它第三方組件,直接嵌入算法即可;2)可移植性高,兼容多種移動端設備;3)提供雙向認證。

圖6 基于時間同步身份認證原理圖Fig.6 Identity authentication diagram based on the time synchronization
基于以上原則,本方案選擇采用基于時間同步的身份認證。該技術的核心算法是單項散列函數,函數的輸入參數是由“證書+鹽值”拼接出的加密明文和當前時間的毫秒數(客戶端和服務器需要校準為統一的時間),輸出參數是長度固定的散列值。該散列值就可以作為用戶身份的安全憑證。原理如圖6所示。
該技術的核心算法是encrypt()方法,該方法的2個參數分別為由“證書+鹽值”拼接出的加密明文和當前時間的毫秒數(客戶端和服務器需要校準為統一的時間),返回值為經過HmacSHA1算法加密后得到的1個32位整數(可能是負數)。HmacSHA1是從SHA1哈希函數構造的一種鍵控哈希算法,很難找到逆向規律,所以加密安全性極高。前、后端在同一時間計算出的口令具有一致性,可以根據此口令作為用戶的身份認證標志,前、后端的計算過程如圖7所示。

圖7 使用動態口令進行身份認證順序Fig.7 Sequence diagram using the dynamic password for identity authentication
核心代碼如下:
private static int encrypt(String encryptText, String encryptKey) {
try {
byte[] data = encryptKey.getBytes("UTF-8");
// 根據給定的字節數組構造一個密鑰,第二參數指定一個密鑰算法的名稱
SecretKeysecretKey = new SecretKeySpec(data, "HmacSHA1");
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(secretKey);// 密鑰初始化
// 完成加密
byte ciphertext[] = mac.doFinal(encryptText.getBytes("UTF-8"));
int num = 0;// 待拼接數字
for (int i = 0; i< 4; i++) {// 取4個字節
// 將數組后4個字節順序翻轉并拼接成一個32位數字
num += ciphertext[ciphertext.length - 1 - i] << 8 * (3 - i);
}
return num;
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return -1;
}
編寫Test測試類,設定一個證書和一個token,獲取當前毫秒數,將更新時間設定為 3 s,將拼接好的明文和時間進行加密,每隔 1 s 輸出一次口令,查看運行結果,完整代碼如下:
public class Test {
public static void main(String[] args) {
String certificate = "8898763578363844";// 證書或公鑰
String token = "UWzwth6I";// 加密參數
String key = certificate + token;// 拼接加密內容
new Thread() {
public void run() {
while (true) {
try {
// 當前時間毫秒數
long time = System.currentTimeMillis();
// 打印隨機口令,3 s更新
System.out.println(JTOTP.getPassword(key, time, 3));
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}.start();
}
}
運行結果如下:
352081
352081
012760
012760
012760
192007
192007
192007
854810
854810
854810
經測試,即使代碼在兩臺計算機上運行,只要計算機本地時間一致,就會得到同步的結果。如果修改了用戶證書或token,動態口令就會立即改變。
本套代碼可以直接用于基于Java語言開發的Android系統程序,在用戶證書、token和本地時間一致的條件下,移動端得到的動態口令與服務器一致,運行速率快,可移植性高,能夠滿足智慧教室控制系統對教師身份認證的要求。