导读
Https协议其实就是在原先的Http应用层协议上面加了一套TLS/SSL协议,也就是在Http协议上了加了一套加密的模块。
服务器和客户端的信息都会通过TLS来进行加密,传输的数据都是加密的数据,具体是怎么加密,解密和验证服务器的
是在几次握手之后来确定的。
几次握手的示意图
握手详情
- 1.第一次客户端发送一个url发送到服务器端,这里面包含客户端能支持的加密算法。
- 2.服务器拿到客户端发过来的信息,是否匹配客户端支持的加密的算法,如果不支持则直接失败。服务器会自己的一套公钥,私钥,证书,公钥是用来加密的,私钥是用来解密的。证书可以自己生成也可以向可信机构申请(自己申请的会弹出弹框需要用户进行信任)。服务器传给客户端的信息包括一套HASH算法,公钥,证书颁发机构,证书过期时间等信息。
- 3.客户端接受到证书之后,会判断证书是否过期,是否可信。如果都可以的话,客户端会生成一个随机值,其实也就是加密算法的一个规则。客户端会根据预定的hash算法对要传送的握手信息取Hash值。然后把握手消息和握手消息的hash值通过随机数进行加密。然后把随机值通过公钥加密和对称加密后的握手信息发给服务器。
- 4.服务器接受到公钥加密的信息和对称加密的握手信息之后,服务器先用私钥解析拿到传输的随机数和握手信息。解密之后在对握手信息和随机数取的hash值,然后判断和客户端传来是是否一致。然后在用随机密码和握手信息生成hash值发给客户端。
5.客户端对称解密,拿到信息,再次生成hash值,然与服务器做对比,如果一致,则握手结束,以后都使用对称加密来传递数据。
取Hash值的目的就是为了验证在数据传递的路途中是否被人篡改过。
6.这时间客户端和服务端就可以通过对称加密来进行数据传递了,因为只有他们知道是如何进行对称加密的,并且加密的钥匙传递的时候也是安全的。所以即使拿到加密的信息也是无法看的懂得。
握手过程中如果有任何错误,都会使加密连接断开,从而阻止了隐私信息的传输。
Android 端如何使用Https
这里网上找的洪洋大神的blog。
Android Https相关完全解析 当OkHttp遇到Https。
通过这里了解到,在Android当中默认的是支持Https的,但是支持的都是CA机构颁发的证书,如果是自己生成的正式的话,那么就在访问的时候会出错。自签名的正式是不被信任的,就像访问12306一样说是不安全的,这时间我们Android这边需要做的就是和网页一样,高级设置继续前往即可(就是让客户端信任服务器的证书。)
* OkHttp的做法:
1.首先把我们下载的srca.cer放到assets文件夹下,其实你可以随便放哪,反正能读取到就行。
2.需要用代码进行设置信任此证书。
public void setCertificates(InputStream... certificates)
{
try
{
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
int index = 0;
for (InputStream certificate : certificates)
{
String certificateAlias = Integer.toString(index++);
keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));
try
{
if (certificate != null)
certificate.close();
} catch (IOException e)
{
}
}
SSLContext sslContext = SSLContext.getInstance("TLS");
TrustManagerFactory trustManagerFactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
sslContext.init
(
null,
trustManagerFactory.getTrustManagers(),
new SecureRandom()
);
mOkHttpClient.setSslSocketFactory(sslContext.getSocketFactory());
} catch (Exception e)
{
e.printStackTrace();
}
}
由于本人的公司也是很穷,某宝买的证书,学习过之后才是也是自签名的,不被客户端信任,所以客户端也需要配置,自家网络请求是老大封装好的HttpUrlConnection,配置如下:
private String doPostNoFile() throws MalformedURLException, IOException, ProtocolException, UnsupportedEncodingException, FileNotFoundException, CertificateException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException { String result = null; URL url1 = new URL(this.url); if(this.urlRequestType == 0) { this.conn = (HttpURLConnection)url1.openConnection(); this.initConn(this.conn); this.conn.setRequestMethod("POST"); this.conn.setRequestProperty("Content-Type", this.DEFAULT_FROM_DATA); this.out = this.conn.getOutputStream(); } else { CertificateFactory buf = CertificateFactory.getInstance("X.509"); InputStream line = this.context.getAssets().open("ssl-bundle.crt"); Certificate buffer = buf.generateCertificate(line); KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType()); keystore.load((InputStream)null, (char[])null); keystore.setCertificateEntry("ca", buffer); String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm); tmf.init(keystore); SSLContext context = SSLContext.getInstance("TLS"); context.init((KeyManager[])null, tmf.getTrustManagers(), (SecureRandom)null); this.urlConnection = (HttpsURLConnection)url1.openConnection(); this.urlConnection.setSSLSocketFactory(context.getSocketFactory()); this.initConn(this.urlConnection); this.urlConnection.setRequestMethod("POST"); this.urlConnection.setRequestProperty("Content-Type", this.DEFAULT_FROM_DATA); this.out = this.urlConnection.getOutputStream(); } } }
总结:
通过以上学习,理解了Https的原理,也明白了客户端这边改如何去处理自信任证书。