Ignore SSL authentication in Java

I must use an invalid SSL certificate to call the HTTP service hosted on the web server In dev, I use keytool to import the certificate, but each client installation certificate is different, so I can't bundle it

I know skipping SSL authentication is really ugly In this specific case, I don't even need SSL. All other communications in the system are through simple HTTP So I really don't care about mitm attacks and so on An attacker does not need to destroy SSL because the data does not have SSL This is support for legacy systems beyond my control

I'm using httpurlconnection. Net for sslsocketfactory with naivetrustmanager and naivehostnameverifier This applies to some self - signed servers I try, but not on the customer's website My mistake is:

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)

My simplesocketfactory looks like:

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 has a method to limit valid hosts, but it is empty, so it basically accepts anything:

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;
        }
    }
}

The usage is as follows:

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;
    }

When I was searching for error messages, most people just import certificates in their store, but again, I can't do this because I don't know which certificate is My only option if this doesn't work is to make a tool that can download certificates and add an easier way to hide the command line, but I'd rather let my java code just ignore invalid certificates

Any ideas?

Solution

The above code actually has no errors The problem seems to be Weblogic and certicom TLS modules When I look at the server options, SSL and advanced I see that I can specify a custom hostnameverifier (sslmbean. Hostnameverifier), but it is suggested that the only element capable of interfering with certificate verification has been deprecated

I tried the above code outside Weblogic, and it worked well (fixed the hostnameverifier in postname)

Then, in this other question, I try to propose "- dusesunhttphandler = true" proposed by ipolevoy to Weblogic parameter It began to work

Having said that, switching HTTP handlers on the Oracle service bus server seems a bit risky In a few weeks, there may be side effects that make me bite me again

I also tried to define my own truststore and point it to jssecacert. Net that contains the required key Weblogic is also ignored because it has its own truststore settings for each server So I asked the administrator to manually import the required keys or point Weblogic to my own store

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>