基于Android10的忽略HTTPS证书校验

文章目录

    • 为什么要忽略证书校验
    • 证书校验不通过,怎么办呢?

为什么要忽略证书校验

从Android 9 开始 APP默认访问的URL 必须是HTTPS协议的,虽然可以配置回支持HTTP,但这种做法不建议使用,已经0202年了,HTTPS早已经是主流。既然要使用HTTPS协议,就少不了CA证书,这个证书是收费的,也有些平台可以什么一年有效期的免费证书,但作为个人开发者,自己建个项目,开发用,完全没必要,我们使用JDK下的keytool生成 https证书。具体方法网上有很多,在此不再叙述。

由于是自建证书,它是不被浏览器或是系统认可的,在Android中使用OkHttp访问时,会报如下错误:

W/System.err: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
2020-03-31 12:27:58.570 26059-26059/com.s W/System.err:     at com.android.org.conscrypt.ConscryptFileDescriptorSocket.startHandshake(ConscryptFileDescriptorSocket.java:231)
2020-03-31 12:27:58.570 26059-26059/com.s W/System.err:     at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.kt:367)
2020-03-31 12:27:58.570 26059-26059/com.s W/System.err:     at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.kt:325)
2020-03-31 12:27:58.571 26059-26059/com.s W/System.err:     at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:197)
2020-03-31 12:27:58.571 26059-26059/com.s W/System.err:     at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:233)
2020-03-31 12:27:58.571 26059-26059/com.s W/System.err:     at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:107)
2020-03-31 12:27:58.571 26059-26059/com.s W/System.err:     at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:75)
2020-03-31 12:27:58.571 26059-26059/com.s W/System.err:     at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:245)
2020-03-31 12:27:58.571 26059-26059/com.s W/System.err:     at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
2020-03-31 12:27:58.571 26059-26059/com.s W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
2020-03-31 12:27:58.571 26059-26059/com.s W/System.err:     at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:82)
2020-03-31 12:27:58.571 26059-26059/com.s W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
2020-03-31 12:27:58.571 26059-26059/com.s W/System.err:     at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
2020-03-31 12:27:58.571 26059-26059/com.s W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
2020-03-31 12:27:58.572 26059-26059/com.s W/System.err:     at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:74)
2020-03-31 12:27:58.572 26059-26059/com.s W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)

证书校验不通过,怎么办呢?

我们需要让OkHttp忽略掉证书校验,网上有很多做法都是:

/**
     * OkHttpClient客户端
     */
    private fun newClient(): OkHttpClient = OkHttpClient.Builder().apply {
            connectTimeout(30, TimeUnit.SECONDS)// 连接时间:30s超时
            readTimeout(10, TimeUnit.SECONDS)// 读取时间:10s超时
            writeTimeout(10, TimeUnit.SECONDS)// 写入时间:10s超时
        // 忽略证书验证 start
        val x509 = MyX509()
        sslSocketFactory(getSSLFactory(x509), x509)
        hostnameVerifier(HostnameVerifier { _, _ -> true })
        // 忽略证书验证 end
        }.build()
        
private fun getSSLFactory(x509TrustManager: X509TrustManager): SSLSocketFactory {
        val trustAllCerts = arrayOf<TrustManager>(x509TrustManager)
        val sslContext = SSLContext.getInstance("SSL")
        sslContext.init(null, trustAllCerts, java.security.SecureRandom())
        return sslContext.socketFactory
    }
    
class MyX509 : X509TrustManager {

        override fun getAcceptedIssuers(): Array<X509Certificate> {
            return arrayOf()
        }

        @Throws(CertificateException::class)
        override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) {
        }

        @Throws(CertificateException::class)
        override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) {
        }
    }

如果这么配置后在Android 10 上会报如下错误:

08:20:04 V/InstrumentationResultParser: java.lang.IllegalArgumentException: Required method checkServerTrusted(X509Certificate[], String, String, String) missing
08:20:04 V/InstrumentationResultParser: at android.net.http.X509TrustManagerExtensions.(X509TrustManagerExtensions.java:71)
08:20:04 V/InstrumentationResultParser: at okhttp3.internal.platform.android.Android10CertificateChainCleaner.(Android10CertificateChainCleaner.kt:36)
08:20:04 V/InstrumentationResultParser: at okhttp3.internal.platform.Android10Platform.buildCertificateChainCleaner(Android10Platform.kt:62)
08:20:04 V/InstrumentationResultParser: at okhttp3.internal.tls.CertificateChainCleaner$Companion.get(CertificateChainCleaner.kt:42)
08:20:04 V/InstrumentationResultParser: at okhttp3.OkHttpClient$Builder.sslSocketFactory(OkHttpClient.kt:751)
08:20:04 V/InstrumentationResultParser: at okhttp.android.test.OkHttpTest.testCustomTrustManager(OkHttpTest.kt:437)
08:20:04 V/InstrumentationResultParser: at java.lang.reflect.Method.invoke(Native Method)
08:20:04 V/InstrumentationResultParser: at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
08:20:04 V/InstrumentationResultParser: at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
08:20:04 V/InstrumentationResultParser: at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
08:20:04 V/InstrumentationResultParser: at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
08:20:04 V/InstrumentationResultParser: at okhttp3.OkHttpClientTestRule$apply$1.evaluate(OkHttpClientTestRule.kt:111)
08:20:04 V/InstrumentationResultParser: at okhttp3.testing.PlatformRule$apply$1.evaluate(PlatformRule.kt:66)

其实这个问题已经有人在OkHttp的GitHub中提了issues,具体的解决方案是把X509TrustManager的实现类换成X509ExtendedTrustManager实现类即可

@RequiresApi(Build.VERSION_CODES.N)
    class MyX509 : X509ExtendedTrustManager() {
        override fun checkClientTrusted(
            chain: Array<out X509Certificate>?,
            authType: String?,
            socket: Socket?
        ) {
        }

        override fun checkClientTrusted(
            chain: Array<out X509Certificate>?,
            authType: String?,
            engine: SSLEngine?
        ) {
        }

        override fun checkClientTrusted(chain: Array<out X509Certificate>?, authType: String?) {
        }

        override fun checkServerTrusted(
            chain: Array<out X509Certificate>?,
            authType: String?,
            socket: Socket?
        ) {
        }

        override fun checkServerTrusted(
            chain: Array<out X509Certificate>?,
            authType: String?,
            engine: SSLEngine?
        ) {
        }

        override fun checkServerTrusted(chain: Array<out X509Certificate>?, authType: String?) {
        }

        override fun getAcceptedIssuers(): Array<X509Certificate> {
            return arrayOf()
        }
    }

相关issues地址

你可能感兴趣的:(Android)