Android OkHttp中添加https支持

基础知识

感觉就是一堆有信誉的机构,说: 我们这些机构的公钥是可信的,我们下面的小弟当然也是可以信任的啦

然后大家就去当人家小弟,就是可信的了….

当然这里面有的大佬不高兴,就自己搞一套证书,比如12306

Https中,值得注意的密钥有:

  • 服务器端的公钥私钥
  • 客户端的随机密钥

值得注意的是一个HTTPS请求实际上就是两次HTTP传输.

1.客户端向服务器发起HTTPS请求,连接到服务器的443端口。

2.服务端收到请求,向客户端发送自己的公钥

3.客户端收到服务器公钥,开始验证证书的合法性,我们知道系统内置了一些证书,应该是叫顶级证书吧

我们的证书并不是啥大机构发的,肯定不在里面,那么就没法验证合法.

合法 > 继续

不合法 > 此次Https请求终止

4.客户端验证公钥合格后(也就是给你发消息的服务器是正经服务器),那么客户端会生成一个 随机密码,客户端会拿着这个随机密码和刚才收到的服务器密钥做非对称加密 >> 得到密文的密码

——–以上第一次http请求结束了——–

5.客户端会发起HTTPS中的第二个HTTP请求,发送客户端密钥(密文)给服务器。

6.服务器收到密文,会用自己的私钥对其进行非对称解密,得到客户端刚才生成的客户端随机密码.

此时服务器使用客户端随机密码,对数据进行对称加密

7.把对称加密后的数据返回给客户端,客户端对称解密,OK 此次Https完美结束

——–整个https请求结束了——–

其中 , 对称加密非对称加密, 各司其职,共同完成整个请求.

对称加密: 最快速,最简单

非对称加密:速度慢,很安全,不需要把秘钥分发,客户端利用公钥加密的数据,只能是拥有秘钥的服务器解密

利用非对称加密的特性传递 客户端生成的随机密钥 ,达到只有服务器和客户端互相知道的密钥,从而使用密钥进行(高速简单的)对称加密数据.

第一部分:信任所有

这就是,我不管是谁传递的消息,不是你家服务器传递的消息,你也会信

Api.java (提供okhttp实例,并创建Retroit服务)

OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .hostnameVerifier(new HostnameVerifier() {
                    @Override
                    public boolean verify(String hostname, SSLSession session) {
                        return true;
                    }
                })
                .sslSocketFactory(createSSLSocketFactory())
                .build();
               
... ...

//这里是创建一个SSLSocketFactory,提供给上面的 .sslSocketFactory()
private SSLSocketFactory createSSLSocketFactory() {
    SSLSocketFactory ssfFactory = null;
    try {
        SSLContext sc = SSLContext.getInstance("TLS");
        sc.init(null, new TrustManager[]{new TrustAllCerts()}, new SecureRandom());
        ssfFactory = sc.getSocketFactory();
    } catch (Exception e) {
    }

    return ssfFactory;
}

其中涉及到TrustAllCerts.java,可以看到只是实现X509TrustManager,所有方法都是默认实现

/**
 * If you have any questions, you can contact by email { wangzhumoo@gmail.com}
 * @author 王诛魔 2018/1/8 下午2:25
 */
public class TrustAllCerts implements X509TrustManager {
    @Override
    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}

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

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

这里就以及可以了,信任所有的连接

第二部分:(强验证)

我只信任证书合法的服务器传递的数据.

  • 查看Https的证书
    在这里插入图片描述

在浏览器上看到这个,这个已经是我把证书添加为信任了,所以他是一个 安全 的标志

  • 分析
    在这里插入图片描述

这里是我查看当前网站证书的结构

最顶—是根证书,到期时间是2028年

最底—是我司证书,到期时间是2018.12.9日

这里我们可以发现,我们网站的证书是有时间限制的,那么就会有一个问题,到了2018.12.9这一天怎么办.

我也不知道会怎么样,应该是续签吧!那么万一这个证书变化了怎么办?

所以,我们应该把根证书置为信任.

  • 下载保存
    在这里插入图片描述

Mac的在 钥匙串访问 中

Windows 没法放图,在chrome上查看证书的时候应该就能保存.

HttpsUtils.java

/**
 * If you have any questions, you can contact by email { wangzhumoo@gmail.com}
 * @author 王诛魔 2018/1/10 下午5:07
 * 支持https的工具类
 */

public class HttpsUtils {
    private static final String TAG = "OkHttp";

    /**
     * 创建一个空白的KeyStore
     * @return KeyStore
     * @throws GeneralSecurityException
     */
    private static KeyStore createEmptyKeyStore() throws GeneralSecurityException {
        try {
            KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
            //此处密码随意,不会产生问题
            keystore.load(null, "password".toCharArray());
            return keystore;
        } catch (IOException e) {
            return null;
        }
    }

    /**
     * TrustManager 生成
     * @return
     * @throws GeneralSecurityException
     */
    private static TrustManager[] generateTrustManager() throws GeneralSecurityException {

        //创建一个X.509格式的CertificateFactory
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");

        Certificate ca;
        //证书工厂根据证书文件的流生成证书Certificate
        InputStream assets = App.getContext().getResources().openRawResource(R.raw.rootca);
        ca = certificateFactory.generateCertificate(assets);
        Log.e(TAG, "trustManager: ca = " + ((X509Certificate) ca).getSubjectDN() );

        //创建KeyStore,用来存储信任证书
        KeyStore keyStor = createEmptyKeyStore();
        keyStor.setCertificateEntry("ca",ca);

        //创建一个默认类型的TrustManagerFactory
        String defaultAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(defaultAlgorithm);

        //用keyStore实例初始化TrustManagerFactory,此时TrustManagerFactory会信任我们保存的证书
        tmf.init(keyStor);

        //通过tmf获取TrustManager数组,TrustManager也会信任keyStor中的证书
        return tmf.getTrustManagers();
    }

    /**
     * 提供一个一个SSLSocketFactory
     * @return SSLSocketFactory实例
     */
    public static SSLSocketFactory generateSSLSocketFactory()  {
        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, generateTrustManager(), new SecureRandom());
            Log.e(TAG, "generateSSLSocketFactory ");
            return sc.getSocketFactory();
        } catch (GeneralSecurityException e) {
            return null;
        }
    }
}

注释很清楚了.

关键:

1.拿到帧数的流

InputStream assets = App.getContext().getResources().openRawResource(R.raw.rootca);

2.保存到keystore

KeyStore keyStor = createEmptyKeyStore();
keyStor.setCertificateEntry("ca",ca);

3.初始化并拿到TrustManager[]

tmf.init(keyStor);
tmf.getTrustManagers()

使用即可:

//这样就Ok
OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .hostnameVerifier((hostname, session) -> true)
                .sslSocketFactory(HttpsUtils.generateSSLSocketFactory())
                .build();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值