我的服务器正在使用自签名证书。我正在使用 Okhttp + Retrofit 进行 api 调用。我从服务器获得了 crt 文件和公钥 [SHA-256]。按照这个和来自谷歌文档的这个链接,我在xml文件夹中创建了一个 network_security_config 文件,并将我的 crt 文件添加到raw文件夹中,并将其添加到清单文件中
android:networkSecurityConfig="@xml/network_security_config"
这是我根据谷歌文档的网络配置文件:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config>
<domain includeSubdomains="true">2.48.3.66:</domain>
<pin-set>
<pin digest="SHA-256">ofJqMSD8j9q3w5myKalxjJO5OklHyBqgkwgHjqcOhds=</pin>
</pin-set>
<trust-anchors>
<certificates src="@raw/ssl_certificate"/>
</trust-anchors>
</domain-config>
</network-security-config>
调用 api 时出现以下异常
Response Failure: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
W/System.err: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
W/System.err: at com.android.org.conscrypt.ConscryptFileDescriptorSocket.startHandshake(ConscryptFileDescriptorSocket.java:231)
W/System.err: at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.kt:367)
W/System.err: at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.kt:325)
W/System.err: at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:197)
W/System.err: at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:249)
W/System.err: at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:108)
W/System.err: at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:76)
W/System.err: at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:245)
W/System.err: at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
W/System.err: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
W/System.err: at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:96)
W/System.err: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
W/System.err: at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
W/System.err: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
W/System.err: at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76)
W/System.err: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
W/System.err: at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.kt:219)
W/System.err: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
W/System.err: at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:197)
W/System.err: at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:502)
W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
W/System.err: at java.lang.Thread.run(Thread.java:919)
所以以下是我的查询:
这是实施自签名证书固定的正确方法吗?因为谷歌在他们的文档中明确提到“幸运的是,您可以通过配置应用程序的网络安全配置来教您的应用程序信任自定义 CA ,而无需修改应用程序内部的代码。”
如果 network_security_config 正确,那么如何检查服务器配置是否有问题(crt 文件 + 公钥)
我是否需要手动加载 crt 文件,然后使用 keystore + sslfactory 来配置 ssl pinning,如此链接中提到的
注意:现在只是为了运行 api,我使用了一个不验证证书链的信任管理器,如下所示:
try {
val trustAllCerts: Array<TrustManager> = arrayOf(object : X509TrustManager {
override fun checkClientTrusted(chain: Array<out java.security.cert.X509Certificate>?, authType: String?) {
}
override fun checkServerTrusted(chain: Array<out java.security.cert.X509Certificate>?, authType: String?) {
}
override fun getAcceptedIssuers(): Array<out java.security.cert.X509Certificate>? = arrayOf()
})
// Install the all-trusting trust manager
val sslContext = SSLContext.getInstance("SSL")
sslContext.init(null, trustAllCerts, SecureRandom())
// Create an ssl socket factory with our all-trusting manager
val sslSocketFactory = sslContext.socketFactory
if (trustAllCerts.isNotEmpty() && trustAllCerts.first() is X509TrustManager) {
builder.sslSocketFactory(sslSocketFactory, trustAllCerts.first() as X509TrustManager)
builder.hostnameVerifier { hostname, session -> true }
}
} catch (e: Exception) {
}