一、前言:
项目中使用的是okhttp,https请求报异常:
Caused by: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
at org.conscrypt.ConscryptFileDescriptorSocket.startHandshake(ConscryptFileDescriptorSocket.java:230)
at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:320)
at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:284)
at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:169)
at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:258)
at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:135)
at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:114)
at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:127)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
是由于Https使用的证书的问题,Https是安全的http请求,请求时需要验证SSL证书。
#####上述报错的原因有几种情况:
- 1.https服务器还没有配置SSL证书。
- 2.https服务器配置的不是正规的CA机构签发的证书,可能是二级代理商等签发的证书,验证不通过造成的。
- SSL/TLS证书是需要去专门的CA机构购买的,一般是买一年期的。当然CA机构也提供免费的CA证书,但是有效期一般比较短,比如只有三个月,且安全性不高。
- SSL/TLS证书提供商的常见品牌:Symantec、Comodo、GeoTrust、GlobalSign、RapidSSL、DigiCert、GlobalSign等
延伸的思考:
-1、https请求时在握手阶段请求下来的ssl证书存储在哪里?还是说不缓存,只存储在内存中? -2、客户端验证证书过程?是将证书发给CA机构进行验证,还是根据证书里的CA机构的签名以及CA机构的公钥进行验证? -3、数字证书提供商靠谱吗? -4、没有域名只有ip可以使用https请求吗?
在CA机构申请CA证书时填写的是域名,所以,证书里的信息绑定的是域名,跟ip无关,因此ip+端口的形式无法使用https请求,因为证书不能绑定到ip,请求时无法获取到证书?初步理解,有待考证…
AWS也是个CA机构,证书费用每个月3千多美刀,一年3-4万美刀。 阿里云的ssl服务是以代理商的方式,本身不是CA机构,证书费用一年两千多。
二、解决:
1、解决方案1:忽略https的证书校验
package com.example.myapplication.utils;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
/**
* @author lyy
* 方案一:让okhttp支持https请求
*/
public class SSLSocketClient {
public static SSLSocketFactory getSSLSocketFactory() {
try {
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, getTrustManager(), new SecureRandom());
return sslContext.getSocketFactory();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static TrustManager[] getTrustManager() {
return new TrustManager[]{
new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
}
};
}
public static X509TrustManager geX509tTrustManager() {
return new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
};
}
public static HostnameVerifier getHostnameVerifier() {
return new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
};
}
}
使用:
private val retrofitBuilder by lazy {
Retrofit.Builder()
.baseUrl("https://www.baidu.com")
.client(
OkHttpClient.Builder()
//1、SSL配置一
.sslSocketFactory(SSLSocketClient.getSSLSocketFactory(), SSLSocketClient.geX509tTrustManager())
.hostnameVerifier(SSLSocketClient.getHostnameVerifier())
//2、SSL配置一
// .sslSocketFactory(SSLSocketClient2.getSSLSocketFactory())//配置
// .hostnameVerifier(SSLSocketClient2.getHostnameVerifier())//配置
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(5, TimeUnit.SECONDS)
.writeTimeout(5, TimeUnit.SECONDS).build()
).build()
}
2、解决方案2:忽略https的证书校验
package com.example.myapplication.utils;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
/**
* @author lyy
* 方案二:让okhttp支持https请求
*/
public class SSLSocketClient2 {
//获取这个SSLSocketFactory
public static SSLSocketFactory getSSLSocketFactory() {
try {
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, getTrustManager(), new SecureRandom());
return sslContext.getSocketFactory();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//获取TrustManager
private static TrustManager[] getTrustManager() {
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
}
};
return trustAllCerts;
}
//获取HostnameVerifier
public static HostnameVerifier getHostnameVerifier() {
HostnameVerifier hostnameVerifier = new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
};
return hostnameVerifier;
}
}
使用:
private val retrofitBuilder by lazy {
Retrofit.Builder()
.baseUrl("https://www.baidu.com")
.client(
OkHttpClient.Builder()
//1、SSL配置一
// .sslSocketFactory(SSLSocketClient.getSSLSocketFactory(), SSLSocketClient.geX509tTrustManager())
// .hostnameVerifier(SSLSocketClient.getHostnameVerifier())
//2、SSL配置一
.sslSocketFactory(SSLSocketClient2.getSSLSocketFactory())//配置
.hostnameVerifier(SSLSocketClient2.getHostnameVerifier())//配置
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(5, TimeUnit.SECONDS)
.writeTimeout(5, TimeUnit.SECONDS).build()
).build()
}
详细解释查看:blog.csdn.net/yzpbright/a…