当前位置:   article > 正文

Android Okhttp3添加https自签名证书以及Glide4.X添加https自签名证书_glide 自签证书

glide 自签证书

一、网络协议

  1. HTTP协议

    Http协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web)服务器传输超文本到本地浏览器的传送协议。

  2. HTTPS协议

    Https协议是Hypertext Transfer Protocol Secure(安全超文本传输协议)的缩写,是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议。

    http和https的区别:

httphttps
HTTPHTTP
TCPSSL / TLS
IPTCP
IP
  1. SSL/TLS协议:

    SSL及其继任者TLS是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层与应用层之间对网络连接进行加密。

    SSL (Secure Sockets Layer 安全套接字协议) 是一种在客户端跟服务器端建立一个加密连接的安全标准. 一般用来加密网络服务器跟浏览器, 或者是邮件服务器跟邮件客户端(如: Outlook)之间传输的数据。

    TLS(Transport Layer Security 传输层安全)是更为安全的升级版的SSL。

    SSL /TLS能保障敏感信息(如:银行卡号, 社保卡号, 登陆凭证等)的传输安全. 一般情况下, 数据在浏览器跟服务器之间的传输使用的是明文格式, 这种方式存在资料被窃取的风险. 如果黑客能拦截浏览器跟服务器之间的通讯数据, 就能看到通讯的内容. 如果某个网站受 SSL 证书保护,其相应的 URL 中会显示 HTTPS,单击浏览器地址栏的挂锁图标,即可查看证书详细信息,包括颁发机构和网站所有者的公司名称。

二、自签名证书

什么是自签名证书(self-signed certicates)?

自签名证书就是没有通过受信任的证书颁发机构, 自己给自己颁发的证书.

SSL 证书大致分三类:

  • 由安卓认可的证书颁发机构CA(Certificate Authority)(如: VeriSign、DigiCert), 或这些机构的下属机构颁发的证书.

  • 没有得到安卓认可的证书颁发机构颁发的证书.

  • 自己颁发的证书, 分临时性的(在开发阶段使用)或在发布的产品中永久性使用的两种.

而只有Android系统认可的机构办法的证书,在使用过程中才不会出现安全提示。

为什么会有人使用自签名的证书呢?

(重要的事重复三遍)免费,免费,免费,不用花费一分钱,在开发阶段写的代码, 测试跟发布的时候也可以用。

三、OkHttp3添加自签名证书

  1. 如何使用自签名证书?

1.获取证书流有两种方式:

  • 将服务端提供的证书文件放到assets文件夹里面,然后获取。(因为是在assets文件下,所以会写入到apk里面)
  • 打开证书文件,将证书里面的内容以字符串的形式通过流写入。(不会写入到apk中)

