2009-07-29 82 views
47

我一直致力於從動態Web應用程序中提取信息的程序,並且程序正常工作,直到我將我的Tomcat服務器設置爲使用SSL簽名(因此,不可信)的證書。錯誤的堆棧跟蹤是:允許Java爲SSL/HTTPS連接使用不受信任的證書

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 
Error: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 
     at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:150) 
     at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1584) 
     at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:174) 
     at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:168) 
     at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:848) 
     at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:106) 
     at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:495) 
     at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:433) 
     at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:877) 
     at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1089) 
     at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1116) 
     at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1100) 
     at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:402) 
     at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:170) 
     at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:857) 
     at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:230) 
     at com.certicom.gls.glscs.nongui.URLReader$PostURL.setupURL(URLReader.java:34) 
     at com.certicom.gls.glscs.nongui.URLReader.getLogin(URLReader.java:227) 
     at com.certicom.gls.glscs.nongui.URLReader.testLogin(URLReader.java:436) 
     at com.certicom.gls.glscs.nongui.Controller.loginMenu(Controller.java:384) 
     at com.certicom.gls.glscs.nongui.Controller.menu(Controller.java:324) 
     at com.certicom.gls.glscs.nongui.Controller.<init>(Controller.java:49) 
     at com.certicom.gls.glscs.nongui.Controller.main(Controller.java:61) 

在Web瀏覽器,與不受信任的證書訪問HTTPS站點時,系統會提示用戶發出警告,並問他是否喜歡繼續破例;我想爲我的命令行應用程序實現類似的功能......我承認我對套接字編程和網絡一般是新手;任何解決這個問題的建議都會很棒!

+0

您可以使用[此實現](http://abhinavasblog.blogspot.com/2011/07 /allow-untrusted-certificate-for-https.html)... 它有兩個部分1.一個靜態方法的類文件被調用之前,你`Https`調用 – Abhinava 2011-07-26 04:22:46

回答

73

Here是一些相關的代碼:

// Create a trust manager that does not validate certificate chains 
TrustManager[] trustAllCerts = new TrustManager[]{ 
    new X509TrustManager() { 
     public java.security.cert.X509Certificate[] getAcceptedIssuers() { 
      return null; 
     } 
     public void checkClientTrusted(
      java.security.cert.X509Certificate[] certs, String authType) { 
     } 
     public void checkServerTrusted(
      java.security.cert.X509Certificate[] certs, String authType) { 
     } 
    } 
}; 

// Install the all-trusting trust manager 
try { 
    SSLContext sc = SSLContext.getInstance("SSL"); 
    sc.init(null, trustAllCerts, new java.security.SecureRandom()); 
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); 
} catch (Exception e) { 
} 

// Now you can access an https URL without having the certificate in the truststore 
try { 
    URL url = new URL("https://hostname/index.html"); 
} catch (MalformedURLException e) { 
} 

這將完全禁用SSL檢查,就是不學異常從這些代碼處理!

要做你想做的事情,你必須在你的TrustManager中執行一個檢查來提示用戶。

+6

這是做到這一點的方式;然而,你需要非常小心,這段代碼並沒有完成生產 - 如果你在生產應用程序中使用不受信任的證書,這是一件壞事。 如果您的應用程序中有像Spring這樣的依賴注入框架,請考慮隔離此代碼併爲生產環境提供安全版本。 – 2009-07-29 15:31:41

5

以下代碼來自here是一個有用的解決方案。沒有密鑰庫等。在初始化服務和端口(在SOAP中)之前調用方法SSLUtilities.trustAllHttpsCertificates()。

import java.security.GeneralSecurityException; 
import java.security.SecureRandom; 
import java.security.cert.X509Certificate; 
import javax.net.ssl.HostnameVerifier; 
import javax.net.ssl.HttpsURLConnection; 
import javax.net.ssl.SSLContext; 
import javax.net.ssl.TrustManager; 
import javax.net.ssl.X509TrustManager; 

/** 
* This class provide various static methods that relax X509 certificate and 
* hostname verification while using the SSL over the HTTP protocol. 
* 
* @author Jiramot.info 
*/ 
public final class SSLUtilities { 

    /** 
    * Hostname verifier for the Sun's deprecated API. 
    * 
    * @deprecated see {@link #_hostnameVerifier}. 
    */ 
    private static com.sun.net.ssl.HostnameVerifier __hostnameVerifier; 
    /** 
    * Thrust managers for the Sun's deprecated API. 
    * 
    * @deprecated see {@link #_trustManagers}. 
    */ 
    private static com.sun.net.ssl.TrustManager[] __trustManagers; 
    /** 
    * Hostname verifier. 
    */ 
    private static HostnameVerifier _hostnameVerifier; 
    /** 
    * Thrust managers. 
    */ 
    private static TrustManager[] _trustManagers; 

