关于okhttp的SSLPeerUnverifiedException(ce.message).apply { initCause(ce) }
问题原因
SSLPeerUnverifiedException在OkHttp中表示SSL握手过程中出现了对等端的身份验证失败。这种异常通常是由于SSL证书验证失败所导致的。在SSL/TLS通信中,服务器端需要提供有效的SSL证书以验证其身份,如果证书无效、过期、或者不受信任,就会触发SSLPeerUnverifiedException异常。 在OkHttp中,当SSL握手过程中发现对等端的SSL证书验证失败时,就会抛出SSLPeerUnverifiedException异常。这种情况可能发生在与服务器建立SSL连接时,客户端无法验证服务器端的SSL证书有效性,进而导致SSLPeerUnverifiedException异常的抛出。 值得注意的是,SSLPeerUnverifiedException异常并不一定表示存在安全问题,有时可能是由于客户端未配置信任的根证书导致的。但也有可能是遭遇了中间人攻击等安全问题。在处理这种异常时,需要仔细检查SSL证书的有效性,并确保客户端和服务器端的证书配置正确,以避免潜在的安全风险。
解决方案
SSLPeerUnverifiedException异常表示SSL握手过程中对等方的身份验证失败,通常在使用HTTPS请求时出现。该异常的出现可能是由于服务器证书不被信任、证书链不完整、证书过期、域名不匹配等原因。 为了解决SSLPeerUnverifiedException异常,可以采取以下几种方法: 1. 信任服务器证书:可以将服务器证书导入到信任库中,让客户端信任该证书。这样客户端在与服务器建立SSL连接时就不会出现身份验证失败的问题。 2. 检查证书链的完整性:确保服务器返回的证书链是完整的,包括中间证书和根证书。如果缺少中间证书,客户端就无法验证服务器证书的有效性。 3. 确保证书未过期:服务器证书需要在有效期内,否则客户端会认为证书已过期而拒绝连接。 4. 确认服务器域名匹配:证书中包含了服务器的域名信息,客户端在验证服务器证书时会检查服务器域名与证书中的域名是否匹配,如果不匹配也会导致SSLPeerUnverifiedException异常。 正确使用示例:
val client = OkHttpClient.Builder()
.sslSocketFactory(sslSocketFactory, trustManager)
.hostnameVerifier { hostname, session -> true }
.build()
val request = Request.Builder()
.url("https://example.com")
.build()
val response = client.newCall(request).execute()
val responseBody = response.body?.string()
println(responseBody)
在以上示例中,我们通过设置合适的SSL认证相关的参数,如SSL Socket工厂、信任管理器和域名验证器,以确保客户端能够正常验证服务器证书,从而避免SSLPeerUnverifiedException异常的出现。
具体例子
SSLPeerUnverifiedException表示SSL握手过程中未能验证对等方身份。为了正确处理这个异常,通常需要添加自定义的HostnameVerifier和TrustManager来验证对等方的身份。 首先,创建一个HostnameVerifier的实现类,用于验证对等方的主机名是否匹配:
val hostnameVerifier = HostnameVerifier { hostname, session ->
// 自定义的主机名验证逻辑,例如检查主机名是否符合预期
true // 返回true表示验证通过,否则验证失败
}
然后,创建一个TrustManager的实现类,用于验证对等方的证书是否受信任:
val trustManager = object : X509TrustManager {
override fun checkClientTrusted(chain: Array?, authType: String?) {
// 检查客户端证书是否受信任,如果需要的话
}
override fun checkServerTrusted(chain: Array?, authType: String?) {
// 自定义的服务器证书验证逻辑,例如检查证书是否受信任
}
override fun getAcceptedIssuers(): Array {
return arrayOf()
}
}
接下来,创建一个SSLContext,并初始化它使用之前创建的HostnameVerifier和TrustManager:
val sslContext = SSLContext.getInstance("TLS")
sslContext.init(null, arrayOf(trustManager), SecureRandom())
最后,使用OkHttp时,将创建的SSLContext设置给OkHttpClient,并且在OkHttpClient中配置HostnameVerifier:
val client = OkHttpClient.Builder()
.sslSocketFactory(sslContext.socketFactory, trustManager)
.hostnameVerifier(hostnameVerifier)
.build()
通过以上步骤,我们为OkHttp配置了自定义的HostnameVerifier和TrustManager,以正确处理SSLPeerUnverifiedException异常。 下面是一个示例,演示了如何正确使用带有自定义HostnameVerifier和TrustManager的OkHttpClient发送HTTPS请求:
val request = Request.Builder()
.url("https://example.com")
.build()
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) throw IOException("Unexpected code $response")
val responseData = response.body?.string()
println(responseData)
}
在这个示例中,我们创建了一个OkHttpClient实例client,用于发送HTTPS请求。在发送请求之前,我们通过自定义HostnameVerifier和TrustManager配置了OkHttpClient,以确保正确处理SSLPeerUnverifiedException异常。