2.创建秘钥,添加证书进去
3.创建信任管理器,并把秘钥初始化到信任管理器里
4.获取SLL上下文,并把信任管理器初始化到SSL里
5.获取socket工厂,设置到okhttpclient中
6.检验主机名

 if (UrlConsts.serverUrl.contains("https://")){
            InputStream cerInputStream = null;
            try {
                //方式一:在assets中获取证书
                cerInputStream = context.getAssets().open("ssl.cer");
                //方式二:把字符串通过流的形式获取证书
//                cerInputStream =  new ByteArrayInputStream(cerText.getBytes("UTF-8"));
                //获取socket工厂
                SSLSocketFactory sslSocketFactory = SSLUtil.getSSLSocketFactory(cerInputStream);
                //okhttp设置socket工厂
                okHttpClientBuilder.sslSocketFactory(sslSocketFactory);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //检验主机名
        okHttpClientBuilder.hostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
public class SSLUtil {


    /**
     * 返回SSLSocketFactory
     *
     * @param certificates 证书的输入流
     * @return SSLSocketFactory
     */
    public static SSLSocketFactory getSSLSocketFactory(InputStream... certificates) {
        return getSSLSocketFactory(null,certificates);
    }

    /**
     * 双向认证
     * @param keyManagers KeyManager[]
     * @param certificates 证书的输入流
     * @return SSLSocketFactory
     */
    public static SSLSocketFactory getSSLSocketFactory(KeyManager[] keyManagers, 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));
                try {
                    if (certificate != null) certificate.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            //创建信任管理工厂
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            //初始化信任管理器
            trustManagerFactory.init(keyStore);

            //获取SSL上下文对象
            SSLContext sslContext = SSLContext.getInstance("TLS");
            //初始化信任管理器
            sslContext.init(keyManagers, trustManagerFactory.getTrustManagers(), new SecureRandom());
            //获取socket工厂
            SSLSocketFactory socketFactory = sslContext.getSocketFactory();
            return socketFactory;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

测试运行,完美解决。
2.信任所有证书(不建议使用)
服务端提供的证书文件,如果服务端更改了需要客户端进行相应的更改,否则无法请求服务端数据。如果想不换证书可以继续访问,可以通过X509TrustManager信任所有的证书,以达到客户端不换证书文件就能获取到服务端数据,但不建议这样使用!!!

 /**
     *信任所有证书(不建议使用)
     * @return
     */
    public static SSLSocketFactory getAllSSLSocketFactory(){

        //创建X509信任管理器
        TrustManager[] trustManagers = new TrustManager[]{
                new X509TrustManager() {
                    @Override
                    public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

                    }

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

                    }

                    @Override
                    public X509Certificate[] getAcceptedIssuers() {
                        return new X509Certificate[0];
                    }
                }
        };
        try {
            //获取SSL上下文对象
            SSLContext sslContext = SSLContext.getInstance("TLS");
            //初始化无信任管理器
            sslContext.init(null, trustManagers, new SecureRandom());
            //获取socket工厂
            SSLSocketFactory socketFactory = sslContext.getSocketFactory();
            return socketFactory;
        } catch (NoSuchAlgorithmException | KeyManagementException e) {
            e.printStackTrace();
        }
       return null;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

四、Glide4.0以上 添加自签名证书

Glide 直接加载没有权威机构颁发的证书https的URL会直接抛出错误SSLHandshakeException(CertPathValidatorException证书路径验证器异常)

	javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
  • 1

在这里插入图片描述
看到CertPathValidatorException这个异常,不用多说也知道什么原因导致的,所以我们需要对Glide内部的Okhttp3进行https自签名。

  1. 从Glide官网查到,需 添加Glide需要的依赖

在这里插入图片描述

	// Glide图片加载库
    api 'com.github.bumptech.glide:glide:4.11.0'
    // Glide需要处理注解时的依赖库,用于处理注解并生成java类
    annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
    // Glide集成OkHttp时需要使用的库
    api 'com.github.bumptech.glide:okhttp3-integration:4.11.0'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  1. 创建一个类继承AppGlideModule并对该类添加GlideModule注解,由Glide的注解处理器自动帮我们处理该类,无需其他操作和配置,添加Https的证书信任,最后替换掉Glide内部的okHttp使用我们自己创建的
//注解处理器帮助我们生成meta-data,无需自行配置
@GlideModule
public class OkHttpGlideModule extends AppGlideModule {

    private SSLSocketFactory mSSLSocketFactory;
    private X509TrustManager mX509TrustManager;

    @Override
    public void registerComponents(Context context, Glide glide, Registry registry) {
        super.registerComponents(context, glide, registry);
        replace(registry);
    }

    private void replace(Registry registry) {
        //信任管理器
        mX509TrustManager = new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { }
            @Override
            public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { }
            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
        };
        //构建OkHttpClient.Builder
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        try {
            //获取SSL上下文对象
            SSLContext sslContext = SSLContext.getInstance("SSL");
            //初始化信任管理器
            sslContext.init(null, new TrustManager[]{mX509TrustManager}, new SecureRandom());
            //获取Socket工厂
            mSSLSocketFactory = sslContext.getSocketFactory();
            //OkHttp设置Socket工厂
            builder.sslSocketFactory(mSSLSocketFactory, mX509TrustManager);
        } catch (NoSuchAlgorithmException | KeyManagementException e) {
            e.printStackTrace();
        }
        //构建OkHttpClient
        OkHttpClient okHttpClient = builder.build();
        //替换Glide内部的OkHttpClient
        registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory(okHttpClient));
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  1. 更换Glide为注解处理器生成的GlideApp
 GlideApp.with(context).load(url).apply(options).into(imageView);
  • 1

万事俱备,只需测试,运行跑一下,呃呃呃,尴尬了翻车了…可以看到SSLPeerUnverifiedException异常Hostname 172.17.230.133 not verified,逗我玩了,都已经做认证了凭什么不给我通过,经过百度和对这段话的分析,发现subjectAltName是个空值,大概率猜测会不会是这个值导致的。于是搜索发现:

数字证书使用 Subject 子项标明证书的持有者,并且使用 subjectAltName 扩展项对持有者的身份进行更多的标记和界定,在 subjectAltName 中可以包含有关持有者身份的多条信息。如果证书持有者是一个CA,则 Subject 项不能为空,必须包含一个 DN 名,该 DN 名必须与该 CA 颁发的所有证书中 Issuer 项的 DN 名相同。

简单说就是 X.509 数字证书中的扩展字段,可以包括更多的主机信息:IP地址、DNS、Email等。原因就是ssl证书的SAN 这块儿没有配置,必须要通过证书中的SAN扩展字段中拿到IP地址做二次校验,才能够建立连接。
在这里插入图片描述
只需要在上面代码中添加hostName进行再次验证

 //设置主机名进行再次验证
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String s, SSLSession sslSession) {
                    return true;
                }
            });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

运行测试,完美解决

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/210584
推荐阅读
相关标签
  

闽ICP备14008679号