android之HTTPS通讯 - Go语言中文社区

android之HTTPS通讯


一、HTTPS介绍

简单讲是HTTP的安全版。

背景: HTTP大势已去 HTTPS加密挑大梁 2017年苹果APP强制HTTPS:苹果公司从2017年1月1日起将全面强制要求iOS App使用HTTPS加密连接。只有HTTPS的网站才能通过iOS App安全审核。

SSL协议(Secure Socket layer)

SSL协议介绍

SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层对网络连接进行加密。

SSL协议位于TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持。SSL协议可分为两层: SSL记录协议(SSL Record Protocol):它建立在可靠的传输协议(如TCP)之上,为高层协议提供数据封装、压缩、加密等基本功能的支持。 SSL握手协议(SSL Handshake Protocol):它建立在SSL记录协议之上,用于在实际的数据传输开始前,通讯双方进行身份认证、协商加密算法、交换加密密钥等。


工作流程:

服务器认证阶段:1)客户端向服务器发送一个开始信息“Hello”以便开始一个新的会话连接;2)服务器根据客户的信息确定是否需要生成新的主密钥,如需要则服务器在响应客户的“Hello”信息时将包含生成主密钥所需的信息;3)客户根据收到的服务器响应信息,产生一个主密钥,并用服务器的公开密钥加密后传给服务器;4)服务器回复该主密钥,并返回给客户一个用主密钥认证的信息,以此让客户认证服务器。
用户认证阶段:在此之前,服务器已经通过了客户认证,这一阶段主要完成对客户的认证。经认证的服务器发送一个提问给客户,客户则返回(数字)签名后的提问和其公开密钥,从而向服务器提供认证。

                                                        非对称加密工作流程


HTTPS操作:

Android模拟器和Tomcat服务器之间的HTTPS数据交互:

生成一对非对称加密的密钥对(公钥和私钥)

私钥交给服务器,公钥交给客户端

1.生成服务器使用的https.jks

keytool -genkeypair -alias itheima -keyalg RSA -validity 3650 
-keypass 123456 -storepass 123456 -keystore https.jks

2.在tomcat服务器中配置Https

tomcat/config/server.xml修改connector配置

<Connector 
    port="8443" 
    protocol="org.apache.coyote.http11.Http11Protocol"
    maxThreads="150" 
    SSLEnabled="true" 
    scheme="https" 
    secure="true"
    clientAuth="false" 
    sslProtocol="TLS"
    keystoreFile="conf/itheima.jks"
    keystorePass="123456"/>

访问:https://127.0.0.1:8443/Shop2hService/home

附上官方配置文档

表示用浏览器Https访问服务器成功

3.从keystore中导出证书(公钥androidHttps.jks)

    1.浏览器导出证书方式

    2.命令行方式:

keytool -exportcert -alias itheima -file itheima.cer -keystore https.jks -storepass 123456

4.Android端https请求实现

/**
 * https请求封装
 *
 * @author christ
 */
public class HttpUtil {

    public static String get(String url) throws Exception {
        HttpURLConnection connection = (HttpURLConnection) 
                new URL(url).openConnection();
        connection.connect();
        if (connection.getResponseCode() == 200) {
            return stream2String(connection.getInputStream());
        } else {
            return "not 200";
        }
    }

    public static String get(String url, InputStream stream, String alias) throws Exception {
        if (url.startsWith("https://")) { // https新增代码
            HttpsURLConnection.setDefaultSSLSocketFactory(getSocketFactory(stream, alias));
            HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true; // 主机名校验通过
                }
            });
        }
        return get(url);
    }

    /**
     * 初始化https配置
     */
    public static SSLSocketFactory getSocketFactory(
            InputStream cerStream, String alias) throws Exception {

        // (1)创建Certificate证书
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        Certificate cert = cf.generateCertificate(cerStream);

        // (2)创建KeyStore,并指定证书
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(null);    // 清空默认证书
        ks.setCertificateEntry(alias, cert);

        // (3)创建TrustManager信任管理器
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
                TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(ks);
        TrustManager[] tm = trustManagerFactory.getTrustManagers();

        // (4)创建SSLContext对象,并指定信任管理器对象
        SSLContext sslContext = SSLContext.getInstance("TLS");

        // 指定本地的证书
        sslContext.init(null, tm, null);
        // 信任所有的证书
        // sslContext.init(null, new TrustManager[]{new MyTrustManager()}, null);

        // (5)设置SSLSocketFactory对象
        return sslContext.getSocketFactory();
    }

    /** 信任所有的证书 */
    private static class MyTrustManager implements X509TrustManager {
        @Override
        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType)
                throws java.security.cert.CertificateException {
        }

        @Override
        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType)
                throws java.security.cert.CertificateException {
        }

        @Override
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return new java.security.cert.X509Certificate[0];
        }
    }

    /**
     * 流转换成String
     */
    public static String stream2String(InputStream is) throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int length = -1;
        while ((length = is.read(buffer)) != -1) {
            baos.write(buffer, 0, length);
        }
        String result = baos.toString("utf-8");
        is.close();
        baos.close();
        return result;
    }
}

