基于JAAS 和智能卡的通用身份認證模塊的實(shí)現
文章出處:http://psychicreadingswithdeb.com 作者:曾海 人氣: 發(fā)表時(shí)間:2011年09月28日
一、概述
傳統的軟件在實(shí)現身份認證功能過(guò)程中,往往自行開(kāi)發(fā)專(zhuān)用的認證模塊。由于不同的軟件開(kāi)發(fā)人員在信息安全方面水平參差不齊,實(shí)現的認證模塊安全性往往得不到保證。認證和授權應當同業(yè)務(wù)邏緝分離一個(gè)通用的身份認證模塊不僅能減輕軟件開(kāi)發(fā)人員的負擔,更能保證認證的強度,確保在當認證方式發(fā)生改變時(shí),應用程序不受影響。
二 JAAS認證和授權服務(wù)
認證和授權是兩種最基本的安全機制,認證是簡(jiǎn)單地對一個(gè)實(shí)體的身份進(jìn)行判斷。而授權則是向實(shí)體授予對數據資源和信息訪(fǎng)問(wèn)權限的決策過(guò)程 Java 提供了一項提供認證和授權功能的標準服務(wù)。該服務(wù)即 JAAS (Java Authentication AutIlorization Service)。JAAS 強調通過(guò)驗證誰(shuí)在運行代碼以及用戶(hù)應該有的權限來(lái)保護系統不受攻擊。使用 JAAS 可以把一些標準驗證服務(wù)。如LDAP(輕量目錄存取協(xié)議)和 Kerberos 等通過(guò)一種通用的,可配置的方式集成到系統中。
認證機制需要參數是為了確定用戶(hù)的身份(對用戶(hù)進(jìn)行標識)。授權在認證之后進(jìn)行,JAAS框架對由配置文件指定的認證模塊進(jìn)行了包裝。如果認證成功。就會(huì )返回一個(gè)包含驗證信息的用戶(hù)標識,認證機制所返回的這個(gè)驗證信息會(huì )用于授權過(guò)程。JAAS 體系結構如圖一所示。其中驗證模塊可以通過(guò)配置模塊替換。
圖一
從身份認證的強度來(lái)看,基于PKI的智能卡身份驗證提供了更好的安全性。因此通用的登錄模塊不使用Java提供的通用模塊,而是實(shí)現了java.security.a(chǎn)uth.spi.LoginMoudle接口的自定義模塊,通過(guò)OCF框架存取智能卡,通過(guò)智能 實(shí)現驗證過(guò)程。
三、基于智能卡的身份認證實(shí)現
智能卡是一種芯片卡,計算芯片鑲嵌在一張名片大小的塑料卡片上,從而完成數據的存儲與計算??梢酝ㄟ^(guò)讀卡器訪(fǎng)問(wèn)智能卡中的數據。智能卡分為接觸式卡和非接觸式卡,接觸式卡中又分為存儲卡和微處理卡,后者更適合基于PKI的身份驗證。
使用智能卡進(jìn)行身份驗證的可用方式包括基于微軟平臺的CSP(Cryptographic Service Provider)、PKCS#11和基于Java的智能卡開(kāi)發(fā)平臺OCF(Open card Framework)。OCF定義了從Java應用環(huán)境到智能卡問(wèn)的通信標準。
從通用的角度看,OCF框架優(yōu)點(diǎn)明顯,它是是一套基于Java的應用程序編程接口,把不同的供應商的與讀卡器交互的細節隱藏起來(lái)以簡(jiǎn)化編程,主流智能卡廠(chǎng)商均支持OCF框架,Java是跨平臺的語(yǔ)言.因此為驗證模塊的運行提供了巨大的靈活性。身份認證使用了OCF的 CardTerminal 和CardService 層服務(wù)。前者提供了讀卡器的接口A(yíng)PI。后者使用File Access Card Service存取卡上文件,使用Signature Card Service提建立和驗證數字簽名.將證書(shū)導人智能卡,公鑰導出智能卡。這是身份認證模塊的核心功能之一。
OCF框架下的身份認證過(guò)程如圖二:
圖二
在卡和登錄模塊間的驗證方式使用了傳統的使用公鑰加密體制的挑戰/應答模式??ㄉ嫌凶约荷傻腞SA密鑰對。登錄模塊給出一個(gè)隨機數。智能卡對它進(jìn)行簽名。而登錄模塊驗證后就可獲知用戶(hù)身份
在實(shí)現過(guò)程中用戶(hù)和公鑰關(guān)聯(lián)以及用戶(hù)公鑰分發(fā)均由PKI應用系統中的CA完成。CA簽發(fā)數字證書(shū)進(jìn)行了用戶(hù)和公鑰關(guān)聯(lián)。證書(shū)可以放在用戶(hù)卡上。也可以存在LDAP服務(wù)器中。登錄模塊必須有用戶(hù)公鑰才能進(jìn)行驗證。登錄交互過(guò)程如圖三所示。
圖三
模塊具體實(shí)現的核心方法是:
private boolean verifySign () throws java.security.Invalid·KeyExeepfion
本方法的主要功能是:
(1)取得智能卡上公私鑰對的存儲位置。
執行數字簽名的時(shí)候需要使用私鑰。雖然智能卡上的私鑰不可導出,但可以取得一個(gè)指向私鑰的引用。通過(guò)引用進(jìn)行簽名操作。某具體智能卡的密鑰對存儲在3F00:0600:0606,首先得到了密鑰對位置:
CardFilePath EF_key=new CardFilePath(“:3F00:0600:0606”);
CardFilePath DF=new CardFilePatll (“:3F00:0600”);
智能卡中密鑰對只能通過(guò)智能卡操作系統引用,而不能使用普通的密鑰對引用方式,只能使用GPKSignatureKeyFile取到卡上密鑰對引用:
GPKSignatureKeyFile KeyFfle = new GPKSignatureKeyFile
(ef_key,512,GPKRSAKeyFile.UNCERTIFIED_KEY);
(2)生成用于挑戰的隨機數。隨機數生成利用了ScureRandom類(lèi),本類(lèi)是一個(gè)高強度偽隨機數生成器,即PRNG(pseudo-random number generator),它保證每次輸出的值沒(méi)有任何規律, 即符合RFC 1750 (Randomness Recommendations for Security)。使用時(shí)比較簡(jiǎn)單:
SecureRandom random=new SecureRandom();
Random.nextBytes(dataToSign);
(3)利用卡上的簽名功能對隨機數進(jìn)行簽名
a.取得智能卡上的簽名服務(wù)引用GPKSignatureService(GPKSignatureService)sm.getCardServiee(SignatureCardService.class,false);
b.調用簽名方法signData,其中參數分別是密鑰文件(在步驟a中取得)、智能卡支持的簽名方法、智能卡支持的填充方式和待簽數據;
byte 口signature1=ArtificalCardVerifys.signData (KeyFile,GPKStandardNames.MD5_RSA.GPKStandardNames.PKCS_PADDING,data To Sign);
其中PKCS padding標準的定義是:必須在被加密的數據后添加額外的字節,使加密后的數據長(cháng)度為加密塊長(cháng)度的整數倍。第二個(gè)參數指明了采用PKCS填充方式:簽后的數據存放在signaturel里,即挑戰得到的響應。
(4)驗證用戶(hù)數字證書(shū)是否正確
a.取得用戶(hù)數字證書(shū)
本設計中CA簽名的證書(shū)存放在3F00:0500:0503位置上,直接使用GPK智能卡的文件系統服務(wù)GPKFileAccessService中read方法:facs.read(file.getPath(),0,file.getLength())
讀出證書(shū)文件后,強制轉換為java.security.cert.Certificate,形成證書(shū)對象cardSignedCert(1ltiiE書(shū)由CA向用戶(hù)頒發(fā).可以從智能卡內獲得,也可以從LDAP服務(wù)器中取得):
b.取得CA數字證書(shū)
本設計中CA證書(shū)存放在LDAP服務(wù)器的根節點(diǎn)上,通過(guò)JNDI操作取得證書(shū)對象iava.security.cert.Certificate對象cac;
c.從CA證書(shū)中取得公鑰(get Public Key方法):
d.使用被驗證證書(shū)對象的verify()方法,驗證cardSignedCert是否由cac簽發(fā),如果驗證失敗則拋出異常返回;
(5)驗證挑戰,響應的結果是否正確
第3步工作得到響應數據signaturel.第4步工作驗證了用戶(hù)公鑰和用戶(hù)名是對應的。原始的挑戰數據在dataToSign中;這里需要驗證響應數據是否正確.工作步驟如下:
a.取得原始挑戰數據dataToSign:
b.取得簽名signaturel:
e.取得客戶(hù)的公鑰,取得方法是eardSignedCert.getPublicK.ey();
d.調用方法verifySignedData(),此方法帶四個(gè)參數,第一個(gè)是智能卡上存公鑰的位置,第二個(gè)是簽名算法名,第三個(gè)是原始數據,第四個(gè)是簽名數據,方法拋出openeard.core.service.Card.ServiceException異常和InvalidKeyException異常。調用的核心語(yǔ)句是:
vefifySignedData (KeyFile,MD5withRSA,dataToSign,signature1)
調用返回true表示挑戰/響應過(guò)程成功??梢赞D向 commit 方法提交用戶(hù)身份
四、智能卡認證結果的傳遞
驗證模塊APPlet 嵌入在A(yíng)SP或者ASP.NET制作的登錄網(wǎng)頁(yè)中,該模塊驗證成功后應該把登錄信息傳遞給業(yè)務(wù)系統首頁(yè)。這里使用JSObjec類(lèi)來(lái)解決 Applet 的信息向動(dòng)態(tài)網(wǎng)頁(yè)傳遞的問(wèn)題。
圖四
(1)Applet 向登錄網(wǎng)頁(yè)傳參數
從APPlet 的角度來(lái)看,驗證模塊調用login方法成功后取得Subject(同時(shí)取得了用戶(hù)名和登錄成功的狀態(tài))。這里把用戶(hù)名和登錄狀態(tài)先傳給JSObject.JSObjeet的方法允許Applet與文檔對象交互,并調用javascript函數。在A(yíng)pplet中加入下列代碼:Drivate JSObject win;//說(shuō)明一個(gè)JSObject對象win=JSObject.getWindow(this):/ 和當前腳本環(huán)境建立聯(lián)系JSObject可以調用腳本環(huán)境中的函數,利用此特性可以把用戶(hù)名和驗證成功的狀態(tài)傳遞給腳本函數fillin.調用時(shí)使用的代碼如下:
args[0]=username;
agrs[1]=“success”;
win.call(“fillin”,args);
(2)網(wǎng)頁(yè)接受Applet的參數并填人表單域
從腳本角度來(lái)看,需要定義一個(gè)函數fillin接受來(lái)自Applet的參數,該函數帶有兩個(gè)參數分別對應用戶(hù)名和驗證狀態(tài),函數的代碼實(shí)現如下:
function fiUin(namel,status1)
{artiticatCardVerify.LoginName.value=name1;artificalCardVerify.status.value=statusl;)
其中artificalCardVerify是驗證網(wǎng)頁(yè)中的表單名.LoginName是用戶(hù)名,在網(wǎng)頁(yè)上不能修改;status是狀態(tài)域,屬性為隱藏,它用于業(yè)務(wù)網(wǎng)頁(yè)判斷來(lái)源是否合法:表單提交后轉向業(yè)務(wù)網(wǎng)頁(yè):
<form method=“POST”action=“artificalCardVerify_login_redirect.a(chǎn)sp”name=“artificalCardVerify”>
(3)業(yè)務(wù)網(wǎng)頁(yè)視圖
業(yè)務(wù)網(wǎng)頁(yè)用ASP或者ASP.NET編寫(xiě),接受來(lái)自登錄網(wǎng)頁(yè)的提交。業(yè)務(wù)網(wǎng)頁(yè)首先檢查是否登錄成功(status域為Success、用戶(hù)名不為空),從業(yè)務(wù)權限表取得該用戶(hù)對應的業(yè)務(wù)權限后,進(jìn)入正常業(yè)務(wù)邏緝。
五、結語(yǔ):
在具有完備PKI 基礎的應用環(huán)境中,實(shí)現基于JAAS 和智能卡的通用身份認證模塊能夠將業(yè)務(wù)系統中的認證模塊分離出來(lái)。提高驗證的安全級別,方便開(kāi)發(fā)者使用和維護。作為一個(gè)可撥插模塊,任何 Web 應用程序都可以將此模塊植入。使用的代碼極少,而安全級別很高。隨著(zhù)智能卡技術(shù)的不斷發(fā)展,使用Java 智能卡將能進(jìn)一步提高驗證的安全性和靈活性。