1.Https相关知识
1.1 http与https的区别
HTTP协议传输的数据都是未加密的,也就是明文的,因此使用HTTP协议传输隐私信息非常不安全,为了保证这些隐私数据能加密传输,于是网景公司设计了SSL(Secure Sockets Layer)协议用于对HTTP协议传输的数据进行加密,从而就诞生了HTTPS。简单来说,HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全。
HTTPS和HTTP的区别主要如下:
- https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
- http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
- http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
- http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
1.2 Https的优点
- 认证用户和服务器,确保数据发送到正确的客户机和服务器;(验证证书)
- 加密数据以防止数据中途被窃取;(加密)
- 维护数据的完整性,确保数据在传输过程中不被改变。(摘要算法)
2.Okhttp中使用自签名证书
一般支持https的网站,都是CA(Certificate Authority)机构颁发的证书,但是一般该机构颁发的证书需要提供费用且有使用时间的限制,到期需要续费。否则默认该链接是不信任的,通过okHttp无法直接访问。
但是我们可以使用自签的方式,通过JDK自带的keytool.exe 生成一个自己的证书,然后使用该证书内容。虽然也是会出现提示“不安全”,但是我们可以通过okhttp访问链接。
2.1 使用自签证书
将证书文件放置在assets目录(也可以放置在其他目录下,只要能正确读取到该文件),在创建OkhttpClient对象时sslSocketFactory()将该证书信息添加。
private SSLContext getSLLContext() {
SSLContext sslContext = null;
try {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
InputStream certificate = mContext.getAssets().open("gdroot-g2.crt");
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
String certificateAlias = Integer.toString(0);
keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));
sslContext = SSLContext.getInstance("TLS");
final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
} catch (CertificateException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
return sslContext;
}
通过以上代码可以看出,通过InputStream方式读取证书信息,因此为了避免将证书文件打包到APK中,我们可以直接将证书文件内容放置在String中,将该字符串转为流的形式。
在使用okhttp时,将其设置到sslSocketFactory中。
OkHttpClient httpClient = new OkHttpClient().newBuilder()
.sslSocketFactory(getSLLContext().getSocketFactory())
.build();
2.2 信任所有证书
通过添加证书的形式,可以实现客户端访问Https服务端的功能,但是如果服务端更换证书内容,那么客户端需要相应的更换https证书,否则无法正常交互获取不到数据,我们可以通过自定义X509TrustManager的形式实现来规避所有的证书检测,实现信任所有证书的目的。
private OkHttpClient getHttpsClient() {
OkHttpClient.Builder okhttpClient = new OkHttpClient().newBuilder();
//信任所有服务器地址
okhttpClient.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslSession) {
//设置为true
return true;
}
});
//创建管理器
TrustManager[] trustAllCerts = new TrustManager[] { new 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 java.security.cert.X509Certificate[] {};
}
} };
try {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
//为OkHttpClient设置sslSocketFactory
okhttpClient.sslSocketFactory(sslContext.getSocketFactory());
} catch (Exception e) {
e.printStackTrace();
}
return okhttpClient.build();
}
创建X509TrustManager对象,并实现其中的方法,由于X509TrustManager是通用证书格式,只需要拿到该格式就行。最后init该安全协议,将其放入okhttp的sslSocketFactory中。
由于Retrofit只是对Okhttp网络接口的封装,因此实际使用中,该方法同样适用于Retrofit中。
欢迎关注晓涵说(CSDN)、xukang868(github)账号信息,查看更多文章。