    /** 
    * Set the default Hostname Verifier to an instance of a fake class that 
    * trust all hostnames. This method uses the old deprecated API from the 
    * com.sun.ssl package. 
    * 
    * @deprecated see {@link #_trustAllHostnames()}. 
    */ 
    private static void __trustAllHostnames() { 
    // Create a trust manager that does not validate certificate chains 
    if (__hostnameVerifier == null) { 
     __hostnameVerifier = new SSLUtilities._FakeHostnameVerifier(); 
    } // if 
    // Install the all-trusting host name verifier 
    com.sun.net.ssl.HttpsURLConnection 
      .setDefaultHostnameVerifier(__hostnameVerifier); 
    } // __trustAllHttpsCertificates 

    /** 
    * Set the default X509 Trust Manager to an instance of a fake class that 
    * trust all certificates, even the self-signed ones. This method uses the 
    * old deprecated API from the com.sun.ssl package. 
    * 
    * @deprecated see {@link #_trustAllHttpsCertificates()}. 
    */ 
    private static void __trustAllHttpsCertificates() { 
    com.sun.net.ssl.SSLContext context; 

    // Create a trust manager that does not validate certificate chains 
    if (__trustManagers == null) { 
     __trustManagers = new com.sun.net.ssl.TrustManager[]{new SSLUtilities._FakeX509TrustManager()}; 
    } // if 
    // Install the all-trusting trust manager 
    try { 
     context = com.sun.net.ssl.SSLContext.getInstance("SSL"); 
     context.init(null, __trustManagers, new SecureRandom()); 
    } catch (GeneralSecurityException gse) { 
     throw new IllegalStateException(gse.getMessage()); 
    } // catch 
    com.sun.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(context 
      .getSocketFactory()); 
    } // __trustAllHttpsCertificates 

    /** 
    * Return true if the protocol handler property java. protocol.handler.pkgs 
    * is set to the Sun's com.sun.net.ssl. internal.www.protocol deprecated 
    * one, false otherwise. 
    * 
    * @return true if the protocol handler property is set to the Sun's 
    * deprecated one, false otherwise. 
    */ 
    private static boolean isDeprecatedSSLProtocol() { 
    return ("com.sun.net.ssl.internal.www.protocol".equals(System 
      .getProperty("java.protocol.handler.pkgs"))); 
    } // isDeprecatedSSLProtocol 

    /** 
    * Set the default Hostname Verifier to an instance of a fake class that 
    * trust all hostnames. 
    */ 
    private static void _trustAllHostnames() { 
     // Create a trust manager that does not validate certificate chains 
     if (_hostnameVerifier == null) { 
      _hostnameVerifier = new SSLUtilities.FakeHostnameVerifier(); 
     } // if 
     // Install the all-trusting host name verifier: 
     HttpsURLConnection.setDefaultHostnameVerifier(_hostnameVerifier); 
    } // _trustAllHttpsCertificates 

    /** 
    * Set the default X509 Trust Manager to an instance of a fake class that 
    * trust all certificates, even the self-signed ones. 
    */ 
    private static void _trustAllHttpsCertificates() { 
    SSLContext context; 

     // Create a trust manager that does not validate certificate chains 
     if (_trustManagers == null) { 
      _trustManagers = new TrustManager[]{new SSLUtilities.FakeX509TrustManager()}; 
     } // if 
     // Install the all-trusting trust manager: 
     try { 
      context = SSLContext.getInstance("SSL"); 
      context.init(null, _trustManagers, new SecureRandom()); 
     } catch (GeneralSecurityException gse) { 
      throw new IllegalStateException(gse.getMessage()); 
     } // catch 
     HttpsURLConnection.setDefaultSSLSocketFactory(context 
      .getSocketFactory()); 
    } // _trustAllHttpsCertificates 

    /** 
    * Set the default Hostname Verifier to an instance of a fake class that 
    * trust all hostnames. 
    */ 
    public static void trustAllHostnames() { 
     // Is the deprecated protocol setted? 
     if (isDeprecatedSSLProtocol()) { 
      __trustAllHostnames(); 
     } else { 
      _trustAllHostnames(); 
     } // else 
    } // trustAllHostnames 

    /** 
    * Set the default X509 Trust Manager to an instance of a fake class that 
    * trust all certificates, even the self-signed ones. 
    */ 
    public static void trustAllHttpsCertificates() { 
    // Is the deprecated protocol setted? 
    if (isDeprecatedSSLProtocol()) { 
     __trustAllHttpsCertificates(); 
    } else { 
     _trustAllHttpsCertificates(); 
    } // else 
    } // trustAllHttpsCertificates 

