Java が SSL/HTTPS 接続に信頼できない証明書を使用できるようにする

StackOverflow https://stackoverflow.com/questions/1201048

  •  05-07-2019
  •  | 
  •  

質問

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

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

役に立ちましたか?

解決

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

// 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 に実装する必要があります。

他のヒント

こちらのコードに従うと、便利なソリューションが得られます。キーストアなどはありません。サービスとポートを(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

もう1つのオプションは、「。pem」を取得することです。 (特定のサーバー用の(公開鍵)ファイル、およびJREの「cacerts」の中心にローカルにインストールします。ファイルを作成すると、実行中のJVMのSSL構造全体を損なうことなく、他の不明な証明書サーバーからのダウンロードを有効にせずに、文句なしにそのサーバーからダウンロードできます...

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top