HTTPS principle

Let’s take a look at the definition, from wikipedia:

HTTPS (also called HTTP over Transport Layer Security (TLS), HTTP over SSL, and HTTP Secure) is a communications protocol for secure communication over a computer network which is widely used on the Internet. HTTPS consists of communication over Hypertext Transfer Protocol (HTTP) within a connection encrypted by Transport Layer Security, or its predecessor, Secure Sockets Layer. The main motivation for HTTPS is authentication of the visited website and protection of the privacy and integrity of the exchanged data.

According to this definition, HTTPS includes THE HTTP protocol and SSL/TLS protocol. It is simply understood that HTTP encryption is transmitted based on SSL/TLS. HTTP is an application-layer protocol that defines the rules that request and responder communication follows, which can be covered in detail in the great HTTP Guru’s Guide. In fact, I would like to discuss some details of the SSL/TLS protocol, after all, this is the biggest difference between HTTPS and HTTP, first let’s take a look at a complete SSL/TLS handshake process.

Very complex interaction process, but understanding down is to use asymmetric encryption means to transfer the key, and then use the key for symmetric encryption to transfer data. During the handshake, the most important thing is certificate verification, and the rest is normal data interaction. There is a lot of literature on how to verify that a certificate is valid, and it can make your network insecure. The verification of a certificate includes the following aspects:

  • First, verify that the certificate is issued by a “trusted root certification Authority” on the client.
  • Second, check whether the certificate is in the revocation list of the superior certificate;
  • Third, verify whether the certificate is expired;
  • Fourth, verify that the certificate domain name is consistent.

One day our QA sister came up to me angrily and asked me why Charles could catch HTTPS packages in other apps and why ours couldn’t. I told her with a smile in my heart that it only showed that we were better than others. I will share the details of how we did this later. First, I will discuss how Charles implemented HTTPS packet capture, which involves a man-in-the-middle attack.

A man-in-the-middle attack on SSL goes like this:

In fact, the middleman is a stealthily changing of the post, the core is how to deceive the client, so that the client can be assured of data interaction with the middleman without any awareness. Charles: How do you do HTTPS packet capture? There are many tutorials on how to do HTTPS packet capture.

Install a digital certificate issued by a private CA into the mobile phone and save it as a trusted certificate

Since the issuance of a certificate to implement the above two, three, four check rule is very simple, want to install the certificate in mobile client trust must seek permission from the user list, bad around here, but given that most users of network security consciousness is poorer, sometimes in a fog of trust, that we as APP developers, can avoid the happening of this kind of situation?

In fact, it is very simple. We build the certificate of the server into our APP. When we do the verification of the certificate of the server, we only check whether it is exactly the same with the certificate. However, there is also a problem that the certificate of the server may expire or be upgraded. In order to improve the security of the network, the validity period of the certificate will not be set too long. In this way, APP will be frequently issued because of the certificate, which is also very painful. (some time ago because our IOS APP is authorized enterprise user’s certificate is not updated in time, cause you can’t open the APP, normal blood lesson cause we don’t want to retrace the road) can you think again, we can configure the certificate on the back end, any changes directly to download is finished, that we don’t have no risk of interception certificate download? Once intercepted, all of our certificate verification will be invalid, which is worse than trusting the phone’s built-in certificate. We don’t want to trust only our server’s certificate, nor do we want to trust all the CA certificates on the phone. Has a good way of trust is the root of our server certificate issued certificate of export packaging to the APP, this won’t be one hundred percent certificate, no loophole, but compared to the trust of hundreds of certificate, we only trust a little a lot of risk, which is our QA sister by Charles grasp not our package. ~ ~ ~

OKHTTP

As an Android developer, let’s take a look at the widely used web library OKHTTP’s support for HTTPS. Here’s a quote from OKHTTP’s introduction to HTTPS:

OkHttp attempts to balance two competing concerns:

  • Connectivity to as many hosts as possible. That includes advanced hosts that run the latest versions of boringssl and less out of date hosts running older versions of OpenSSL.
  • Security of the connection. This includes verification of the remote webserver with certificates and the privacy of data exchanged with strong ciphers.

Several HTTPS related apis:

SSLSocketFactory:

The Secure socket layer factory used to create SSLSocket. The default SSLSocket is a list of certificates that trust the phone’s built-in trust. We can use the okHttpClient. Builder sslSocketFactory method to define our own trust policy, such as implementing the above mentioned we only trust the root certificate of the server certificate.

Public static SSLSocketFactory getSSLSocketFactory(InputStream... Certificates) {try {/ / use our certificate to create a keystore CertificateFactory CertificateFactory = CertificateFactory. GetInstance ("X.509");
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null);
            int index = 0;
            for (InputStream certificate : certificates) {
                String certificateAlias = "server"+Integer.toString(index++);
                keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));
                try {
                    if(certificate ! = null) { certificate.close(); } } catch (IOException e) { e.printStackTrace(); } // Create a trustManager that trusts only the keystore we created. SSLContext SSLContext = sslContext.getInstance ("TLS");
            TrustManagerFactory trustManagerFactory =
                    TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);
            sslContext.init(
                    null,
                    trustManagerFactory.getTrustManagers(),
                    new SecureRandom()
            );
            return sslContext.getSocketFactory();
        } catch (Exception e) {
            e.printStackTrace();
            returnnull; }}Copy the code

X509TrustManager:

public interface X509TrustManager extends TrustManager {
    void checkClientTrusted(X509Certificate[] var1, String var2) throws CertificateException;

    void checkServerTrusted(X509Certificate[] var1, String var2) throws CertificateException;

    X509Certificate[] getAcceptedIssuers();
}
Copy the code

CheckServerTrusted implements server-side validation. The system’s default implementation is generally used. Some tutorials describe how to configure SSL in this way

private static synchronized SSLSocketFactory getDefaultSSLSocketFactory() {
    try {
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, new TrustManager[]{
                new X509TrustManager() {
                    public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

                    }

                    public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
                    }

                    public X509Certificate[] getAcceptedIssuers() {
                        return new X509Certificate[0];
                    }
                }
        }, null);
        returnsslContext.getSocketFactory(); } catch (GeneralSecurityException e) { throw new AssertionError(); }}Copy the code

Do not do this, you will not do any verification, the recommended system default, it will find exceptions during the verification process directly throw.

HostnameVerifier:

public interface HostnameVerifier {
    boolean verify(String var1, SSLSession var2);
}
Copy the code

OKHTTP implements OkHostnameVerifier, which performs various re matches for IP and Host names in the certificate. This strategy is used by default. Sometimes you run into some weird validation problems, and most tutorials teach you something like this:

OKHttpClient.Builder.hostnameVerifier(new HostnameVerifier() {
                    @Override
                    public boolean verify(String hostname, SSLSession session) {
                        return true; }})Copy the code

In fact, you completely abandon the hostname verification, which is quite insecure.