    /** 
    * This class implements a fake hostname verificator, trusting any host 
    * name. This class uses the old deprecated API from the com.sun. ssl 
    * package. 
    * 
    * @author Jiramot.info 
    * 
    * @deprecated see {@link SSLUtilities.FakeHostnameVerifier}. 
    */ 
    public static class _FakeHostnameVerifier implements 
     com.sun.net.ssl.HostnameVerifier { 

    /** 
    * Always return true, indicating that the host name is an acceptable 
    * match with the server's authentication scheme. 
    * 
    * @param hostname the host name. 
    * @param session the SSL session used on the connection to host. 
    * @return the true boolean value indicating the host name is trusted. 
    */ 
    public boolean verify(String hostname, String session) { 
     return (true); 
    } // verify 
    } // _FakeHostnameVerifier 

    /** 
    * This class allow any X509 certificates to be used to authenticate the 
    * remote side of a secure socket, including self-signed certificates. This 
    * class uses the old deprecated API from the com.sun.ssl package. 
    * 
    * @author Jiramot.info 
    * 
    * @deprecated see {@link SSLUtilities.FakeX509TrustManager}. 
    */ 
    public static class _FakeX509TrustManager implements 
     com.sun.net.ssl.X509TrustManager { 

    /** 
    * Empty array of certificate authority certificates. 
    */ 
    private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[]{}; 

    /** 
    * Always return true, trusting for client SSL chain peer certificate 
    * chain. 
    * 
    * @param chain the peer certificate chain. 
    * @return the true boolean value indicating the chain is trusted. 
    */ 
    public boolean isClientTrusted(X509Certificate[] chain) { 
     return (true); 
    } // checkClientTrusted 

    /** 
    * Always return true, trusting for server SSL chain peer certificate 
    * chain. 
    * 
    * @param chain the peer certificate chain. 
    * @return the true boolean value indicating the chain is trusted. 
    */ 
    public boolean isServerTrusted(X509Certificate[] chain) { 
     return (true); 
    } // checkServerTrusted 

    /** 
    * Return an empty array of certificate authority certificates which are 
    * trusted for authenticating peers. 
    * 
    * @return a empty array of issuer certificates. 
    */ 
    public X509Certificate[] getAcceptedIssuers() { 
     return (_AcceptedIssuers); 
    } // getAcceptedIssuers 
    } // _FakeX509TrustManager 

    /** 
    * This class implements a fake hostname verificator, trusting any host 
    * name. 
    * 
    * @author Jiramot.info 
    */ 
    public static class FakeHostnameVerifier implements HostnameVerifier { 

    /** 
    * Always return true, indicating that the host name is an acceptable 
    * match with the server's authentication scheme. 
    * 
    * @param hostname the host name. 
    * @param session the SSL session used on the connection to host. 
    * @return the true boolean value indicating the host name is trusted. 
    */ 
    public boolean verify(String hostname, javax.net.ssl.SSLSession session) { 
     return (true); 
    } // verify 
    } // FakeHostnameVerifier 

    /** 
    * This class allow any X509 certificates to be used to authenticate the 
    * remote side of a secure socket, including self-signed certificates. 
    * 
    * @author Jiramot.info 
    */ 
    public static class FakeX509TrustManager implements X509TrustManager { 

    /** 
    * Empty array of certificate authority certificates. 
    */ 
    private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[]{}; 

    /** 
    * Always trust for client SSL chain peer certificate chain with any 
    * authType authentication types. 
    * 
    * @param chain the peer certificate chain. 
    * @param authType the authentication type based on the client 
    * certificate. 
    */ 
    public void checkClientTrusted(X509Certificate[] chain, String authType) { 
    } // checkClientTrusted 

    /** 
    * Always trust for server SSL chain peer certificate chain with any 
    * authType exchange algorithm types. 
    * 
    * @param chain the peer certificate chain. 
    * @param authType the key exchange algorithm used. 
    */ 
    public void checkServerTrusted(X509Certificate[] chain, String authType) { 
    } // checkServerTrusted 

    /** 
    * Return an empty array of certificate authority certificates which are 
    * trusted for authenticating peers. 
    * 
    * @return a empty array of issuer certificates. 
    */ 
    public X509Certificate[] getAcceptedIssuers() { 
     return (_AcceptedIssuers); 
    } // getAcceptedIssuers 
    } // FakeX509TrustManager 
} // SSLUtilities 
2

另一種選擇是讓一個「質子交換膜」(公鑰)文件中查找特定的服務器,並進行本地安裝到你的JRE的‘cacerts的’文件的心臟,那麼這將是能夠從下載該服務器無需投訴,不會影響正在運行的JVM的整個SSL結構,並可從其他未知證書服務器下載...

相關問題