# 【译】通过信鸽理解HTTPS交互原理

![carrier pigeon](https://1527815414-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-L_XyF-PcxCv1bX8ii73%2F-LbMptYIUaXNTU4oOoP1%2F-LbMpwPsZNa5pqOMPxkR%2Fhttps.png?alt=media\&token=c850400c-7018-46e7-8ab6-2ac4592db09a)

原文链接：<https://medium.freecodecamp.org/https-explained-with-carrier-pigeons-7029d2193351>

密码学本身确实是一个难懂的学科，因为它包含非常多的数学证明。但是如果我们不是为了开发一整套加密系统，我们可以忽略底层复杂的细节，从较高层面把里面涉及到的概念抽象出来加以理解学习。

#### Alice，Bob，Mallory 和信鸽

我们上网时做的一切事情几乎都会涉及到客户端和服务端的通信，比如阅读帖子，网上购物以及上传文件等等。比较常见的客户端就是浏览器了，浏览器和服务端通信过程非常简单：浏览器发送一个消息给服务端，服务端收到消息后给浏览器返回响应消息。

为了更好的学习HTTPS，我们把客户端和服务端的通信交给`信鸽`来完成，虽然有点随意，但是有利于我们更加容易的学习HTTPS工作原理。

同时，我们用密码学中的经典比喻来描述客户端和服务端的通信：

* `Alice`用来表示`客户端`；
* `Bob`用来表示`服务端`；
* `Mallory`用来表示图谋不轨的`消息拦截者`。

相信学过密码学的人肯定非常熟悉这三个名字。

#### “白莲花”式的通信

我们从最简单的通信方式着手，假设Alice想要给Bob发送信息，Alice将信息绑在信鸽腿上然后发给Bob，Bob收到信鸽后读取Alice发送过来的信息。

这看起来很美好，但是假如Mallory中途拦截了Alice的信鸽并且篡改了Alice的消息内容，这种情况下Bob并无法知晓消息已被篡改。

单纯的HTTP其实就是这样工作的。是不是很恐怖，你敢把自己的银行账号密码通过这种方式传输么？反正我是不敢。

#### 对称密钥加密算法 - 凯撒密码

现在假设Alice和Bob非常机灵，他们决定在互相发送消息的时候将信息进行编码，那怎么编码呢？他们决定采用一种非常古老、简单的加密算法：`凯撒密码`。非常简单，将字母表中的字母左移三个位置即可。例如，D->A，E->B，F->C。文本信息“secret message”编码结果为“pbzobq jbppxdb”。

如果Mallory中途即便截获了信息，由于不知道编码加密规则，她无法理解信息，也无法篡改生成有意义的伪造信息。但是收到信息后Bob可以基于一下规则解码得到原始信息：A->D，B->E，C->F。加密信息“pbzobq jbppxdb”的解码结果为“secret message”。

上面用到的凯撒密码非常简单，真实场景会用到更加复杂的编码方式。如果你知晓如何进行编码加密，你当然也知道如何进行解密，因此这种加密方式称为`对称密钥加密`。

#### 如何选取安全密钥

在前面的凯撒密码中，我们可以把密钥理解为`移动3位`。Alice和Bob能使用该密钥进行安全通信有个前提条件，就是他们必须提前商定好使用该种密钥进行加密，但是如果Alice和Bob从来没有碰过面，他们如何约定安全的密钥？这在网络互联的场景中再正常不过了。

你可能会想到Alice先把密钥发送给Bob，但是这次信息传递也可能会被中间人Mallory截获，进而破解并篡改后面的消息传递。这就是典型的`中间人攻击`，要想避免这种中间人攻击，只能选取一套全新的加密系统：非对称密钥加密算法。

#### 非对称密钥加密算法 - 将信鸽传递的信息装箱子

为了破解中间人攻击，Alice和Bob想出了一套更好的系统。当Alice给Bob发送信息时按照如下流程发送消息：

* Alice给Bob发一只不带任何信息的信鸽；
* Bob给Alice回发的信鸽携带一只带锁的箱子，注意锁要处于打开状态，钥匙Bob要保留好；
* Alice收到带箱子的信鸽后，将信息放入箱子中，将锁锁好，然后再发回给Bob；
* Bob收到锁住的箱子后用保存好的钥匙打开箱子即可读到Alice发过来的原始信息。

这种方式下，即便Mallory截获了信鸽由于没有钥匙也无法打开箱子读取原始信息。当Bob想要发送信息给Alice时也采用相同的步骤即可。

Alice和Bob刚刚用的这套新的加密方式称为`非对称密钥加密`，之所以是`非对称`，是因为即便一方知道怎么加密信息（锁箱），他也无法解密（开锁）。技术实现上一般将`带锁的箱子`称为`公钥`，将`开锁的钥匙`称为`私钥`，具体实现比如有`RSA加密算法`等。

#### 数字签名 - 如何判断箱子的可靠性

如果你仔细揣摩会发现前面的这个系统还是有问题。当Bob收到箱子后他怎么判断这个箱子确实是Alice发过来的，而不是被Mallory截获并且换过箱子的？

为了让Bob确认箱子是Alice自己发送的，Alice决定在箱子上面签名盖章，这时Bob收到箱子后如果看到Alice的签名则确认没有被截获并篡改。

然后你可能又会问了，Bob怎么判断Alice的签名盖章不是伪造的？因此Alice和Bob一致同意，发送方本身不再在箱子上签名，而是交给具有公信力的第三方`Ted`来负责签名盖章。

这里的Ted就是大家经常听说的`HTTPS证书颁发机构`，比如DigiCert、Symantec等。

#### 数字签名可靠性校验

那么如何理解数字证书、签名、公钥以及私钥这几者的关系呢？其实很简单，证书颁发机构颁发的证书包含公钥、签名以及其他信息，私钥由证书申请者自己保存。

那么客户端（比如浏览器）如何验证证书的可靠性？具体验证过程如下。比如服务端发送给客户端的证书声称该证书由Symantec颁发，还附带了签名。事实上，Symantec生成证书签名的时候会使用他们的`签名算法私钥`来生成签名，而客户端一般会内置这些权威机构的`签名算法公钥`，因此拿到服务端发送过来的证书时可以根据`签名算法公钥`来判断签名的可靠性。

当然了，证书颁发机构也不会随随便便的给一个申请者颁发证书，而是会经过线上、线下各种认证之后才会颁发，因此客户端和服务端通信双方才会通过这个可靠的第三方建立安全通信机制。

这里有一点需要注意，前面介绍过的`非对称加密算法`虽然也有私钥和公钥，但是不要和这里的`数字签名算法`弄混，这是两套不同的算法，用途完全不一样，前者是为了实现加密，后者是为了验证签名可靠性。感兴趣的可以去搜索对比`RSA加密算法`和`RSA签名算法`。

#### 非对称加密+对称加密 - 双剑合璧

Alice和Bob现在可以进行安全可靠的通信了，但是他们觉得每次通信都要带个箱子显然效率太低了。

因此他们决定非对称加密与对称加密双剑合璧，使用非对称加密算法传递用于对称加密算法的密钥，然后使用对称加密算法进行信息传递。这样既安全又高效。
