近来项目中使用了https,然后发现对此不是十分了解,借此简单梳理一下。
https原理
https简介
HTTP 协议(HyperText Transfer Protocol,超文本传输协议):是客户端浏览器或其他程序与Web服务器之间的应用层通信协议 。
HTTPS 协议(HyperText Transfer Protocol over Secure Socket Layer):可以理解为 HTTP+SSL/TLS, 即 HTTP 下加入 SSL 层,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL,用于安全的 HTTP 数据传输。
原先的http协议使用的是明文传输,第三方可能会窃听、篡改、冒充。SSL/TLS协议就像是一道保护层,它的加入保证了:
- 所有信息都是加密传播,第三方无法窃听。
- 具有校验机制,一旦被篡改,通信双方会立刻发现。
- 配备身份证书,防止身份被冒充。https原理1.客户端发出请求客户端想服务器发起请求,发送:
- 协议版本号,比如TLS 1.0版
- 生成随机数C1
- 客户端支持的加密方式
- 支持的压缩方法2.服务器回应服务器接收到请求,确认相关信息并作回应:
- 确认协议达成一致,否则关闭连接
- 生成随机数S1
- 选择一种加密方式,例如RSA公钥加密
- 服务器证书3.客户端验证客户端收到回应后,对服务器证书进行认证:
- 是否是可信机构颁布
- 证书中的域名与实际域名不一致
- 证书有效期
 验证通过后,取出证书中的公钥。4.客户端回应生成随机数C2,并使用证书公钥非对称加密C2生成P,回应给服务器。客户端现在拥有随机数C1+C2+S1和约定的加密算法,生成”对话密钥”K。5.服务器回应服务器接收到P,使用服务器证书私钥解密P得到随机数C2。服务器端也拥有了随机数C1+C2+S1和约定的加密算法,生成”对话密钥”K。然后之后客户端与服务器端的通信都使用K加密内容。
  
Android踩坑
在客户端交互的时候会涉及证书一说,一种是自己签发的证书,一种是第三方机构认证的证书。详细可查看这个。然而Android对此就会有以下两种情况。
自签证书
信任所有证书
对于任意的证书都可信任,简单,但有一定安全局限。
以OkHttp为例,所有重写方法不做任何的检验和校对。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | static {
 internalHttpClientWithLongTimeout = new OkHttpClient.Builder()
 .connectTimeout(30, TimeUnit.SECONDS)
 .writeTimeout(30, TimeUnit.SECONDS)
 .readTimeout(30, TimeUnit.SECONDS)
 .sslSocketFactory(SSLSocketClient.getSSLSocketFactory())
 .hostnameVerifier(SSLSocketClient.getHostnameVerifier())
 .proxy(Proxy.NO_PROXY)
 .build();
 }
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 
 | public class SSLSocketClient {
 
 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);
 }
 }
 
 
 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;
 }
 
 
 public static HostnameVerifier getHostnameVerifier() {
 HostnameVerifier hostnameVerifier = new HostnameVerifier() {
 @Override
 public boolean verify(String s, SSLSession sslSession) {
 return true;
 }
 };
 return hostnameVerifier;
 }
 }
 
 | 
只信任唯一证书
将证书文件srca.cer 文件,复制到 Android 项目的 resource/raw/中。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 
 |  private void customTrust() {X509TrustManager trustManager;
 SSLSocketFactory sslSocketFactory;
 
 InputStream cerIn = getResources().openRawResource(R.raw.srca);
 try {
 
 trustManager = trustManagerForCertificates(cerIn);
 SSLContext sslContext = SSLContext.getInstance("TLS");
 sslContext.init(null, new TrustManager[]{trustManager}, null);
 sslSocketFactory = sslContext.getSocketFactory();
 } catch (GeneralSecurityException e) {
 throw new RuntimeException(e);
 }
 
 mOkHttpClient = new OkHttpClient.Builder()
 .sslSocketFactory(sslSocketFactory, trustManager)
 .build();
 }
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 
 | public static X509TrustManager trustManagerForCertificates(InputStream in) throws GeneralSecurityException {
 
 
 
 CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
 
 Collection<? extends Certificate> certificates = certificateFactory.generateCertificates(in);
 if (certificates.isEmpty()) {
 throw new IllegalArgumentException("expected non-empty set of trusted certificates");
 }
 
 
 char[] password = "password".toCharArray();
 KeyStore keyStore = newEmptyKeyStore(password);
 int index = 0;
 for (Certificate certificate : certificates) {
 String certificateAlias = Integer.toString(index++);
 keyStore.setCertificateEntry(certificateAlias, certificate);
 }
 
 
 KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(
 KeyManagerFactory.getDefaultAlgorithm());
 keyManagerFactory.init(keyStore, password);
 TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
 TrustManagerFactory.getDefaultAlgorithm());
 trustManagerFactory.init(keyStore);
 TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
 if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
 throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers));
 }
 return (X509TrustManager) trustManagers[0];
 }
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | private static KeyStore newEmptyKeyStore(char[] password) throws GeneralSecurityException {try {
 KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
 InputStream in = null;
 
 
 keyStore.load(in, password);
 return keyStore;
 } catch (IOException e) {
 throw new AssertionError(e);
 }
 }
 
 | 
数字证书签发机构(CA)颁发的证书
如果是这种情况,且该权威CA内置于系统内部,那么代码无需做任何处理。
参考引用
https://www.zhihu.com/question/33645891
http://pingguohe.net/2016/02/26/Android-App-secure-ssl.html
https://jaq.alibaba.com/community/art/show?articleid=545
https://yq.aliyun.com/articles/109939