Ktor Socket客户端连接自签名服务器报checkServerTrusted错误如何解决?
问题原因
- 基础配置不匹配:你代码中连接的服务器IP是
192.168.1.5,但网络安全配置中信任的域名是192.168.78.74,二者不一致导致系统级信任配置未生效。 - Ktor 1.x版本的TLS实现缺陷:Ktor 1.6.5的TLS握手逻辑默认调用的是双参数
checkServerTrusted(X509Certificate[], String)方法,而Android 7+的网络安全配置要求必须调用带主机名的三参数重载checkServerTrusted(X509Certificate[], String, String),否则就会抛出你遇到的异常。
解决步骤
第一步:修正网络安全配置匹配
把network_security_config.xml中的domain改为你实际连接的服务器IP:
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config> <domain includeSubdomains="true">192.168.1.5</domain> <trust-anchors> <certificates src="@raw/my_cert"/> </trust-anchors> </domain-config> </network-security-config>
第二步:自定义Ktor TLS配置适配Android要求
在调用tls()方法时传入自定义TLS配置,明确指定服务器主机名,触发系统要求的三参数证书校验逻辑:
// 先定义服务器地址常量 val serverHost = "192.168.1.5" val serverPort = 8080 socketConnection = aSocket(ActorSelectorManager(Dispatchers.IO)) .tcp() .connect(InetSocketAddress(serverHost, serverPort)) .tls( coroutineContext = Dispatchers.IO, config = TLSConfigBuilder().apply { // 明确指定服务器主机名,触发三参数的证书校验方法 serverName = serverHost }.build() )
如果仍有报错,可以手动实现仅信任你的自签名证书的TrustManager,适配校验规则:
class CustomTrustManager(private val trustedCert: X509Certificate) : X509TrustManager { override fun checkClientTrusted(chain: Array<out X509Certificate>?, authType: String?) = Unit override fun checkServerTrusted(chain: Array<out X509Certificate>?, authType: String?) { checkServerTrusted(chain, authType, null) } override fun checkServerTrusted(chain: Array<out X509Certificate>?, authType: String?, host: String?) { chain ?: throw CertificateException("Certificate chain is empty") val serverCert = chain.firstOrNull() ?: throw CertificateException("No server certificate") // 校验证书是否和我们信任的自签名证书一致 if (serverCert.encoded.contentEquals(trustedCert.encoded)) return throw CertificateException("Certificate not trusted") } override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf(trustedCert) }
然后把自定义TrustManager注入到TLS配置中:
// 读取raw目录下的自签名证书 val certFactory = CertificateFactory.getInstance("X.509") val trustedCert = resources.openRawResource(R.raw.my_cert).use { certFactory.generateCertificate(it) as X509Certificate } val customTrustManager = CustomTrustManager(trustedCert) // 构建TLS配置 config = TLSConfigBuilder().apply { serverName = serverHost trustManagers = arrayOf(customTrustManager) }.build()
注意:不要为了省事直接信任所有证书,会导致应用存在中间人攻击风险,仅信任你自己的自签名证书即可。
可选方案:升级Ktor版本
Ktor 2.0及以上版本已经修复了这个TLS校验的兼容问题,如果你的项目可以升级依赖,直接把Ktor版本升到2.x即可,不需要自定义TrustManager,只需要修正IP匹配问题即可正常使用系统网络安全配置。
内容的提问来源于stack exchange,提问作者Michael Dippold
相关产品推荐
相关产品推荐

