http 协议 下的 TCP 三次握手
上面不需要多说,是未经过 ssl 协议加密情况下的三次握手过程。
简单朴素的加密通信过程
以上过程其实就是 https 想要实现的过程。在会话秘钥协商阶段,通过非对称加密算法,双方协商出此次会话的对称秘钥。确保双方都拥有同一个对称秘钥后,就可以进行安全通信了。
但是上面的过程有一个 bug,就是第二步客户端收到服务端的公钥时,怎么知道确实是服务端发过来的,而不是中间人发送过来的?攻击过程如下图所示:
如何防止这个中间人攻击
其实仔细观察上述攻击过程,可以发现,攻击能够成立的根本原因是 Client 端无法验证收到的公钥是 Server 端发送过来的合法公钥。要验证这个公钥的合法性也很简单,那就是引入可信第三方 CA。客户端收到公钥时,向 CA 求证,这个公钥确实是客户端希望通信的对端发送过来的。这个机制,就是证书链机制。在证书链机制下,我们上述的公钥就变成了证书。可以这样理解:证书就是带有可信第三方认证信息的公钥。
我们来看两个证书:简书的证书以及它的 CA 的证书(点击浏览器输入栏中的那个锁就可查看):
可以看到简书的证书链是这样的:DigiCert Global Root CA -> DigiCert SHA2 Secure Server CA -> *.jianshu.com。
-
证书链中每个证书是怎么生成的呢?每一层机构 A 自行生成自己的 公钥 - 私钥 对,然后将自己的公钥以及机构其他信息组成 InfoA 一起交给上层机构 Root 去认证。认证方式就是用 Root 的私钥去签名 InfoA 以及其他必要信息的 hash,生成签名信息 sign。然后填上证书中 Public Key(A 的公钥) ,Signature(上面生成的 sign),Issuer(Root 自己的信息),等。
-
因此,验证 简书证书 合法性的过程就变为了:客户端拿到简书证书
jianshuCertificate 后,取出其中的签发机构 issuer = jianshuCertificate.issuer,通过 issuer 找到本地保存的 issuer 证书 issuerCertificate,然后使用 issuerCertificate.PubKey 公钥解出 jianshuCertificate.signature,得到的值就是 hash1,然后计算 jianshuCertificate 的 hash2,比较 hash1 和 hash2,如果相同则认证通过。
上述过程只是大概流程如此,具体值可能不一样。比如 hash 具体是那些字段的哈希,可能与实际不一样(虽然我是信息安全方向,但是没有做过证书验证。。。)。
了解上述验签过程有利于理解实现 certificate pinning 的代码
https 的完整流程
理解了中间人攻击原理后,我们就可以理解 https 的完整流程,包括了了 TCP 3 次握手,TLS 5 次握手:
- Handshake 1: 通信双方确定使用的加密算法。客户端发送它所支持的算法列表,由服务器端确定使用哪种算法。
- Handshake 2: 服务器端发送证书列表到客户端,客户端验证服务器证书的合法性。
- Handshake 3: 服务器使用自己的私钥加密 DH 算法的服务端参数发送给客户端,客户端用服务器证书中的公钥解出 DH 算法参数。
- Handshake4: 客户端使用服务器证书中的公钥加密 DH 算法的客户端参数发送给服务器,服务器用自己的私钥解出 DH 算法参数。
- Handshake5: 服务器发送 session ticket 给客户端,用于下次 TLS 握手时更快的建立连接,类似 cookie。