注意一下文章中提到的jsse在jdk1.4之後已經集成了,沒必要糾結. java
摘 要 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證書信任管理器類的方法將避免手工導出證書的問題。
X509證書信任管理器類的實現及應用
在JSSE中,證書信任管理器類就是實現了接口X509TrustManager的類。咱們能夠本身實現該接口,讓它信任咱們指定的證書。
接口X509TrustManager有下述三個公有的方法須要咱們實現:
⑴ oid checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException
該方法檢查客戶端的證書,若不信任該證書則拋出異常。因爲咱們不須要對客戶端進行認證,所以咱們只須要執行默認的信任管理器的這個方法。JSSE中,默認的信任管理器類爲TrustManager。
⑵ oid checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException
該方法檢查服務器的證書,若不信任該證書一樣拋出異常。經過本身實現該方法,可使之信任咱們指定的任何證書。在實現該方法時,也能夠簡單的不作任何處理,即一個空的函數體,因爲不會拋出異常,它就會信任任何證書。
⑶ X509Certificate[] getAcceptedIssuers()
返回受信任的X509證書數組。
本身實現了信任管理器類,如何使用呢?類HttpsURLConnection彷佛並無提供方法設置信任管理器。其實,HttpsURLConnection經過SSLSocket來創建與HTTPS的安全鏈接,SSLSocket對象是由SSLSocketFactory生成的。HttpsURLConnection提供了方法setSSLSocketFactory(SSLSocketFactory)設置它使用的SSLSocketFactory對象。SSLSocketFactory經過SSLContext對象來得到,在初始化SSLContext對象時,可指定信任管理器對象。下面用一個圖簡單表示這幾個JSSE類的關係:
圖1 部分JSSE類的關係圖
|
假設本身實現的X509TrustManager類的類名爲:MyX509TrustManager,下面的代碼片段說明了如何使用MyX509TrustManager:
//建立SSLContext對象,並使用咱們指定的信任管理器初始化 TrustManager[] tm = {new MyX509TrustManager ()}; SSLContext sslContext = SSLContext.getInstance("SSL","SunJSSE"); sslContext.init(null, tm, new java.security.SecureRandom()); //從上述SSLContext對象中獲得SSLSocketFactory對象 SSLSocketFactory ssf = sslContext.getSocketFactory(); //建立HttpsURLConnection對象,並設置其SSLSocketFactory對象 HttpsURLConnection httpsConn = (HttpsURLConnection)myURL.openConnection(); httpsConn.setSSLSocketFactory(ssf); |
這樣,HttpsURLConnection對象就能夠正常鏈接HTTPS了,不管其證書是否經權威機構的驗證,只要實現了接口X509TrustManager的類MyX509TrustManager信任該證書。
小結
本文主要介紹了在HTTPS的證書未經權威機構認證的狀況下,訪問HTTPS站點的兩種方法,一種方法是把該證書導入到Java的TrustStore文件中,另外一種是本身實現並覆蓋JSSE缺省的證書信任管理器類。兩種方法各有優缺點,第一種方法不會影響JSSE的安全性,但須要手工導入證書;第二種方法雖然不用手工導入證書,但須要當心使用,不然會帶來一些安全隱患。