项目中使用的是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等
延伸的思考:
- https请求时在握手阶段请求下来的ssl证书存储在哪里?还是说不缓存,只存储在内存中?
- 客户端验证证书过程?是将证书发给CA机构进行验证,还是根据证书里的CA机构的签名以及CA机构的公钥进行验证?
- 数字证书提供商靠谱吗?
- 没有域名只有ip可以使用https请求吗?
在CA机构申请CA证书时填写的是域名,所以,证书里的信息绑定的是域名,跟ip无关,因此ip+端口的形式无法使用https请求,因为证书不能绑定到ip,请求时无法获取到证书?初步理解,有待考证…
AWS也是个CA机构,证书费用每个月3千多美刀,一年3-4万美刀。
阿里云的ssl服务是以代理商的方式,本身不是CA机构,证书费用一年两千多。
解决方案:
解决方案1:
向后台获取最新的ca证书,从后台服务器下载或者存储在app本地都可。
解决方案2:忽略https的证书校验
有时候为了测试需要,可以忽略证书验证。
public class SSLSocketClient {
//获取这个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;
}
}
使用:
String url = "https://wwww.baidu.com";
OkHttpClient okHttpClient = new OkHttpClient()
.newBuilder()
.sslSocketFactory(SSLSocketClient.getSSLSocketFactory())//配置
.hostnameVerifier(SSLSocketClient.getHostnameVerifier())//配置
.build();
final Request request = new Request.Builder()
.url(url)
.get()
.build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {[添加链接描述](https://docs.oracle.com/javase/8/docs/api/javax/net/ssl/SSLSocketFactory.html)
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG, "onFailure: ");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(TAG, "onResponse: " + response.body().string());
}
});
OkHttpClient.Builder的sslSocketFactory方法
该方法的官方介绍:
//OkHttpClient.java
...
/**
* Sets the socket factory and trust manager used to secure HTTPS connections. If unset, the
* system defaults will be used.
*
* <p>Most applications should not call this method, and instead use the system defaults. Those
* classes include special optimizations that can be lost if the implementations are decorated.
*
* <p>If necessary, you can create and configure the defaults yourself with the following code:
*
* <pre> {@code
*
* TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
* TrustManagerFactory.getDefaultAlgorithm());
* trustManagerFactory.init((KeyStore) null);
* TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
* if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
* throw new IllegalStateException("Unexpected default trust managers:"
* + Arrays.toString(trustManagers));
* }
* X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
*
* SSLContext sslContext = SSLContext.getInstance("TLS");
* sslContext.init(null, new TrustManager[] { trustManager }, null);
* SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
*
* OkHttpClient client = new OkHttpClient.Builder()
* .sslSocketFactory(sslSocketFactory, trustManager)
* .build();
* }</pre>
*/
public Builder sslSocketFactory(SSLSocketFactory sslSocketFactory, X509TrustManager trustManager) {
if (sslSocketFactory == null) throw new NullPointerException("sslSocketFactory == null");
if (trustManager == null) throw new NullPointerException("trustManager == null");
this.sslSocketFactory = sslSocketFactory;
this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
return this;
}
...
该方法有两个参数:sslSocketFactory和trustManager。
sslSocketFactory是用于创建SSLSocket的。
trustManager是用于传递给CertificateChainCleaner.get(trustManager);的,是用于构造证书链清洁器CertificateChainCleaner并用于清理证书列表的:
//CertificateChainCleaner.java
/**
* Computes the effective certificate chain from the raw array returned by Java's built in TLS APIs.
* Cleaning a chain returns a list of certificates where the first element is {@code chain[0]}, each
* certificate is signed by the certificate that follows, and the last certificate is a trusted CA
* certificate.
*
* <p>Use of the chain cleaner is necessary to omit unexpected certificates that aren't relevant to
* the TLS handshake and to extract the trusted CA certificate for the benefit of certificate
* pinning.
*/
public abstract class CertificateChainCleaner {
public abstract List<Certificate> clean(List<Certificate><

本文详细分析了HTTPS请求中遇到的SSLHandshakeException异常,指出问题可能源于服务器证书未配置或非正规CA签发。解释了SSL/TLS证书的验证流程,包括TrustManager用于验证证书本身的有效性,而HostnameVerifier则确认证书与请求的域名匹配。同时,介绍了如何自定义TrustManager和HostnameVerifier以忽略证书验证,以及OkHttp中相关方法的使用。最后,讨论了X509证书和信任管理器在HTTPS连接中的作用。

4854

被折叠的 条评论
为什么被折叠?



