# HTTPs 小故事

# HTTPS

HTTP 可以进行网络通信，既然有了 HTTP 又为什么需要 HTTPS 呢？

HTTPS 的全称是 Hypertext Transfer Protocol over **S**ecure **S**ocket **L**ayer，是以安全为目标的HTTP通道。通俗来讲 HTTPS 并不是一个新的协议，而是在原来的 HTTP 协议上进行了数据加密，HTTP 为什么需要加密呢？可以看下面的几个小故事来方便理解。

## 明文通信

假定客户端叫做夏洛，服务器叫做马冬梅，夏洛和马冬梅距离非常远，需要通过邮件来通信。

如果夏洛想要约马冬梅周六去看海，他就会写一封信，信里约定了时间地点，把信装到信封里给邮差，然后邮差把信送给马冬梅，马冬梅收到了信写一封回信给夏洛答应周末去看海，到了周末他们就在约定的地点碰头，非常完美。

但这个邮差不是普通的邮差，这个邮差叫袁华，他也偷偷喜欢马冬梅，每个经过他送给马冬梅的信他都会拆开看一下。看到这封约会的信他害怕马冬梅会答应，于是他偷偷改了信里的约会地点，把去看海改成了去爬山。然后马冬梅的回信被他改成了拒绝。这样到了周六，夏洛因为被拒绝了没有去，而马冬梅去山脚下等了一天没有等到人，最后非常的生气。

这就是 HTTP 的工作流程，整个传输过程都是明文传输，任何经手的人都可以任意篡改网站的内容。

## 对称加密

假如马冬梅非常生气，直接去找了夏洛，俩人一沟通，就会发现有人篡改了信的内容。但是除了通过邮差通信没有其他办法远距离沟通，那怎么办呢？

夏洛非常机智，他说可以使用带锁的盒子来放信件，两人各一个盒子和一把钥匙，写好的信放到盒子里锁住再给邮差，对方拿到盒子后用钥匙打开盒子才能看到信。这样邮差没有钥匙，就无法看到信和里面的内容了。

上面这种方法就是`对称加密`，对称加密是使用同一个秘钥进行加密和解密。如果除了发信人和收信人外没有人知道秘钥，那么通信就是安全的。例如将一段文本中的每个字母按照字母表中的顺序前移三位。比如，D→A，E→B，F→C。如此一来，原文为 `secret message` 的信息就变成了 `pbzobq jbppxdb`，没有密码没法理解其中的内容，而如果随意篡改了内容，则解密后的内容是乱码无法阅读，也会知道内容被篡改了。

夏洛和马冬梅直接的通信问题解决了，后面他们结婚，住到了一起，开了一家乡村银行。由于地广人稀，存钱取钱还是要通过邮差，但是经常会发现数目不对的情况，赔了不少钱。

于是夏洛使用对称加密的方法，他造出来了很多盒子，每个盒子都有两把钥匙，如果一个叫大春的人想要存钱，就按照如下步骤进行：

1. 大春找到夏洛，说想要在他的银行存款；

2. 夏洛给了大春一个盒子和配套的一把钥匙，另一把钥匙自己保管；

3. 如果大春在外地想要取钱的话就把取多少钱的信放到盒子里并锁着，通过邮差寄给夏洛；

4. 夏洛收到盒子用钥匙打开，读了信后，把响应的钱放进盒子里并锁住，过邮差寄会给大春；

5. 大春收到盒子用钥匙打开，拿到了钱；

## 非对称加密

上面的方式发现了一个问题。这种通信方式需要大春先去夏洛那里拿到盒子和钥匙，而如果不方便到夏洛那里去就没办法拿到盒子和钥匙。如果通过邮差来传递的话，那么邮差就可以给大春假的盒子和钥匙，从而在邮寄途中偷偷把钱拿走。

经过冥思苦想，夏洛想出来一个更好的方式。于是大春存取款都按照新的步骤进行：

1. 大春先经过邮差寄给夏洛发一个要存钱的信；

2. 夏洛把一个盒子（没有钥匙，锁开着）通过邮差寄给大春；

3. 大春把钱放到盒子里，然后用锁锁住寄给夏洛；

4. 夏洛收到盒子后用钥匙打开盒子，把钱拿出来放到金库里；


这样夏洛只需要一个盒子和一把钥匙就可以了，钥匙自己保管不需要给大春，邮差没有钥匙也打不开盒子没法拿到盒子里的钱。

