摘 要JSSE是一個SSL和TLS的純Java實現,通過JSSE可以很輕易地編程實現對HTTPS站點的訪問。但是,假如該站點的證書未經權威機構的驗證,JSSE將拒絕信任該證書從而不能訪問HTTPS站點。本文在簡要介紹JSSE的基礎上提出了兩種解決該問題的方法。
引言
過去的十幾年,網絡上已經積累了大量的Web應用。如今,無論是整合原有的Web應用系統,還是進行新的Web開發,都要求通過編程來訪問某些Web頁面。傳統的方法是使用Socket接口,但現在很多開發平台或工具如.NET、Java或PHP等都提供了簡單的Web訪問接口,使用這些接口很輕易編程實現與Web應用系統的交互訪問,即使要訪問那些采用了HTTPS而不是HTTP的Web應用系統。
HTTPS,即安全的超文本傳輸協議,采用了SSL技術,被廣泛使用以保證Web應用系統的安全性。訪問Web應用的編程接口大多封裝了SSL,使得訪問HTTPS和訪問HTTP一樣簡單。但是很多中、小型應用系統或基於局域網、校園網的應用系統所使用的證書並不是由權威的認證機構發行或者被其驗證,直接使用這些編程接口將不能訪問HTTPS。
本文將在簡要介紹JSSE的基礎上,具體描述使用JSSE訪問HTTPS的方法,主要說明了如何訪問帶有未經驗證證書的HTTPS站點。
JSSE簡介
Java安全套接擴展 (Java Secure Socket Extension, JSSE)是實現Internet安全通信的一系列包的集合。它是一個SSL和TLS的純Java實現,可以透明地提供數據加密、服務器認證、信息完整性等功能,可以使我們像使用普通的套接字一樣使用JSSE建立的安全套接字。JSSE是一個開放的標准,不只是Sun公司才能實現一個JSSE,事實上其他公司有自己實現的JSSE。
在深入了解JSSE之前,需要了解一個有關Java安全的概念:客戶端的TrustStore文件。客戶端的TrustStore文件中保存著被客戶端所信任的服務器的證書信息。客戶端在進行SSL連接時,JSSE將根據這個文件中的證書決定是否信任服務器端的證書。
JSSE中,有一個信任治理器類負責決定是否信任遠端的證書,這個類有如下的處理規則:
⑴ 果系統屬性javax.net.sll.trustStore指定了TrustStore文件,那麼信任治理器就去jre安裝路徑下的lib/security/目錄中尋找並使用這個文件來檢查證書。
⑵ 果該系統屬性沒有指定TrustStore文件,它就會去jre安裝路徑下尋找默認的TrustStore文件,這個文件的相對路徑為:lib/security/jssecacerts。
⑶ 假如 jssecacerts不存在,但是cacerts存在(它隨J2SDK一起發行,含有數量有限的可信任的基本證書),那麼這個默認的TrustStore文件就是cacerts。
直接使用類HttpsURLConnection訪問Web頁面
Java提供了一種非常簡潔的方法來訪問HTTPS網頁,即使用類HttpsURLConnection、URL等。這幾個類為支持HTTPS對JSSE相關類做了進一步的封裝,例子如下所示:
URL reqURL = new URL("https://www.sun.com" ); //創建URL對象
HttpsURLConnection httpsConn = (HttpsURLConnection)reqURL.openConnection();
/*下面這段代碼實現向Web頁面發送數據,實現與網頁的交互訪問
httpsConn.setDoOutput(true);
OutputStreamWriter out = new OutputStreamWriter(hUC.getOutputStream(), "8859_1");
out.write( "……" );
out.flush();
out.close();
*/
//取得該連接的輸入流,以讀取響應內容
InputStreamReader insr = new InputStreamReader(httpsConn.getInputStream();
//讀取服務器的響應內容並顯示
int respInt = insr.read();
while( respInt != -1){
System.out.print((char)respInt);
respInt = insr.read();
}
這段代碼能夠正常執行,然而把訪問的URL改為https://login.bjut.edu.cn時,程序將拋出異常javax.net.ssl.SSLException,這是由於https://login.bjut.edu.cn站點的安全證書不被JSSE所信任。根據JSSE簡介中對信任治理器的分析,一種解決這個問題的方法是按照信任治理器的處理規則,把站點的證書放到證書庫文件jssecacerts中,或者把證書存放到任一TrustStore文件中,然後設置系統屬性javax.net.sll.trustStore指向該文件。另一種解決方法則是自己實現信任治理器類,讓它信任我們指定的證書。下面分別介紹這兩種方法。
將證書導入到TrustStore文件中
Java提供了命令行工具keytool用於創建證書或者把證書從其它文件中導入到Java自己的TrustStore文件中。把證書從其它文件導入到TrustStore文件中的命令行格式為:
keytool -import -file src_cer_file –keystore dest_cer_store
其中,src_cer_file為存有證書信息的源文件名,dest_cer_store為目標TrustStore文件。
在使用keytool之前,首先要取得源證書文件,這個源文件可使用IE浏覽器獲得,IE浏覽器會把訪問過的HTTPS站點的證書保存到本地。從IE浏覽器導出證書的方法是打開“Internet 選項”,選擇“內容”選項卡,點擊“證書…”按鈕,在打開的證書對話框中,選中一個證書,然後點擊“導出…”按鈕,按提示一步步將該證書保存到一文件中。最後就可利用keytool把該證書導入到Java的TrustStore文件中。為了能使Java程序找到該文件,應該把這個文件復制到jre安裝路徑下的lib/security/目錄中。
這樣,只需在程序中設置系統屬性javax.net.sll.trustStore指向文件dest_cer_store,就能使JSSE信任該證書,從而使程序可以訪問使用未經驗證的證書的HTTPS站點。
使用這種方法,編程非常簡單,但需要手工導出服務器的證書。當服務器證書經常變化時,就需要經常進行手工導出證書的操作。下面介紹的實現X509證書信任治理器類的方法將避免手工導出證書的問題。