2013-11-01 84 views
23

Web服務是通過SSL進行的休眠,它具有自簽名證書,託管在遠程系統中。我已經創建了訪問該Web服務的客戶端。這是通過將證書添加到key store programatically來完成的。Java:覆蓋功能以禁用SSL證書檢查

現在我聽說,沒有必要向密鑰存儲區添加證書以訪問自簽名的Web服務。 相反,我們可以通過重寫某些方法來禁用證書檢查。這是真的?哪些是這些方法?請幫忙。

+3

Web服務不應該有一個自簽名的證書。期。支付這筆費用並由CA簽署。你所聽到的確是正確的,但它也是非常不可取的。它需要在客戶端進行特殊編程,這會引入(a)安全問題,(b)發展風險和(c)部署問題。 – EJP

+4

該Web服務尚未發佈。它正在工作。這就是爲什麼現在它沒有通過可信CA認證。已知通過禁用這些證書檢查來使用服務是不理想的。儘管我需要檢查它。請幫忙。謝謝@EJP – Sumithlal

+3

爲臨時解決方案花費的任何努力(a)浪費時間和金錢,(b)引入安全風險,即您將「意外」部署到生產環境中。現在花錢。只有幾百美元。 – EJP

回答

30

這應該是足夠的。我在測試代碼時針對測試和登臺服務器(我們沒有正確簽名的證書)使用此代碼。 但是,您真的應該非常認真地考慮在生產服務器上獲取有效的SSL證書。沒有人希望被竊聽,並侵犯了他們的隱私。

SSLContext sc = SSLContext.getInstance("TLS"); 
sc.init(null, new TrustManager[] { new TrustAllX509TrustManager() }, new java.security.SecureRandom()); 
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); 
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier(){ 
    public boolean verify(String string,SSLSession ssls) { 
     return true; 
    } 
}); 

而這。

import javax.net.ssl.X509TrustManager; 
import java.security.cert.X509Certificate; 

/** 
* DO NOT USE IN PRODUCTION!!!! 
* 
* This class will simply trust everything that comes along. 
* 
* @author frank 
* 
*/ 
public class TrustAllX509TrustManager implements X509TrustManager { 
    public X509Certificate[] getAcceptedIssuers() { 
     return new X509Certificate[0]; 
    } 

    public void checkClientTrusted(java.security.cert.X509Certificate[] certs, 
      String authType) { 
    } 

    public void checkServerTrusted(java.security.cert.X509Certificate[] certs, 
      String authType) { 
    } 

} 

祝你好運!

=== UPDATE ===

我只是想指出的是,有一個名爲Let's Encrypt服務,它能夠自動生成並設置SSL的過程/ TLS證書被幾乎所有人都承認,這是絕對自由!

+0

感謝您的回覆。只有在jssecert或cacert中添加了證書時才能使用。如果證書被刪除並運行,那麼我得到的錯誤是SSLHandshakeException 。它還警告「無法發送消息」。 – Sumithlal

+0

不應該如此。在使用具有自簽名證書的密鑰庫時,可以使用javax.ssl.something = keystore.jks設置密鑰庫。使用此方法時不應該設置。我會盡快重新測試。 – Paaske

+2

getAcceptedIssuers()的返回值可能不爲null。看到Javadoc。 – EJP

10

由於任何其他代碼仍將使用安全默認值,因此忽略每個連接的證書安全得多。

下面的代碼:

  • 覆蓋在每個連接的基礎上的信任管理器和主機名驗證。
  • 重用SSLSocketFactory以支持持久連接,避免了對同一服務器的重複請求進行昂貴的SSL握手。

正如其他人所說,這應該只用於測試,和/或內部系統與其他內部系統通信。

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 
import java.net.HttpURLConnection; 
import java.net.URL; 
import java.security.KeyManagementException; 
import java.security.NoSuchAlgorithmException; 
import java.security.cert.X509Certificate; 

import javax.net.ssl.HostnameVerifier; 
import javax.net.ssl.HttpsURLConnection; 
import javax.net.ssl.SSLContext; 
import javax.net.ssl.SSLSession; 
import javax.net.ssl.SSLSocketFactory; 
import javax.net.ssl.TrustManager; 
import javax.net.ssl.X509TrustManager; 

public class TestPersistentConnection 
{ 
    private static SSLSocketFactory sslSocketFactory = null; 

    /** 
    * Use the VM argument <code>-Djavax.net.debug=ssl</code> for SSL specific debugging; 
    * the SSL handshake will appear a single time when connections are re-used, and multiple 
    * times when they are not. 
    * 
    * Use the VM <code>-Djavax.net.debug=all</code> for all network related debugging, but 
    * note that it is verbose. 
    * 
    * @throws Exception 
    */ 
    public static void main(String[] args) throws Exception 
    { 

     //URL url = new URL("https://google.com/"); 
     URL url = new URL("https://localhost:8443/"); 

     // Disable first 
     request(url, false); 

     // Enable; verifies our previous disable isn't still in effect. 
     request(url, true); 
    } 