2.HTTPUrlConnection的用法

private String url = "https://10.0.0.2:8443/Shop2hService/home";
private int keystoreId = R.raw.androidHttps;  // 数字证书

private void getData01() {
    new Thread() {
        public void run() {
            try {
                InputStream stream = getResources().openRawResource(keystoreId);
                final String result = HttpUtil.get(url, stream, "");
                showContent("HttpURLConnect: n" + result);
            } catch (final Exception e) {
               ...
            }
        }
    }.start();
}

3.OKHttp用法

private void getData02() {
    try {
        InputStream isCert = getResources().openRawResource(keystoreId);
        OkHttpClient okHttpClient = new OkHttpClient.Builder().build();

        if (url.startsWith("https://")) {
            okHttpClient = new OkHttpClient.Builder()
                    .sslSocketFactory(HttpUtil.getSocketFactory(isCert, "alias"))
                    .hostnameVerifier(new HostnameVerifier() {
                        @Override
                        public boolean verify(String hostname, SSLSession session) {
                            System.out.println("------hostname: " + hostname);
                            return true;
                        }
                    }).build();
        }

        Request request = new Request.Builder().url(url).build();
        Call call = okHttpClient.newCall(request);
        ...

    } catch (Exception e) {
        e.printStackTrace();
    }
}

4.Retrofit的用法

 /**
     * Retrofit初始化
     */
    public void initRetrofit() {


//        OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
//
//        //创建拦截器对象
//        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
//
//        //设置拦截器对象的级别
//        loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
//
//        //设置okhttpClient的日子拦截器,作用,打印请求和响应数据,设置拦截时间
//        builder.addInterceptor(loggingInterceptor).connectTimeout(20, TimeUnit.SECONDS);




        try {
            InputStream isCert = Global.mContext.getResources().openRawResource(androidHttps);
            OkHttpClient mClient = new OkHttpClient.Builder().build();


            if (IRetrofitAPI.HOST_URL.startsWith("https://")) {
                mClient = new OkHttpClient.Builder()
                        .addInterceptor(new Interceptor() {
                            @Override
                            public okhttp3.Response intercept(Chain chain) throws IOException {
                                Request request = chain.request();
                                Request.Builder builder1 = request.newBuilder();
                                Request build = builder1.addHeader("userid", SharedPreUtil.getString("userid", "")).build();
                                return chain.proceed(build);
                            }
                        }).retryOnConnectionFailure(true)
                        .sslSocketFactory(HttpUtil.getSocketFactory(isCert, "http"))
//                        .addInterceptor(loggingInterceptor).connectTimeout(20, TimeUnit.SECONDS)
                        .hostnameVerifier(new HostnameVerifier() {
                            @Override
                            public boolean verify(String hostname, SSLSession session) {
                                return true;
                            }
                        }).build();
            }
            mRetrofit = new Retrofit
                    .Builder()
                    .baseUrl(IRetrofitAPI.HOST_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .client(mClient)
//                    .client(builder.build())
                    .build();
            mIRetrofitAPI = mRetrofit.create(IRetrofitAPI.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

最后模拟器也能把数据打印出来。

扩展

数字证书原理,公钥私钥加密原理

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_40855550/article/details/80975127
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2021-05-16 12:26:33
  • 阅读 ( 953 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