这就是非对称加密。非对称加密是一种使用不同秘钥进行加密和解密的加密算法，非对称加密有两个秘钥——公开秘钥和私有秘钥（下文简称公钥和私钥），公钥用来加密，私钥用来解密，以公钥加密的内容只能使用私钥解密。这样的话，私钥只会让自己知道，公钥的话可以让任何人知道，保证了安全。

## 认证加密

刚开始运行良好，没有什么问题，好景不长，过了一段时间又发现数目不对的情况了。经过调查发现邮局有人仿造了夏洛的盒子。在夏洛把盒子给大春的过程中，截留了夏洛的盒子，把仿造的盒子给了大春，然后拿到大春寄回来的盒子后，用仿造盒子的钥匙把盒子打开，把钱截留了一部分，把剩下的钱放到真正的盒子里给夏洛。这样两边都没法发现钱少了，只有最后取钱发现钱不够了时才会出现问题。

夏洛没有办法，求助警局，警局给夏洛的盒子加了个无法仿造的警徽标记，只要拿着盒子到当地的警局就能确认这个盒子是不是真的，这样邮局就没办法自己仿造盒子了，从而保障了整个交易过程。

这里警局在术语中就被成为 `签证机构 Catificate Authority`，简称 `CA`。盒子就是公钥，钥匙就是私钥。关于 `CA` 相关的内容后面再单独写一篇文章来讲。

# HTTPS 认证过程

下面来说一下实际 HTTPS 的认证过程(TLS 1.3)<sup>[3][4][5][6][7][8]</sup>：

1. TCP 三次握手建立会话，这里就不进行解释了。

2. 客户端发送Client Hello，给出以下内容：
  1. TLS协议版本信息（Client Version）；
  2. 客户端生成的随机数（Client Random）；
  3. 客户端支持的加密算法列表（Cipher Suites）；
  4. 客户端支持的压缩算法列表（Compression Methods）；
  5. 其他扩展字段（Extensions）<sup>[6]</sup>。

3. 服务器收到客户端的Client Hello后，发送Server Hello，确认协商的信息结果：
  1. 确定协商使用的TLS版本号`TLS 1.0`/`TLS 1.1`/`TLS 1.2`/`TLS 1.3`（Server Version）；
  2. 服务器生成的随机数（Server Random）；
  3. 服务器选择的最终的加密算法（Cipher Suite）；
  4. 服务器选择的最终的压缩算法（Compression Method）；
  5. 其他扩展字段（Extensions）<sup>[6]</sup>。

4. 服务器给出终端数字证书（证书中包含Host、公钥和CA签名）。

5. 服务器发送Server Key Exchange，对于使用DHE/ECDHE非对称密钥协商算法的SSL握手，将发送该类型握手。RSA算法不会进行该握手流程（DH、ECDH也不会发送server key exchange），也就是说此报文不一定要发送，视加密算法而定<sup>[9]</sup>。

6. 服务器发送Server Hello Done，通知客户端 Server Hello 信息发送结束。

7. 客户端通过CA验证数字证书签名的合法性后，生成一个新的随机数，并使用服务器给出的终端数字证书中的公钥，加密这个随机数，发给服务器。

8. 服务器使用自己的私钥，获取客户端发来的随机数（即Premaster secret）。

9. 服务器和客户端根据约定的加密方法，使用前面的三个随机数，协商生成"对话密钥"（Session Key）。

10. 服务器发送New Session Ticket，用处就是在一段时间之内（超时时间到来之前），双方都以协商的密钥进行通信。

11. 接下来用"对话密钥"（Session Key）来进行对称加密传输会话内容。

12. 完成数据发送，TCP 4次挥手结束会话。

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1651337042454/9dM-Fw8cI.png align="left")


# 参考

1. [深入浅出 HTTPS](https://www.jianshu.com/p/ee3559af04be)
2. [分分钟让你理解HTTPS](https://juejin.cn/post/6844903599303032845)
3. [图解SSL/TLS协议](https://www.ruanyifeng.com/blog/2014/09/illustration-ssl.html)
4. [刨根问底系列之https详细握手过程](https://juejin.cn/post/6847902219745181709)
5. [TLS Handshake](https://wiki.osdev.org/TLS_Handshake)
6. [The Illustrated TLS 1.3 Connection](https://tls13.ulfheim.net/)
7. [The First Few Milliseconds of an HTTPS Connection](http://www.moserware.com/2009/06/first-few-milliseconds-of-https.html#client-hello)
8. [TLS 协议详解](https://wonderful.blog.csdn.net/category_7152768.html)
9. [TLS/SSL 协议详解(12) server key exchange](https://wonderful.blog.csdn.net/article/details/77867831)


















