1 overview

OkHttp configures HTTPS access, which consists of the following three core parts:

  • sslSocketFactory()
  • HostnameVerifier
  • X509TrustManager

The first is an SSL socket factory, the second is used to validate the host name, and the third is a certificate trust manager class. To implement HTTPS access through OkHttp, you need to implement the above three parts yourself. There is also a brief mention of server-side deployment, using Tomcat9, and finally possible solutions to some common problems.

2 OkHttp introduction

OkHttp is an open source lightweight framework for handling web requests. It is provided by Square as an alternative to HttpUrlConnection and Apache HttpClient. It is currently available on Github at 36.4K star. Advantages are

  • HTTP/2 supports shared sockets for all requests that connect to the same host
  • Connection pooling reduces request latency
  • Caching response data reduces repeated network requests
  • Automatically handles GZIP compression

OkHttp is an excellent HTTP framework that supports GET/POST requests and file upload/download.

3 Preparations

  • A server
  • A domain name
  • A certificate

What? All have no? To buy! Of course, there is no need to buy the certificate, you can use openSSL and other tools to generate, but the self-signed certificate later verification will be a bit troublesome, I suggest you buy.

Part four OkHttp

4.1 Violence Program

public static String test(a) {
	OkHttpClient client = new OkHttpClient.Builder()
        .sslSocketFactory(createSSLSocketFactory(), new TrustAllCerts())
        .hostnameVerifier(new TrustAllHostnameVerifier()).build();

	String url = "https://xxxxxxx";   // Change it to its own URL
    Request request = new Request.Builder().url(url).build();
    Call call = build.newCall(request);
    Response response = call.execute();
    if(response.body() ! =null)
    {
        String result = response.body().string();
        / / processing result}}private static class TrustAllCerts implements X509TrustManager {
    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
    public X509Certificate[] getAcceptedIssuers() {return new X509Certificate[0];}
}

private static class TrustAllHostnameVerifier implements HostnameVerifier {
    public boolean verify(String hostname, SSLSession session) { return true; }}private static SSLSocketFactory createSSLSocketFactory(a) {
    SSLSocketFactory ssfFactory = null;
    try {
        SSLContext sc = SSLContext.getInstance("TLS");
        sc.init(null.new TrustManager[]{new TrustAllCerts()}, new SecureRandom());
        ssfFactory = sc.getSocketFactory();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return ssfFactory;
}
Copy the code

This is a violent scheme, as shown by the class name, to trust all certificates and hosts:

public boolean verify(String hostname, SSLSession session) { return true; }
Copy the code

This method returns true, which is to trust all hosts.

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

Here the two check functions do nothing and accept arbitrary client and server certificates. Writing this is equivalent to using a useless TrustManager, which is better not encrypted and not recommended.

4.2 Recommended Solutions

Start with modification from two aspects: one is X509TrustManager and the other is HostnameVerifier.

2 HostnameVerifier

First say a simple, here is mainly to verify the host name, simple words, can be implemented as follows:

HostnameVerifier hnv = new HostnameVerifier() {
	@Override
	public boolean verify(String hostname, SSLSession session) {
	    if("www.test.com".equals(hostname)){  
			return true;  
	    } 
	    else {  
			HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
			returnhv.verify(hostname, session); }}};Copy the code

Here to verify the host name is www.test.com return true, the implementation is relatively simple, complex business can be combined with the configuration center, black/white list and other dynamic verification.

4.2.2 X509TrustManager

There are actually two ways to add the trust certificate, one is to stream it:

private static X509TrustManager trustManagerForCertificates(InputStream in)
        throws GeneralSecurityException
{
    CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
    Collection<? extends Certificate> certificates = certificateFactory.generateCertificates(in);
    if (certificates.isEmpty()) {
        throw new IllegalArgumentException("expected non-empty set of trusted certificates");
    }

    char[] password = "password".toCharArray(); // Any password can be used here
    KeyStore keyStore = newEmptyKeyStore(password);
    int index = 0;
    for (Certificate certificate : certificates) {
        String certificateAlias = Integer.toString(index++);
        keyStore.setCertificateEntry(certificateAlias, certificate);
    }

    // Use it to build an X509 trust manager.
    KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(
            KeyManagerFactory.getDefaultAlgorithm());
    keyManagerFactory.init(keyStore, password);
    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
            TrustManagerFactory.getDefaultAlgorithm());
    trustManagerFactory.init(keyStore);
    TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
    if(trustManagers.length ! =1| |! (trustManagers[0] instanceof X509TrustManager))
    {
        throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers));
    }
    return (X509TrustManager) trustManagers[0];
}
Copy the code

