忽略Java的SSL验证(Ignoring SSL validation in Java)

2019-08-03 00:01发布

我打电话给托管Web服务器上的SSL证书无效的HTTP服务。 在开发中,我输入了keytool的证书,但该证书将是每个客户端上安装不同的,所以我不能只将其捆绑。

前言:我知道 ,跳绳SSL验证实在是太丑了。 在这种特殊情况下,我甚至不会需要SSL和系统中的所有其他通信都是通过简单的HTTP。 所以,我真的不关心MITM攻击或此类。 攻击者不需要去尽可能打破SSL,因为没有为数据没有SSL。 这是一个遗留系统在这我管不着支持。

我使用HttpURLConnectionSSLSocketFactory具有NaiveTrustManagerNaiveHostnameVerifier 。 此工程部分自签名的服务器我试过,但没有在客户的网站上。 我得到的错误是:

javax.net.ssl.SSLKeyException: [Security:090477]Certificate chain received from xxxxxxxxxx was not trusted causing SSL handshake failure.
    at com.certicom.tls.interfaceimpl.TLSConnectionImpl.fireException(Unknown Source)
    at com.certicom.tls.interfaceimpl.TLSConnectionImpl.fireAlertSent(Unknown Source)
    at com.certicom.tls.record.handshake.HandshakeHandler.fireAlert(Unknown Source)
    at com.certicom.tls.record.handshake.HandshakeHandler.fireAlert(Unknown Source)
    at com.certicom.tls.record.handshake.ClientStateReceivedServerHello.handle(Unknown Source)
    at com.certicom.tls.record.handshake.HandshakeHandler.handleHandshakeMessage(Unknown Source)
    at com.certicom.tls.record.handshake.HandshakeHandler.handleHandshakeMessages(Unknown Source)
    at com.certicom.tls.record.MessageInterpreter.interpretContent(Unknown Source)
    at com.certicom.tls.record.MessageInterpreter.decryptMessage(Unknown Source)
    at com.certicom.tls.record.ReadHandler.processRecord(Unknown Source)
    at com.certicom.tls.record.ReadHandler.readRecord(Unknown Source)
    at com.certicom.tls.record.ReadHandler.readUntilHandshakeComplete(Unknown Source)
    at com.certicom.tls.interfaceimpl.TLSConnectionImpl.completeHandshake(Unknown Source)
    at com.certicom.tls.record.WriteHandler.write(Unknown Source)
    at com.certicom.io.OutputSSLIOStreamWrapper.write(Unknown Source)
    at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:65)
    at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:123)
    at java.io.FilterOutputStream.flush(FilterOutputStream.java:123)
    at weblogic.net.http.HttpURLConnection.writeRequests(HttpURLConnection.java:154)
    at weblogic.net.http.HttpURLConnection.getInputStream(HttpURLConnection.java:358)
    at weblogic.net.http.SOAPHttpsURLConnection.getInputStream(SOAPHttpsURLConnection.java:37)
    at weblogic.net.http.HttpURLConnection.getResponseCode(HttpURLConnection.java:947)
    at (my own code)

SimpleSocketFactory的样子:

public static final SSLSocketFactory getSocketFactory()
{
    if ( sslSocketFactory == null ) {
        try {
            // get ssl context
            SSLContext sc = SSLContext.getInstance("SSL");

            // Create a trust manager that does not validate certificate chains
            TrustManager[] trustAllCerts = new TrustManager[]{
                new NaiveTrustManager() {
                    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                        log.debug("getAcceptedIssuers");
                        return new java.security.cert.X509Certificate[0];
                    }
                    public void checkClientTrusted(
                        java.security.cert.X509Certificate[] certs, String authType) {
                        log.debug("checkClientTrusted");
                    }
                    public void checkServerTrusted(
                        java.security.cert.X509Certificate[] certs, String authType) {
                        log.debug("checkServerTrusted");
                    }
                }
            };

            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            // EDIT: fixed the following line that was redeclaring SSLSocketFactory sslSocketFactory, returning null every time. Same result though.
            sslSocketFactory = sc.getSocketFactory();

            HttpsURLConnection.setDefaultSSLSocketFactory(sslSocketFactory);
            // EDIT: The following line has no effect
            //HttpsURLConnection.setDefaultHostnameVerifier(new NaiveHostNameVerifier());

        } catch (KeyManagementException e) {
            log.error ("No SSL algorithm support: " + e.getMessage(), e);
        } catch (NoSuchAlgorithmException e) {
            log.error ("Exception when setting up the Naive key management.", e);
        }
    }
    return sslSocketFactory;
}

