2009-07-29 63 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结构,并可从其他未知证书服务器下载...

相关问题