如何在java中绕过ssl证书检查

时间:2017-03-15 10:14:08

标签: java ssl-certificate

我想访问一个SOAP webservice url,其中https托管在远程虚拟机中。我在使用HttpURLConnection访问它时遇到异常。

这是我的代码:

import javax.net.ssl.*;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

/**
 * Created by prasantabiswas on 07/03/17.
 */
public class Main
{
    public static void main(String [] args)
    {
        try
        {
            URL url = new URL("https://myhost:8913/myservice/service?wsdl");
            HttpURLConnection http = null;

            if (url.getProtocol().toLowerCase().equals("https")) {
                trustAllHosts();
                HttpsURLConnection https = (HttpsURLConnection) url.openConnection();
                https.setHostnameVerifier(DO_NOT_VERIFY);
                http = https;
            } else {
                http = (HttpURLConnection) url.openConnection();
            }
            String SOAPAction="";
//            http.setRequestProperty("Content-Length", String.valueOf(b.length));
            http.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
            http.setRequestProperty("SOAPAction", SOAPAction);
            http.setRequestMethod("GET");
            http.setDoOutput(true);
            http.setDoInput(true);
            OutputStream out = http.getOutputStream();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    final static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    };

    private static void trustAllHosts() {
        // Create a trust manager that does not validate certificate chains
        TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return new java.security.cert.X509Certificate[] {};
            }

            public void checkClientTrusted(X509Certificate[] chain,
                                           String authType) throws CertificateException
            {
            }

            public void checkServerTrusted(X509Certificate[] chain,
                                           String authType) throws CertificateException {
            }
        } };

        // 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) {
            e.printStackTrace();
        }
    }
}

我遇到以下异常:

javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: Certificates does not conform to algorithm constraints
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1509)
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)
    at sun.security.ssl.Handshaker.process_record(Handshaker.java:914)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
    at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
    at sun.net.www.protocol.http.HttpURLConnection.getOutputStream0(HttpURLConnection.java:1283)
    at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1258)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:250)
    at Main.main(Main.java:35)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
Caused by: java.security.cert.CertificateException: Certificates does not conform to algorithm constraints
    at sun.security.ssl.AbstractTrustManagerWrapper.checkAlgorithmConstraints(SSLContextImpl.java:1055)
    at sun.security.ssl.AbstractTrustManagerWrapper.checkAdditionalTrust(SSLContextImpl.java:981)
    at sun.security.ssl.AbstractTrustManagerWrapper.checkServerTrusted(SSLContextImpl.java:923)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1491)
    ... 18 more

尝试了谷歌搜索的不同解决方案,非他们的工作。我想避免使用keytool,因为我将在不同的vm上运行我的测试。

有没有人对此有任何解决方案?

4 个答案:

答案 0 :(得分:10)

使用X509ExtendedTrustManager而不是X509TrustManager()解决了这个问题。这是一个例子:

 SELECT A.NAME, A,ADDRESS, B.VALUE as TABLE 
 FROM CRM A
   LEFT JOIN SomeTable B ON B.COD=101 AND B.XXXX = A.YYYY

答案 1 :(得分:4)

编辑:了解在使用之前可能导致的漏洞。这绝不建议用于生产用途。

最好的方法是创建一个信任一切的虚拟信任管理器。

 TrustManager[] dummyTrustManager = new TrustManager[] { new X509TrustManager() {
      public java.security.cert.X509Certificate[] getAcceptedIssuers() {
        return null;
      }

      public void checkClientTrusted(X509Certificate[] certs, String authType) {
      }

      public void checkServerTrusted(X509Certificate[] certs, String authType) {
      }
    } };

然后使用虚拟信任管理器初始化SSL上下文

SSLContext sc = SSLContext.getInstance("SSL");
    sc.init(null, dummyTrustManager, new java.security.SecureRandom());

最后使用SSLContext打开连接

HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

    URL url = new URL("https://myhost:8913/myservice/service?wsdl");

这个问题已经在这里得到了更详细的回答 Java: Overriding function to disable SSL certificate check

更新:

上述问题是由于Java不支持证书签名算法。根据{{​​3}},Java 8的更高版本已禁用md5算法。

要启用md5支持,请在< jre_home> / lib / security下找到java.security文件 并找到该行(535)

jdk.certpath.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, 

并删除MD5

答案 2 :(得分:2)

尝试使用Apache HTTP客户端,这对我有用。

SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, new TrustStrategy() {
     public boolean isTrusted(final X509Certificate[] chain, String authType) throws CertificateException {
          return true;
     }
});
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build());

CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();

// GET or POST request with the client
...

答案 3 :(得分:0)

除了使用HttpsURLConnection.setDefaultSSLSocketFactory和您自己的实现TrustManagerX509ExtendedTrustManager之外,您还可以将TrustManagerFactory与发布证书的证书一起使用KeyStore您需要信任(对于自签名证书,该证书与主机证书相同),并在特定实例上调用HttpsURLConnection.setSSLSocketFactory。这既减少了代码量,又避免了信任所有HTTPS证书的安全性问题。

main中:

            if (url.getProtocol().toLowerCase().equals("https")) {
                HttpsURLConnection https = (HttpsURLConnection) url.openConnection();
                https.setSSLSocketFactory(createSSLSocketFactory());
                http = https;
            }

方法createSSLSocketFactory如下所示:

    private static SSLSocketFactory createSSLSocketFactory() {
         File crtFile = new File("server.crt");
         Certificate certificate =          CertificateFactory.getInstance("X.509").generateCertificate(new FileInputStream(crtFile));

         KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
         keyStore.load(null, null);
         keyStore.setCertificateEntry("server", certificate);

         TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
         trustManagerFactory.init(keyStore);

         SSLContext sslContext = SSLContext.getInstance("TLS");
         sslContext.init(null, trustManagerFactory.getTrustManagers(), null);

         return sslContext.getSocketFactory();
    }