参考:
https://segmentfault.com/a/1190000009002353?sort=newest
https://zhuanlan.zhihu.com/p/353571366
HTTPS=HTTP+TLS,其它的协议也类似,如FTPS=FTP+TLS

1) ClientHello
2)Server Hello
3)证书校验
Client端和Server端,最终都会用相同的算法将pre-master secret(预主密钥)转换成master secret(主密钥),通过主密钥可以生成session key。两者后续的通信交互数据,将通过session key进行加密。

参考:https://www.laoqingcai.com/tls1.2-premasterkey/
4)Client 握手结束通知
5)Server 握手结束通知
6)Client 开始HTTPS通讯
两者后续的通信交互数据,将通过session key进行加密。所以中间人即使截获数据,也无法解析。
证书=服务器公钥+(服务器公钥+服务器信息)的签名
签名=摘要+私钥加密
CA:Certificate Authority,专门用自己的私钥 给别人进行签名的机构
关键过程:用信任CA库里CA证书(公钥),验证网站的证书文件里的签名
参考:
https://shunix.com/ssl-pinning/
https://zhuanlan.zhihu.com/p/58204817
SSL Pinning可以分为Certificate Pinning(证书锁定)和Public Key Pinning(公钥锁定)
把证书文件打包进安装包,将app设置为仅接受指定的内置证书,而不接受操作系统内置的CA根证书对应的任何证书。
提取证书中的公钥并内置到App中,通过与服务器对比公钥值,来验证连接的合法性。我们在申请证书时,公钥在证书的续期前后可以保持不变,所以可以解决证书有效期问题。
// kotlin语法
// 加载证书文件
val cf: CertificateFactory = CertificateFactory.getInstance("X.509")
val caInput: InputStream = BufferedInputStream(FileInputStream("load-der.crt"))
// 使用CertificateFactory生成一个X509Certificate的实例
val ca: X509Certificate = caInput.use {
cf.generateCertificate(it) as X509Certificate
}
System.out.println("ca=" + ca.subjectDN)
// 创建一个KeyStore实例,并把前边的X509Certificate实例加进去,并起一个别名"ca"
val keyStoreType = KeyStore.getDefaultType()
val keyStore = KeyStore.getInstance(keyStoreType).apply {
load(null, null)
setCertificateEntry("ca", ca)
}
// 创建一个TrustManagerFactory实例,并且使用前边的KeyStore实例进行初始化
val tmfAlgorithm: String = TrustManagerFactory.getDefaultAlgorithm()
val tmf: TrustManagerFactory = TrustManagerFactory.getInstance(tmfAlgorithm).apply {
init(keyStore)
}
// 创建一个SSLContext实例,并且使用前面的TrustManagerFactory实例的trustManagers进行初始化
val context: SSLContext = SSLContext.getInstance("TLS").apply {
init(null, tmf.trustManagers, null)
}
// 创建HttpsURLConnection实例urlConnection
val url = URL("https://certs.cac.washington.edu/CAtest/")
val urlConnection = url.openConnection() as HttpsURLConnection
// 将SSLContext实例context的socketFactory属性,赋值给urlConnection
urlConnection.sslSocketFactory = context.socketFactory
val inputStream: InputStream = urlConnection.inputStream
copyInputStreamToOutputStream(inputStream, System.out)
需要在Manifest文件的android:networkSecurityConfig属性加上对应的配置内容,示例如下:
<network-security-config>
<domain-config>
<domain includeSubdomains="true">example.comdomain>
<trust-anchors>
<certificates src="@raw/my_ca"/>
trust-anchors>
domain-config>
<domain-config>
<domain includeSubdomains="true">example.comdomain>
<pin-set expiration="2018-01-01">
<pin digest="SHA-256">7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=pin>
<pin digest="SHA-256">fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE=pin>
pin-set>
domain-config>
network-security-config>