通過JSSE來發起Https請求

jopen 12年前發布 | 13K 次閱讀 JSSE 網絡工具包

    摘 要

    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("             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類的關系: 

                    通過JSSE來發起Https請求
                        圖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的安全性,但需要手工導入證書;第二種 方法雖然不用手工導入證書,但需要小心使用,否則會帶來一些安全隱患。

</span>來自:
http://tech.163.com/06/0406/09/2E11A15U0009159T.html

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!