NaiveHostnameVerifier有办法限制的有效主机,但它保留为空,所以基本上任何接受:

public class NaiveHostnameVerifier implements HostnameVerifier {
    String[] patterns;

    public NaiveHostnameVerifier () {
        this.patterns=null;
    }

    public NaiveHostnameVerifier (String[] patterns) {
        this.patterns = patterns;
    }

    public boolean verify(String urlHostName,SSLSession session) {
        if (patterns==null || patterns.length==0) {
            return true;
        } else {
            for (String pattern : patterns) {
                if (urlHostName.matches(pattern)) {
                    return true;
                }
            }
            return false;
        }
    }
}

用法是这样的:

    try {
        conn = (HttpURLConnection)url.openConnection();
        if (conn instanceof HttpsURLConnection) {
                ((HttpsURLConnection)conn).setSSLSocketFactory(SimpleSSLSocketFactory.getSocketFactory());
                // EDIT: added this line, the HV has to be set on connection, not on the factory.
                ((HttpsURLConnection)conn).setHostnameVerifier(new NaiveHostnameVerifier());
        }
        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-type","application/x-www-form-urlencoded");
        conn.connect();

        StringBuffer sbContent = new StringBuffer();
        // (snip)
        DataOutputStream stream = new DataOutputStream(conn.getOutputStream ());
        stream.writeBytes(sbContent.toString());
        stream.flush();
        stream.close();
    } catch (ClassCastException e) {
        log.error("The URL does not seem to point to a HTTP connection");
        return null;
    } catch (IOException e) {
        log.error("Error accessing the requested URL", e);
        return null;
    }

当我在搜索上的错误消息,大多数人只是导入证书,在他们的商店,但再次,我真的不能这样做,因为我不知道哪个证书做到这一点会。 我如果这行不通唯一的选择就是让一个工具,可以下载证书,并在一个更简单的方式,神秘的命令行,但我宁愿让我的Java代码只是忽略无效的证书添加。

任何的想法 ?

Answer 1:

其实也有没有错,上面的代码。 这个问题似乎在于使用Weblogic,这是Certicom TLS模块。 当我看着服务器选项,SSL高级我看到,我可以指定一个自定义的HostnameVerifier(SSLMBean.HostnameVerifier),但建议用证书验证已被弃用干扰能力的唯一元素。

我想上面的代码的Weblogic之外,它漂亮的工作(固定在后的HostnameVerifier虽然)。

然后我尝试添加“-DUseSunHttpHandler = true”添加到Weblogic的参数通过ipolevoy在提出这个问题的其他 。 它开始工作。

话虽这么说,切换的Oracle服务总线服务器上的HTTP处理程序似乎有点冒险。 有很可能是副作用是回来咬我在几个星期的时间...

我也试图定义自己的信任库,然后将其指向包含所需的键jssecacert。 也有人通过Weblogic的忽略,因为它有自己的的trustStore每个服务器的设置。 所以我诉诸要求管理员手动导入所需的键或点的Weblogic我自己的商店。



Answer 2:

其实,这是在Weblogic的版本10.3.5以下,对于其中有从Oracle提供一个补丁知道是不是BUG。 请参阅有关详细信息的My Oracle Support文档1474989.1。

上面的解决方法是由Oracle非推荐的(但支持)的解决方法,这将工作,但不是优选的解决方案。

优选的解决方案是下载Oracle文章中提到的补丁,并替换为新的,这也是Weblogic的10.3.5及以上的部分中的SSL主机名验证。 如果你想在支持方面与甲骨文保持兼容,这是要走的路。



文章来源: Ignoring SSL validation in Java