web-dev-qa-db-ja.com

JavaがSSL / HTTPS接続に信頼できない証明書を使用することを許可する

私は動的Webアプリケーションから情報を抽出するプログラムに取り組んでおり、自己署名(したがって、信頼できない)証明書を使用してSSLを使用するようにTomcatサーバーを設定するまで、プログラムは正常に機能しました。エラーのスタックトレースは次のとおりです。

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サイトにアクセスすると警告が表示され、続行する場合は例外を作成するように求められます。コマンドラインアプリケーションに同様の機能を実装したいのですが、ソケットプログラミングとネットワーキング全般は初めてだと思います。この問題を解決するためのアドバイスはすばらしいでしょう!

55
Midnight Blue

ここ は関連するコードです:

// 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でユーザーにプロンプ​​トを表示するチェックを実装する必要があります。

94
Yishai

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
7

別のオプションは、その特定のサーバーの「.pem」(公開鍵)ファイルを取得し、それをJREの「cacerts」ファイルの中心にローカルにインストールすることです。実行中のJVMのSSL構造全体と、他の未知の証明書サーバーからのダウンロードを可能にします...

3
rogerdpack