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