一、概述
其实这篇文章理论上不限于okhttp去访问自签名的网站,不过接上篇博文了,就叫这个了。首先要了解的事,okhttp默认情况下是支持https协议的网站的,比如https://www.baidu.com
,https://github.com/hongyangAndroid/okhttp-utils
等,你可以直接通过okhttp请求试试。不过要注意的是,支持的https的网站基本都是CA机构颁发的证书,默认情况下是可以信任的。
当然我们今天要说的是自签名的网站,什么叫自签名呢?就是自己通过keytool
去生成一个证书,然后使用,并不是CA机构去颁发的。使用自签名证书的网站,大家在使用浏览器访问的时候,一般都是报风险警告,如下界面:使用 okhttp 进行访问时未信任的安全网站时会提示
javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
或
javax.net.ssl.SSLPeerUnverifiedException: Hostname xxxx.com not verified:
二、解决办法
解决办法有两种
信任所有的证书(开发测试使用)
导入自签名证书
1、信任所有的证书
信任所有的证书后可以成功解决掉不能访 https 自签名地址的问题,但这样也就失去了使用自签名的意义。开发过程中可以使用这种方式屏蔽掉自签名,需要使用到无法获得证书的地址的资源时也可以使用这种方式。
实现代码
import okhttp3.OkHttpClient; import javax.net.ssl.*; import java.security.SecureRandom; import java.security.cert.X509Certificate; /** * 封装的支持Https连接工具类 */ public class HttpsUtils { private MyTrustManager mMyTrustManager; private SSLSocketFactory createSSLSocketFactory() { SSLSocketFactory ssfFactory = null; try { mMyTrustManager = new MyTrustManager(); SSLContext sc = SSLContext.getInstance("TLS"); sc.init(null, new TrustManager[]{mMyTrustManager}, new SecureRandom()); ssfFactory = sc.getSocketFactory(); } catch (Exception ignored) { ignored.printStackTrace(); } return ssfFactory; } /** * 实现X509TrustManager接口 */ public class MyTrustManager implements X509TrustManager { @Override public void checkClientTrusted(X509Certificate[] chain, String authType) { } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) { } @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } } /** * 实现HostnameVerifier接口(信任所有的 https 证书。) */ private class TrustAllHostnameVerifier implements HostnameVerifier { @Override public boolean verify(String hostname, SSLSession session) { return true; } } public OkHttpClient getTrustAllClient() { OkHttpClient.Builder mBuilder = new OkHttpClient.Builder(); mBuilder.sslSocketFactory(createSSLSocketFactory(), mMyTrustManager) .hostnameVerifier(new TrustAllHostnameVerifier()); return mBuilder.build(); } }
实现步骤:
-
创建实现 HostnameVerifier 接口的类并重写他的
verify
方法使其直接返回true
; -
创建实现 X509TrustManager 接口的类并重写
getAcceptedIssuers()
使其返回 new X509Certificate[0]; -
构建 SSL 工厂
SSLSocketFactory
即上面代码中的createSSLSocketFactory()
方法; -
使用 OkHttpClient.Builder 中设置 sslSocketFactory(
构建的工厂
,实现的 TrustManager 类),此处的 TurstManager 需要保持跟 Factory 中使用的 TrustManager 是同一个实例。设置 hostnameVerifier 为构建的 HostnameVerifier;
2、导入自签名证书
信任所有证书虽然能解决不能访问 https 服务器地址的问题,但安全性被忽视掉了。显然是不符合要求的,用 https 就是为了安全性跳过 验证也就失去了他的意义了。好在我们还有其他的方法来解决----导入自签名的证书。
未完带补充。。。