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