2009-07-29 19 views
47

Pracowałem nad programem do wyodrębniania informacji z dynamicznej aplikacji internetowej, a program działał poprawnie, dopóki nie ustawię serwera tomcat do korzystania z SSL za pomocą self-self podpisany (a więc niezaufany) certyfikat. Ślad stosu błędu jest:Zezwalanie Java na używanie niezaufanego certyfikatu dla połączenia 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) 

W przeglądarce internetowej, użytkownik jest proszony ostrzeżenie podczas uzyskiwania dostępu do witryny HTTPS z niezaufanym certyfikatem, i poprosił, aby zrobić wyjątek jeśli lubi postępować; Chciałbym zaimplementować podobną funkcjonalność dla mojej aplikacji wiersza poleceń ... Przyznaję, że jestem nowy w zakresie programowania gniazd i ogólnie w sieci; każda rada rozwiązująca ten problem będzie świetna!

+0

Możesz użyć [tej implementacji] (http://abhinavasblog.blogspot.com/2011/07 /allow-untrusted-certificate-for-https.html) ... ma dwie części 1. plik klasy ze statyczną metodą do wywołania przed 'Https' call – Abhinava

Odpowiedz

73

Here jakiś odpowiedni kod:

// 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) { 
} 

To będzie całkowicie wyłączyć sprawdzanie SSL-tylko nie uczyć się obsługi wyjątku od takiego kodu!

Aby zrobić to, co chcesz, musisz zaimplementować kontrolę w swoim TrustManager, który monituje użytkownika.

+6

To jest sposób, aby to zrobić; jednak musisz być naprawdę ostrożny, aby ten kod nie trafił do produkcji - a jeśli używasz niezaufanych certyfikatów w aplikacji produkcyjnej, jest to Złe. Jeśli masz strukturę zastrzyków zależności, taką jak wiosna w swojej aplikacji, rozważ izolowanie tego kodu i zainstalowanie bezpiecznej wersji dla środowiska produkcyjnego. –

+3

Parametr 'new java.security.SecureRandom()' można również zastąpić przez 'null'. –

+0

Od wersji Java 7 użytkownik 'X509ExtendedTrustManager'rather może ominąć kolejne problemy, takie jak ograniczenia algorytmów. Oczywiście muszę powtórzyć komentarz @ TimHowland .. – amcc

5

Następujący kod z here jest przydatnym rozwiązaniem. Brak magazynów kluczy itp. Po prostu wywołaj metodę SSLUtilities.trustAllHttpsCertificates() przed zainicjalizowaniem usługi i portu (w SOAP).

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

Inną opcją jest dostać „.pem” (klucz publiczny) złożyć do danego serwera, a następnie zainstalować go lokalnie do serca «cacerts» złożyć JRE, a następnie będzie mógł pobrać od ten serwer bez reklamacji, bez naruszania całej struktury SSL uruchomionej maszyny JVM i umożliwiającej pobieranie z innych nieznanych serwerów certyfikatów ...

Powiązane problemy