2013-10-31 25 views
3

我有一個Javafx應用程序,它通過HTTPS將GET和POST請求發送到安全的Web服務。承載Web服務的服務器上的SSL設置是單向ssl,即Javafx應用程序驗證服務器的身份,但服務器不驗證胖客戶端的身份。如何從JavaFX應用程序連接到HTTPS URL

應用程序服務器位於具有證書(由外部授權機構簽名)的F5後面。

對於瀏覽器來說,這不會是一個問題,因爲瀏覽器本身處理驗證服務器的身份並向用戶顯示相關的警告。但對於胖客戶端,我不確定如何在發送請求之前驗證服務器的身份。請讓我知道如何在Javafx應用程序中處理這個問題。

我的確詢問過有關此早期herehere的問題,但這些都沒有幫助。所以,請原諒我對這個主題的有限知識。

任何幫助,將不勝感激。

+0

如果已知的(你的Java版本),CA和_valid_頒發服務器證書(它包括各個方面:PKIX鏈,日期不前 - 沒有,CN,擴展等),一切都應該工作,沒有任何額外的代碼。簡單的HttpsUrlConnection將完成這項工作。 – user1516873

+0

而HttpsUrl連接將檢查所有內容,因此無法通過https協議連接到具有無效證書的網站。事實上,如果您擁有帶有舊根CA證書的舊Java版本,則甚至不能使用有效證書連接到站點,而是使用新CA頒發,因爲java內部密鑰庫中沒有它。 – user1516873

+0

如果你想了解更多關於ssl/https以及它是如何工作的,我推薦這篇文章http://www.zytrax.com/tech/survival/ssl.html – user1516873

回答

5

如果您的證書在Firefox/java中不起作用,那麼很有可能它的發行者未被Firefox/java所知。

如何使其工作:

  1. 讓您的服務器的完整證書鏈。你可以用Firefox做到這一點。查看證書 - >詳細信息 - >導出到.pem文件。在您的案例鏈中將包含至少2個證書(Cerver證書和CA證書,CA可能自簽名或可能不)在.pem文件中導出CA證書。

  2. 現在您可以強制java信任該CA,可以通過多種方式完成此操作,例如,您可以在jce cacerts中添加CA證書或爲HttpsURLConnection創建自定義SSLContext。

  3. 如果你做DNS或etchosts修改,請將其回滾。連接地址應該與證書CN匹配,包含通配符。

  4. 使用該代碼連接到您的服務器:

    public void test() throws Exception { 
        URL u = new URL(
          "https://my-server.com/my-webservices/data"); 
        HttpsURLConnection http = (HttpsURLConnection) u.openConnection(); 
        http.setSSLSocketFactory(createSSLContext().getSocketFactory()); 
        http.setAllowUserInteraction(true); 
        http.setRequestMethod("GET"); 
        http.connect(); 
    
        InputStream is = http.getInputStream(); 
        BufferedReader reader = new BufferedReader(new InputStreamReader(is)); 
        StringBuilder stringBuilder = new StringBuilder(); 
        String line = null; 
        while ((line = reader.readLine()) != null) 
        { 
         stringBuilder.append(line 
           + "\n"); 
        } 
        System.out.println(stringBuilder.toString()); 
    
    } 
    
    private SSLContext createSSLContext() throws Exception { 
        CertificateFactory cf = CertificateFactory.getInstance("X.509"); 
        FileInputStream in = new FileInputStream("path_to_ca_file.pem"); 
        KeyStore trustStore = KeyStore.getInstance("JKS"); 
        trustStore.load(null); 
        try { 
         X509Certificate cacert = (X509Certificate) cf.generateCertificate(in); 
         trustStore.setCertificateEntry("ca", cacert); 
        } finally { 
         IOUtils.closeQuietly(in); 
        } 
    
        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); 
        tmf.init(trustStore); 
    
        SSLContext sslContext = SSLContext.getInstance("SSL"); 
        sslContext.init(null, tmf.getTrustManagers(), new SecureRandom()); 
        return sslContext; 
    } 
    
+1

感謝您的回覆[user1516873](http://stackoverflow.com/users/1516873/user1516873)。我試圖避免將證書打包到本地,因爲證書過期時,則需要更新。我認爲如果應用程序總是與服務器上的證書一起工作,那麼這將是最好的解決方案。有沒有辦法做到這一點? – Aspirant

+2

是的,應用程序可以使用從服務器獲得的任何證書,但它只消除一種攻擊 - 嗅探。 MITM http://en.wikipedia.org/wiki/Man-in-the-middle_attack和etc/hosts重寫仍然可以應用於那種https。 – user1516873

+0

因此,只要不像上面的代碼那樣設置SSLSocketFactory就可以實現這一點?謝謝。 'http.setSSLSocketFactory(createSSLContext()。getSocketFactory());' – Aspirant

相關問題