一日一学_okhttp(https忽悠证书过期)
2017-01-06 本文已影响3819人
WuXiao_
最近项目全部换成了https,并且项目进度很急,遇到了一些问题,okhttp默认情况下是支持https协议的网站的(有些情况不行,手机系统时间不对如何解决,就是下面要讲问题),比如常用的网址:https://www.baidu.com, https://www.jianshu.com ...你可以直接通过okhttp请求.不过要注意的是,支持的https的网站基本都是CA机构颁发的证书,默认情况下是可以信任的。
还有一些自签名证书,需要自己通过keytool去生成一个证书,然后使用,并不是CA机构去颁发的。使用自签名证书的网站,浏览器访问的时候,都会提示风险警告,比如:https://kyfw.12306.cn。 今天主要我思考的CA证书的使用。
简单了解Https
HTTPS:HTTP协议 + SSL(SSL位于TCP/IP和HTTP协议之间进行安全保护).
SSL有什么作用:
- 认证用户和服务器,确保数据发送到正确的客户机和服务器;(验证证书)
- 加密数据以防止数据中途被窃取;(加密)
- 维护数据的完整性,确保数据在传输过程中不被改变。(摘要算法)
HTTPS的工作原理(对应SSL):
HTTPS在传输数据之前,客户端与服务端之间会进行一次握手(确立双方加密传输数据的密码信息),握手过程:
- 客户端将自己支持的一套加密算法、HASH算法发送给服务端。
- 服务端从中选出一组加密算法与HASH算法,并将自己的身份信息以证书的形式发回给客户端。证书里面包含了网站地址,加密公钥,以及证书的颁发机构等信息。
- 客户端获得网站证书之后,开始验证证书的合法性,如果证书合法,则生成一串随机数字作为通讯过程中对称加密的秘钥。然后取出证书中的公钥,将这串数字以及HASH的结果进行加密,然后发给服务端。
- 服务端接收客户端发来的数据之后,通过私钥进行解密,然后HASH校验,如果一致,则使用客户端发来的数字串使加密一段握手消息发给客户端。
- 客户端解密,并HASH校验,没有问题,则握手结束。接下来的传输过程将由之前客户端生成的随机密码并利用对称加密算法进行加密。
握手过程中如果有任何错误,都会使加密连接断开,从而阻止了隐私信息的传输。
okhttp(https)使用中出现的问题
之前也说了okhttp默认情况下是支持https协议的网站的,我用的是CA颁发的证书。在系统时间正确的时候正常访问,在系统时间不准确的时候将会报错:
javax.net.ssl.SSLHandshakeException:
com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorExcepti
on: Could not validate certificate: Certificate not valid until Wed Dec 16
09:00:05 GMT+08:00 2015 (compared to Sun Oct 12 16:20:03
GMT+08:00 2003)
这个错误是证书过期导致的,如何修改这个错误?
创建一个自定义X509Certificate,让它忽略证书验证.
public static OkHttpClient.Builder addLogClient(OkHttpClient.Builder builder) {
builder.addInterceptor(logging)
.addNetworkInterceptor(NetWorkInterceptor.REWRITE_CACHE_CONTROL_INTERCEPTOR)
.addInterceptor(NetWorkInterceptor.REWRITE_CACHE_CONTROL_INTERCEPTOR)
.cache(cache)
.cookieJar(cookieJar)
.sslSocketFactory(createSSLSocketFactory());
return builder;
}
@SuppressLint("TrulyRandom")
private static SSLSocketFactory createSSLSocketFactory() {
SSLSocketFactory sSLSocketFactory = null;
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, new TrustManager[]{new TrustAllManager()},
new SecureRandom());
sSLSocketFactory = sc.getSocketFactory();
} catch (Exception e) {
}
return sSLSocketFactory;
}
private static class TrustAllManager implements X509TrustManager {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] x509Certificates, String s) throws java.security.cert.CertificateException {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] x509Certificates, String s) throws java.security.cert.CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
通过SSL和https的介绍,使用这段代码违背了https不建议使用(公司和一个车机公司有合作,每次开机会重置时间导致接口无法使用,正在努力想其他方式解决)