Using RestTemplate to access https to implement SSL request operation

  • 2021-12-05 06:11:22
  • OfStack

Directory 1, add HttpsClientRequestFactory tool class 2, modify RestTemplate3, access https, throw exception scheme 1: replace jce package scheme 2: upgrade JDK to version 1.8 (recommended method)

Method 1: java is used to generate certificates, which is not recommended and has poor portability.

Method 2: Change RestTemplate to https request.

1. Add an HttpsClientRequestFactory tool class


import org.springframework.http.client.SimpleClientHttpRequestFactory;
import javax.net.ssl.*;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.Socket;
import java.security.cert.X509Certificate;
 
/**
 * TLS Adj. 3 Functions: 
 * 	 ( 1 ) Authentication 
 * 		 Verify the identity of the other party through certificate authentication to prevent man-in-the-middle attack 
 * 	 ( 2 ) Data privacy 
 * 		 Encrypt the transmitted data with a symmetric key, because the key is only used by the client / The server has it, so no one else can spy on it. 
 * 	 ( 3 ) Data integrity 
 * 		 The digest algorithm is used to calculate the message, and the value is checked after receiving the message to prevent the data from being tampered or lost. 
 *     
 *      Use RestTemplate Go on HTTPS Request access: 
 * 	private static RestTemplate restTemplate = new RestTemplate(new HttpsClientRequestFactory());
 * 
 */
public class HttpsClientRequestFactory extends SimpleClientHttpRequestFactory {
    @Override
    protected void prepareConnection(HttpURLConnection connection, String httpMethod) {
        try {
            if (!(connection instanceof HttpsURLConnection)) {
                throw new RuntimeException("An instance of HttpsURLConnection is expected");
            }
 
            HttpsURLConnection httpsConnection = (HttpsURLConnection) connection; 
            TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return null;
                        }
                        @Override
                        public void checkClientTrusted(X509Certificate[] certs, String authType) {
                        }
                        @Override
                        public void checkServerTrusted(X509Certificate[] certs, String authType) {
                        } 
                    }
            };
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            httpsConnection.setSSLSocketFactory(new MyCustomSSLSocketFactory(sslContext.getSocketFactory()));
 
            httpsConnection.setHostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String s, SSLSession sslSession) {
                    return true;
                }
            });
 
            super.prepareConnection(httpsConnection, httpMethod);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private static class MyCustomSSLSocketFactory extends SSLSocketFactory { 
        private final SSLSocketFactory delegate; 
        public MyCustomSSLSocketFactory(SSLSocketFactory delegate) {
            this.delegate = delegate;
        }
 
        //  Returns the password suite enabled by default. Unless 1 List enabled, for the SSL Connected handshakes use these cipher packages. 
        //  The minimum quality of these default services requires confidentiality protection and server authentication 
        @Override
        public String[] getDefaultCipherSuites() {
            return delegate.getDefaultCipherSuites();
        }
 
        //  The returned cipher suite can be used for SSL Connection enabled name 
        @Override
        public String[] getSupportedCipherSuites() {
            return delegate.getSupportedCipherSuites();
        } 
 
        @Override
        public Socket createSocket(final Socket socket, final String host, final int port,
                                   final boolean autoClose) throws IOException {
            final Socket underlyingSocket = delegate.createSocket(socket, host, port, autoClose);
            return overrideProtocol(underlyingSocket);
        } 
 
        @Override
        public Socket createSocket(final String host, final int port) throws IOException {
            final Socket underlyingSocket = delegate.createSocket(host, port);
            return overrideProtocol(underlyingSocket);
        }
 
        @Override
        public Socket createSocket(final String host, final int port, final InetAddress localAddress,
                                   final int localPort) throws
                IOException {
            final Socket underlyingSocket = delegate.createSocket(host, port, localAddress, localPort);
            return overrideProtocol(underlyingSocket);
        }
 
        @Override
        public Socket createSocket(final InetAddress host, final int port) throws IOException {
            final Socket underlyingSocket = delegate.createSocket(host, port);
            return overrideProtocol(underlyingSocket);
        }
 
        @Override
        public Socket createSocket(final InetAddress host, final int port, final InetAddress localAddress,
                                   final int localPort) throws
                IOException {
            final Socket underlyingSocket = delegate.createSocket(host, port, localAddress, localPort);
            return overrideProtocol(underlyingSocket);
        }
 
        private Socket overrideProtocol(final Socket socket) {
            if (!(socket instanceof SSLSocket)) {
                throw new RuntimeException("An instance of SSLSocket is expected");
            }
            //((SSLSocket) socket).setEnabledProtocols(new String[]{"TLSv1.2"});
            ((SSLSocket) socket).setEnabledProtocols(new String[]{"TLSv1", "TLSv1.1", "TLSv1.2"});
            return socket;
        }
    }
}

Note: The server TLS version should be the same as the 1 defined in the client tool class. (TLSv1.2)

2. Modify RestTemplate

When in use, the


private static RestTemplate restTemplate = new RestTemplate();

Replace with the following:


private static RestTemplate restTemplate = new RestTemplate(new HttpsClientRequestFactory());

Other code remains unchanged.

You can also use injection:


@Configuration
public class ConfigBean {
 @Bean
 public RestTemplate getRestTemplate() {
  return new RestTemplate(new HttpsClientRequestFactory());
 }
}

3. Exception thrown when accessing https

javax. net. ssl. SSLHandshakeException: Received fatal alert: handshake_failure Solution

Because the security mechanism of jce in jdk leads to an error, it is necessary to download the corresponding jce package from oracle official website to replace the jce package in jdk.

Scenario 1: Replace the jce package


 Directory  %JAVA_HOME%\jre\lib\security In local_policy.jar,US_export_policy.jar
JDK7 http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html
JDK8 http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
 
// pub1:/home/myron/jdk1.7.0_80 % cd $JAVA_HOME/jre/lib/security/  //jce Where jdk Path of 
US_export_policy.jar
local_policy.jar

Scenario 2: Upgrade JDK to version 1.8 (recommended)


// pub1:/home/myron % vi .cshrc
setenv JAVA_HOME /home/myron/jdk1.8.0_211
// pub1:/home/myron % source .cshrc
// pub1:/home/myron % java -version
java version "1.8.0_211"

Related articles: