Android OkHttp3网络请求SSL证书验证问题绕过解决方案(包括Android 10及以上适配)

2022-07-30 07:55:55

出现情况

当我们将之前封装的一套OKhttp的网络请求换成HTTPS的时候会发现,日志中会报出:

java.security.cert.CertPathValidatorException
Caused by: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

如下所示:

2021-11-1909:16:12.1407773-7773W/System.err:Caused by:java.security.cert.CertificateException:java.security.cert.CertPathValidatorException:Trust anchorfor certification path not found.2021-11-1909:16:12.1407773-7773W/System.err:     atcom.android.org.conscrypt.TrustManagerImpl.verifyChain(TrustManagerImpl.java:674)2021-11-1909:16:12.1407773-7773W/System.err:     atcom.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:551)2021-11-1909:16:12.1407773-7773W/System.err:     atcom.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:617)2021-11-1909:16:12.1407773-7773W/System.err:     atcom.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:507)2021-11-1909:16:12.1407773-7773W/System.err:     atcom.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:426)2021-11-1909:16:12.1407773-7773W/System.err:     atcom.android.org.conscrypt.TrustManagerImpl.getTrustedChainForServer(TrustManagerImpl.java:354)2021-11-1909:16:12.1407773-7773W/System.err:     atandroid.security.net.config.NetworkSecurityTrustManager.checkServerTrusted(NetworkSecurityTrustManager.java:94)2021-11-1909:16:12.1407773-7773W/System.err:     atandroid.security.net.config.RootTrustManager.checkServerTrusted(RootTrustManager.java:89)2021-11-1909:16:12.1407773-7773W/System.err:     atcom.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:224)2021-11-1909:16:12.1407773-7773W/System.err:     atcom.android.org.conscrypt.ConscryptFileDescriptorSocket.verifyCertificateChain(ConscryptFileDescriptorSocket.java:407)2021-11-1909:16:12.1407773-7773W/System.err:     atcom.android.org.conscrypt.NativeCrypto.SSL_do_handshake(NativeMethod)2021-11-1909:16:12.1407773-7773W/System.err:     atcom.android.org.conscrypt.NativeSsl.doHandshake(NativeSsl.java:387)2021-11-1909:16:12.1407773-7773W/System.err:     atcom.android.org.conscrypt.ConscryptFileDescriptorSocket.startHandshake(ConscryptFileDescriptorSocket.java:226)2021-11-1909:16:12.1407773-7773W/System.err:...34 more2021-11-1909:16:12.1417773-7773W/System.err:Caused by:java.security.cert.CertPathValidatorException:Trust anchorfor certification path not found.2021-11-1909:16:12.1417773-7773W/System.err:...47 more

一番摸索之后,网上给出常规解决方案是在OkHttpClient.Builder 创建者中添加sslSocketFactory()hostnameVerifier() 来忽略对SSL证书的验证,如下所示:


        okHttpClient=newOkHttpClient.Builder().connectTimeout(DEFAULT_CONNECT_TIME,TimeUnit.SECONDS).writeTimeout(DEFAULT_WRITE_TIME,TimeUnit.SECONDS).readTimeout(DEFAULT_READ_TIME,TimeUnit.SECONDS)//注意此处.sslSocketFactory(MySSLSocketClient.getSSLSocketFactory(),MySSLSocketClient.X509).hostnameVerifier(MySSLSocketClient.getHostnameVerifier())//.addInterceptor(chain->{Request original= chain.request();Request request= original.newBuilder().headers(headersBuilder.build()).method(original.method(), original.body()).build();return chain.proceed(request);}).build();

MySSLSocketClient

importjava.security.SecureRandom;importjava.security.cert.X509Certificate;importjavax.net.ssl.HostnameVerifier;importjavax.net.ssl.SSLContext;importjavax.net.ssl.SSLSession;importjavax.net.ssl.SSLSocketFactory;importjavax.net.ssl.TrustManager;importjavax.net.ssl.X509TrustManager;publicclassMySSLSocketClient{//获取这个SSLSocketFactorypublicstaticSSLSocketFactorygetSSLSocketFactory(){try{SSLContext sslContext=SSLContext.getInstance("SSL");
            sslContext.init(null,getTrustManager(),newSecureRandom());return sslContext.getSocketFactory();}catch(Exception e){thrownewRuntimeException(e);}}//获取TrustManagerpublicstaticTrustManager[]getTrustManager(){TrustManager[] trustAllCerts=newTrustManager[]{newX509TrustManager(){@OverridepublicvoidcheckClientTrusted(X509Certificate[] chain,String authType){}@OverridepublicvoidcheckServerTrusted(X509Certificate[] chain,String authType){}@OverridepublicX509Certificate[]getAcceptedIssuers(){//8.0之前返回nullreturnnewX509Certificate[]{};}}};return trustAllCerts;}//获取HostnameVerifierpublicstaticHostnameVerifiergetHostnameVerifier(){HostnameVerifier hostnameVerifier=newHostnameVerifier(){@Overridepublicbooleanverify(String s,SSLSession sslSession){returntrue;}};return hostnameVerifier;}}

至此,常规操作已经可以解决问题了。
但是,对于Android开发者来说总所周知的一件事就是:版本适配!(手动心酸泪目…)
对于在Android 10及以上的设备上,会出现设备信任问题(个人理解命名),报错如:
Required method checkServerTrusted
Unable to extract the trust manager on Android10Platform 之类

解决方式

在 OkHttp 的GitHub 中的 issues 已经给出了具体的解决方案
就是把上面 MySSLSocketClient类中的X509TrustManager 的实现类换成X509ExtendedTrustManager 实现类即可。

最终 MySSLSocketClient 类如下:

importjava.net.Socket;importjava.security.SecureRandom;importjava.security.cert.CertificateException;importjava.security.cert.X509Certificate;importjavax.net.ssl.HostnameVerifier;importjavax.net.ssl.SSLContext;importjavax.net.ssl.SSLEngine;importjavax.net.ssl.SSLSession;importjavax.net.ssl.SSLSocketFactory;importjavax.net.ssl.TrustManager;importjavax.net.ssl.X509ExtendedTrustManager;publicclassMySSLSocketClient{//获取TrustManagerpublicstaticX509ExtendedTrustManager X509=newX509ExtendedTrustManager(){@OverridepublicvoidcheckClientTrusted(X509Certificate[] x509Certificates,String s,Socket socket)throwsCertificateException{}@OverridepublicvoidcheckServerTrusted(X509Certificate[] x509Certificates,String s,Socket socket)throwsCertificateException{}@OverridepublicvoidcheckClientTrusted(X509Certificate[] x509Certificates,String s,SSLEngine sslEngine)throwsCertificateException{}@OverridepublicvoidcheckServerTrusted(X509Certificate[] x509Certificates,String s,SSLEngine sslEngine)throwsCertificateException{}@OverridepublicvoidcheckClientTrusted(X509Certificate[] x509Certificates,String s)throwsCertificateException{}@OverridepublicvoidcheckServerTrusted(X509Certificate[] x509Certificates,String s)throwsCertificateException{}@OverridepublicX509Certificate[]getAcceptedIssuers(){returnnewX509Certificate[0];}};//获取这个SSLSocketFactorypublicstaticSSLSocketFactorygetSSLSocketFactory(){try{SSLContext sslContext=SSLContext.getInstance("SSL");
            sslContext.init(null,newTrustManager[]{X509},newSecureRandom());return sslContext.getSocketFactory();}catch(Exception e){thrownewRuntimeException(e);}}//获取HostnameVerifierpublicstaticHostnameVerifiergetHostnameVerifier(){HostnameVerifier hostnameVerifier=newHostnameVerifier(){@Overridepublicbooleanverify(String s,SSLSession sslSession){returntrue;}};return hostnameVerifier;}}
  • 作者:MrRobot_
  • 原文链接:https://blog.csdn.net/sinat_35214775/article/details/121414905
    更新时间:2022-07-30 07:55:55