美文网首页代码片段分享
Android https忽略证书信任问题, 以及性能问题

Android https忽略证书信任问题, 以及性能问题

作者: 花艺荣 | 来源:发表于2020-11-27 19:47 被阅读0次

    【第一部分,忽略证书信任问题】 直接去第二部分性能问题
    搬运自:https://blog.csdn.net/lizeyang/article/details/18983843
    java程序在访问https资源时,出现报错

    sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

    1)https通信过程

    (1)客户使用https的URL访问Web服务器,要求与Web服务器建立SSL连接。

    (2)Web服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端。

    (3)客户端的浏览器与Web服务器开始协商SSL连接的安全等级,也就是信息加密的等级。

    (4)客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的公钥将会话密钥加密,并传送给网站。

    (5)Web服务器利用自己的私钥解密出会话密钥。

    (6)Web服务器利用会话密钥加密与客户端之间的通信。

    image

    2)java程序的证书信任规则

    如上文所述,客户端会从服务端拿到证书信息。调用端(客户端)会有一个证书信任列表,拿到证书信息后,会判断该证书是否可信任。

    如果是用浏览器访问https资源,发现证书不可信任,一般会弹框告诉用户,对方的证书不可信任,是否继续之类。

    Java虚拟机并不直接使用操作系统的keyring,而是有自己的security manager。与操作系统类似,jdk的security manager默认有一堆的根证书信任。如果你的https站点证书是花钱申请的,被这些根证书所信任,那使用java来访问此https站点会非常方便。因此,如果用java访问https资源,发现证书不可信任,则会报文章开头说到的错误。

    解决问题的方法

    1)将证书导入到jdk的信任证书中(理论上应该可行,未验证)

    2)在客户端(调用端)添加逻辑,忽略证书信任问题

    第一种方法,需要在每台运行该java程序的机器上,都做导入操作,不方便部署,因此,采用第二种方法。下面贴下该方法对应的代码。

    1)先实现验证方法

    void trustAllHttpsCertificates() throws Exception {
            TrustManager[] trustAllCerts = new TrustManager[1];
            trustAllCerts[0] = new MyTrustManager();
            SSLContext sslCtx = SSLContext.getInstance("SSL");
            sslCtx.init(null, trustAllCerts, null);
            javax.net.ssl.SSLSocketFactory sslsocketfactory = sslCtx.getSocketFactory();
            javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sslsocketfactory);
        }
    
    class MyTrustManager implements TrustManager, X509TrustManager {
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
    
            public boolean isServerTrusted(X509Certificate[] certs) {
                return true;
            }
    
            public boolean isClientTrusted(X509Certificate[] certs) {
                return true;
            }
    
            public void checkServerTrusted(X509Certificate[] certs, String authType)
                    throws CertificateException {
                return;
            }
    
            public void checkClientTrusted(X509Certificate[] certs, String authType)
                    throws CertificateException {
                return;
            }
        }
    

    2)在访问https资源前,调用

    try {
                trustAllHttpsCertificates();
            } catch (Exception e) {
                e.printStackTrace();
            } //setDefaultSSLSocketFactory
            HostnameVerifier hv = (urlHostName, session) -> {
                Log.e("apibhuc", "Warning: URL Host: v7" + urlHostName + " vs. " + session.getPeerHost());
                return true;
            };
            HttpsURLConnection.setDefaultHostnameVerifier(hv);  // outer try catch
    

    【第二部分,以上代码性能问题】

    如果你像上面说的每次请求都添加上面的代码,那么会有性能问题,具体就是访问耗时,应将将上面部分代码放至应用初始化时;

    相关文章

      网友评论

        本文标题:Android https忽略证书信任问题, 以及性能问题

        本文链接:https://www.haomeiwen.com/subject/ebffwktx.html