    public static void request(URL url, boolean enableCertCheck) throws Exception { 
     BufferedReader reader = null; 
     // Repeat several times to check persistence. 
     System.out.println("Cert checking=["+(enableCertCheck?"enabled":"disabled")+"]"); 
     for (int i = 0; i < 5; ++i) { 
      try { 

       HttpURLConnection httpConnection = (HttpsURLConnection) url.openConnection(); 

       // Normally, instanceof would also be used to check the type. 
       if(! enableCertCheck) { 
        setAcceptAllVerifier((HttpsURLConnection)httpConnection); 
       } 

       reader = new BufferedReader(new InputStreamReader(httpConnection.getInputStream()), 1); 

       char[] buf = new char[1024]; 
       StringBuilder sb = new StringBuilder(); 
       int count = 0; 
       while(-1 < (count = reader.read(buf))) { 
        sb.append(buf, 0, count); 
       } 
       System.out.println(sb.toString()); 

       reader.close(); 

      } catch (IOException ex) { 
       System.out.println(ex); 

       if(null != reader) { 
        reader.close(); 
       } 
      } 
     } 
    } 

    /** 
    * Overrides the SSL TrustManager and HostnameVerifier to allow 
    * all certs and hostnames. 
    * WARNING: This should only be used for testing, or in a "safe" (i.e. firewalled) 
    * environment. 
    * 
    * @throws NoSuchAlgorithmException 
    * @throws KeyManagementException 
    */ 
    protected static void setAcceptAllVerifier(HttpsURLConnection connection) throws NoSuchAlgorithmException, KeyManagementException { 

     // Create the socket factory. 
     // Reusing the same socket factory allows sockets to be 
     // reused, supporting persistent connections. 
     if(null == sslSocketFactory) { 
      SSLContext sc = SSLContext.getInstance("SSL"); 
      sc.init(null, ALL_TRUSTING_TRUST_MANAGER, new java.security.SecureRandom()); 
      sslSocketFactory = sc.getSocketFactory(); 
     } 

     connection.setSSLSocketFactory(sslSocketFactory); 

     // Since we may be using a cert with a different name, we need to ignore 
     // the hostname as well. 
     connection.setHostnameVerifier(ALL_TRUSTING_HOSTNAME_VERIFIER); 
    } 

    private static final TrustManager[] ALL_TRUSTING_TRUST_MANAGER = new TrustManager[] { 
     new X509TrustManager() { 
      public X509Certificate[] getAcceptedIssuers() { 
       return null; 
      } 
      public void checkClientTrusted(X509Certificate[] certs, String authType) {} 
      public void checkServerTrusted(X509Certificate[] certs, String authType) {} 
     } 
    }; 

    private static final HostnameVerifier ALL_TRUSTING_HOSTNAME_VERIFIER = new HostnameVerifier() { 
     public boolean verify(String hostname, SSLSession session) { 
      return true; 
     } 
    }; 

} 

非常感謝: http://runtime32.blogspot.com/2008/11/let-java-ssl-trust-all-certificates.html

+0

你是否確定它在每個連接的基礎上工作?使用'SSLContext.getInstance'我永遠不知道它是吸氣劑還是什麼... – maaartinus

+0

相當確定。在示例程序中唯一的替換是enableCertCheck爲false(通過setAcceptAllVerifier(...))。如果系統範圍的套接字工廠和主機名驗證器被替換,則第二次調用main()中的request(url,true)會在標準輸出上打印一個異常。否則,它將被改變的唯一方式是暫時通過連接本身,這將在它完成後恢復它,這看起來不太可能。 –

+0

這個工程!我有用於禁用證書檢查的'setDefaultSSLSocketFactory'版本,但它使我到另一個網站的其他連接確實需要證書檢查失敗。我只是適應了這一點,現在我可以連接到兩個https站點 – jpp1jpp1

0
TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() { 
        public java.security.cert.X509Certificate[] getAcceptedIssuers() { 
         return null; 
        } 
        public void checkClientTrusted(X509Certificate[] certs, String authType) { 
        } 
        public void checkServerTrusted(X509Certificate[] certs, String authType) { 
        } 
       } 
      }; 
      SSLContext sc = SSLContext.getInstance("SSL"); 
      sc.init(null, trustAllCerts, new java.security.SecureRandom()); 
      HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); 

      HostnameVerifier allHostsValid = new HostnameVerifier() { 
       public boolean verify(String hostname, SSLSession session) { 
        return true; 
       } 
      }; 
      HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid); 
      GetCustomerPhone http = new GetCustomerPhone(); 

    System.out.println("Processing..");  
    try{ 
      http.sendPost();  
     } 
    catch(Exception e){ 
      e.printStackTrace(); 
     }    
} 

我認爲它會工作fine.because它我的罰款...