See the complete code at the end. The utility class method is static and can be called directly:

OKHTTP.send("https://xxxxx");
Copy the code

Another way is to directly customize a TrustManager and override the three methods in it:

SSLContext context = SSLContext.getInstance("TLS");
context.init(null.new TrustManager[]{
    new X509TrustManager() {
        @Override
        public void checkClientTrusted(X509Certificate[] chain,String authType) throws CertificateException {}
        
        @Override
        public void checkServerTrusted(X509Certificate[] chain,String authType) throws CertificateException {
            for (X509Certificate cert : chain) {
                // Make sure that it hasn't expired.
                cert.checkValidity();
                // Verify the certificate's public key chain.
                try {
                    cert.verify(((X509Certificate) ca).getPublicKey());
                } catch (NoSuchAlgorithmException e) {
                    e.printStackTrace();
                } catch (InvalidKeyException e) {
                    e.printStackTrace();
                } catch (NoSuchProviderException e) {
                    e.printStackTrace();
                } catch(SignatureException e) { e.printStackTrace(); }}}@Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0]; }}},null);
Copy the code

So the first method is theta

@Override
public void checkClientTrusted(X509Certificate[] chain,String authType) throws CertificateException {}
Copy the code

This method checks the certificate of the client. The client does not need to be authenticated by default. The second method is

@Override
public void checkServerTrusted(X509Certificate[] chain,String authType)
Copy the code

This method checks the certificate of the server and throws an exception if it does not trust the certificate. By implementing this method, you can trust any certificate specified by yourself. If you do not do any processing, no exception will be thrown. This checks whether the certificate is expired and whether the signature of the certificate matches. The third method is

@Override
public X509Certificate[] getAcceptedIssuers() {
    return new X509Certificate[0];
}
Copy the code

Returns an array of trusted X509 certificates.

This method has not tried, only for reference.

5 Server Deployment

The server uses Tomcat, and a brief introduction to deployment.

5.1 Uploading Project

Back-end processing with the Spring Boot project, do not demonstrate, use IDEA into a WAR package and then upload to webapps.

5.2 the Tomcat configuration

Conf /server. XML file and find the default Host named localhost:

https://www.test.com:port
Copy the code

test

6 Verification and source code

This is difficult to verify because there is no complete Demo. Specifically, the OkHttp core used in the front end is introduced, and the Tomcat server used in the back end is also introduced. It should be easy to do a Demo with Spring Boot.

Github is the source of the OKHTTP utility class

7 FaQs

7.1 Tomcat HTTPS Is Inaccessible

  • Certificate file error, but this is less likely.
  • Configuration error, please check the configuration file is correct, you can ps – ef | grep tomcat see if tomcat can open and view the logs/catalina. Log out.
  • Tomcat HTTPS port 8443 is the default Tomcat HTTPS port 8443 is the default Tomcat HTTPS port 8443 is the default Tomcat HTTPS port 8443
  • Security group or firewall problems. For cloud servers, you need to enable corresponding ports in the security group configuration and check whether an IP address is blacklisted and cannot be accessed. The firewall mainly refers to iptables. If the firewall is not enabled, you do not need to ignore it. If the firewall is enabled, you need to enable the corresponding port.

7.2 OkHttp HTTPS cannot be accessed

  • Unable to read the certificate file: You need to read the certificate file in the corresponding path of the project. For example, you need to use getAssets().open(“xxx.xxx”) to obtain the certificate file. For Maven project, you need to use FileInputStream to obtain the certificate file from Resources.
  • singed fields invalid:

    The certificate file format is incorrect. CRT /. Pem is used.

  • Signature does not match: This may be an exception when using the openSSL self-generated certificate. The possible solution is to convert the certificate format and re-generate the certificate if the certificate fails.

8 Reference Links

1. Secure HTTPS communication between Apple core and Android App

2.Android OkHttp implements HTTPS access and supports HTTPS access of Android 4.X system

3.Android uses OkHttp to request self-signed HTTPS sites

If you think the article looks good, please like it. At the same time, welcome to pay attention to wechat public number: Lingzhi Road.