Android https忽略证书信任问题

原文地址 www.cnblogs.com

【第一部分,忽略证书信任问题】 直接去第二部分性能问题
搬运自: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 服务器利用会话密钥加密与客户端之间的通信。

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

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

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

posted @ 2023-03-29 12:14  cps666  阅读(290)  评论(0编辑  收藏  举报