Android中Https通信实现_客户端单向认证校验防止中间人攻击

版权声明:本博客主要记录学习笔记和遇到的一些问题解决方案,转载请注明出处! https://blog.csdn.net/u010982507/article/details/85266096

引入HTTPS是为了解决HTTP所带来的三个问题:

  • HTTP是明文传输,数据容易被窃取,因此要加密数据以防止数据中途窃取
  • 认证服务器身份,确保数据发送到正确的服务器
  • 维护数据的完整性,防止数据在传输中被改变,如中间人攻击
    所以本章主要是讲述如何使用OkHttp或HttpUrlConnection来实现自制证书的访问。

设置证书校验

前面博客中写了如何绕过证书访问,那是不安全的访问方式,容易受到中间人攻击,所以客户端需要做双向证书校验,来保证客户端的合法性。

private static SSLSocketFactory setCertificates(InputStream... certificates) {
   try {
       CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
       KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
       keyStore.load(null);
       int index = 0;
       for (InputStream certificate : certificates) {
           String certificateAlias = Integer.toString(index++);
           keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));
           if (certificate != null) {
               certificate.close();
           }
       }
       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();
       return null;
   }
}

设置域名校验

域名校验需要自己设置一个trustHosts数组,当前访问域名匹配这个数组中的一条,即可返回true,否则返回false。

//获取HostnameVerifier
public static HostnameVerifier getHostnameVerifier(final JSONArray trustHosts) {
    HostnameVerifier hostnameVerifier = new HostnameVerifier() {
        @Override
        public boolean verify(String host, SSLSession sslSession) {
            if (trustHosts == null || trustHosts.length() == 0) {
                return false;
            }
            try {
                for (int i = 0; i < trustHosts.length(); i++) {
                    String trustHost = trustHosts.getString(i);
                    if (host.equalsIgnoreCase(trustHost)) {
                        return true;
                    }
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
            return false;
        }
    };
    return hostnameVerifier;
}

调用接口

//获取这个SSLSocketFactory
public static SSLSocketFactory getSSLSocketFactory(InputStream cerIn) {
    try {
        SSLSocketFactory factory = setCertificates(cerIn);
        return factory;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

OkHttp设置信任证书

JSONArray trustHosts= new JSONArray();
jsonArray.put("192.169.15.110");
jsonArray.put("192.169.15.111");
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.sslSocketFactory(SSLSocketCert.getSSLSocketFactory(context.getAssets().open("jetty.crt")));
builder.hostnameVerifier(SSLSocketCert.getHostnameVerifier(trustHosts));

HttpURLConnection设置信任证书

JSONArray trustHosts= new JSONArray();
jsonArray.put("192.169.15.110");
jsonArray.put("192.169.15.111");
URL url = new URL(fileUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
((HttpsURLConnection) conn).setSSLSocketFactory(SSLSocketCert.getSSLSocketFactory(context.getAssets().open("jetty.crt")));
((HttpsURLConnection) conn).setHostnameVerifier(SSLSocketCert.getHostnameVerifier(trustHosts));

使用证书字符串

上面是将证书放到Android工程的assets下,我们也可以将证书的内容导出来放到程序中

private String CER_STR = "-----BEGIN CERTIFICATE-----\n" +
          "MIICmjCCAgOgAwIBAgIIbyZr5/jKH6QwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ04xKTAn\n" +
          "BgNVBAoTIFNpbm9yYWlsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRTUkNBMB4X\n" +
          "DTA5MDUyNTA2NTYwMFoXDTI5MDUyMDA2NTYwMFowRzELMAkGA1UEBhMCQ04xKTAnBgNVBAoTIFNp\n" +
          "bm9yYWlsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRTUkNBMIGfMA0GCSqGSIb3\n" +
          "DQEBAQUAA4GNADCBiQKBgQDMpbNeb34p0GvLkZ6t72/OOba4mX2K/eZRWFfnuk8e5jKDH+9BgCb2\n" +
          "9bSotqPqTbxXWPxIOz8EjyUO3bfR5pQ8ovNTOlks2rS5BdMhoi4sUjCKi5ELiqtyww/XgY5iFqv6\n" +
          "D4Pw9QvOUcdRVSbPWo1DwMmH75It6pk/rARIFHEjWwIDAQABo4GOMIGLMB8GA1UdIwQYMBaAFHle\n" +
          "tne34lKDQ+3HUYhMY4UsAENYMAwGA1UdEwQFMAMBAf8wLgYDVR0fBCcwJTAjoCGgH4YdaHR0cDov\n" +
          "LzE5Mi4xNjguOS4xNDkvY3JsMS5jcmwwCwYDVR0PBAQDAgH+MB0GA1UdDgQWBBR5XrZ3t+JSg0Pt\n" +
          "x1GITGOFLABDWDANBgkqhkiG9w0BAQUFAAOBgQDGrAm2U/of1LbOnG2bnnQtgcVaBXiVJF8LKPaV\n" +
          "23XQ96HU8xfgSZMJS6U00WHAI7zp0q208RSUft9wDq9ee///VOhzR6Tebg9QfyPSohkBrhXQenvQ\n" +
          "og555S+C3eJAAVeNCTeMS3N/M5hzBRJAoffn3qoYdAO1Q8bTguOi+2849A==\n" +
          "-----END CERTIFICATE-----";

然后再调用

JSONArray trustHosts= new JSONArray();
jsonArray.put("192.169.15.110");
jsonArray.put("192.169.15.111");
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.sslSocketFactory(SSLSocketCert.getSSLSocketFactory(new Buffer().writeUtf8(CER_STR).inputStream()));
builder.hostnameVerifier(SSLSocketCert.getHostnameVerifier(trustHosts));

工具类上传地址
https://download.csdn.net/download/u010982507/10905059
学习参考
https://blog.csdn.net/lmj623565791/article/details/48129405

猜你喜欢

转载自blog.csdn.net/u010982507/article/details/85266096