# 加密的问题
## 对称加密
HTTP的通信是明文的, 任何一个人都可以监听上面的通信,截取里面的数据包。最容易想到的解决方法无非就是**加密。**
每次传输之前把消息用加密算法加密,服务器收到了以后再解密。
如下图所示
![image.png](http://upload-images.jianshu.io/upload_images/1323506-d83f7df38ce1b2cc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
这种**加密和解密用的是同一个密钥的算法称为对称加密算法**。那么实际上**加密和解密算法是公开的,密钥是保密的**
那么问题就来了,如果密钥在网络上发送的时候被截取了怎么办,也就是说密钥同样不能在网络上传输,但是加密双方都必须知道。
## 非对称加密
之前的算法需要协商一个保密的**密钥**,而这个密钥在网络上传输的时候存在被窃取的风险。然后出现了一个**RSA非对称加密算法。**
这个算法有一对密钥,一个是**私钥,**它是保密的,一个是**公钥**,是对外公开的。
那么用**私钥加密的数据,只能用对应的公钥来解密**
同样,用**公钥**加密的数据,只有对应的**私钥**才能解密。
于是浏览器给服务器发消息的时候,浏览器先使用**服务器的公钥**进行加密,然后服务器可以使用自己的**私钥**去解密。
反之亦然,服务器给浏览器发信息的时候,使用浏览器的**公钥**进行加密。
## 非对称加密 + 对称加密
使用非对称加密好是好,但是特别的慢。相对于非对称加密而言,对称加密会快很多。那么能不能折中一下呢?
我们知道之前用对称加密的时候,问题在于密钥无法安全传输。那么现在能不能**先对密钥使用非对称加密**,这样保证了密钥的安全传输。等到密钥被对方收到了以后,就使用**对称加密**,这样可以兼顾安全和性能呢。
# 身份认证的问题
上面说了,可以对密钥进行非对称加密,对报文进行对称加密,这样可以保证性能和安全性。但是新的问题来了,我们怎么保证对方的身份。也就是说如果服务器给浏览器发的**公钥**给中间人**截取了**,然后冒充服务器给浏览器发了一个公钥,这个时候,浏览器并不知道这一切,所以会使用中间人的公钥进行加密,中间人当然就可以解密到消息了。
这就如同古代的时候,新上任的县官被人半路上被绑匪给截了,然后绑匪拿着他的印信冒名顶替,下面的人并不知道此人并非真实县官,这样绑匪自然可以窃取各种机密。
所以**问题在于公钥是公开的,完全可以被冒名顶替**
## 公证处
所以问题根源在于,**如何证明这个公钥确实是服务器发出来的。**
这个问题在现实中就有,公证处就是这样的第三方的存在,他提供的资料受到大家的信任。所以我们也可以搞一个认证中心,给大家颁发一个**数字证书**,证明这个人的身份。同时证书里面一定有**这个人的公钥**。
但是证书依然有怎么安全传输,怎么避免被篡改的问题。我们可以使用HASH算法生成一个**消息摘要**,这就是**数字签名。**
HASH算法有个特性,**只要输入有变化,那生成的数字签名就会有巨大的变化**,这样就可以防篡改。
中间人说,虽然改不了**公钥**,但是可以替换整个原始的信息啊。就如果我们破解开机密码一样,不也是把原来加密以后的密码文件给替换了吗?
道高一尺,魔高一丈,我们再让公信处(CA)用**它的私钥对消息摘要**加密,形成签名。
**原始信息 + 数字签名** = **数字证书**
![image.png](http://upload-images.jianshu.io/upload_images/1323506-1de1bb7699767c0e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
这样有了第三方的证书,相当于有个参考。我们可以用**CA的公钥**对数字签名进行解密,以此为**基线**
当服务器把它的**证书**给我们的时候,我们可以使用相同的Hash算法生成消息摘要,然后与“基线”对比,就知道是否被篡改过了没。
![image.png](http://upload-images.jianshu.io/upload_images/1323506-289ca0646b585699.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
**总结一下**,因为公钥传输有可能被截取,所以我们希望有一个**第三方机构**能提供**基线**,我们只要对比**基线**就知道是否被人篡改过了。这样每个网站它的基线应该是不同的,所以可以使用HASH算法对网站的个人信息生成一个**消息摘要**。那么我们只需要核对从网站收到的**消息摘要**与第三方给的**消息摘要**是否是一样的就可以了。
好了,保证**基线**正确非常的关键,而第三方机构的证书同样存在没有加密的问题,容易被篡改的问题。
- 加密的问题:可以让第三方机构使用其私钥对**基线**加密,我们用其公钥解密即可。
- 容易被篡改的问题:无解,只能说对CA进行信用分级,在操作系统/浏览器内置一些顶层的CA证书,高层的CA给底层的CA做背书。
这样,网站在给我们发送**公钥**的时候,实际上是把**公钥**和**加密后的消息摘要**放到一起发过来的,我们
- 使用CA的**公钥**对加密后的**消息摘要**进行解密,得到**基线**
- 再对含有**公钥**的个人信息同样使用HASH算法也得到消息摘要
如果没有被篡改过,这两者应该是相等的
# 小结
我们可以对上面的过程进行简单的总结。
如果传输的信息没有加密,则信息容易在传输的过程中被窃取掉。那么我们可以使用同一个密钥对信息加密,但是在传输之前,必须把密钥在网络上传输一次,所以一样存在密钥被窃取的风险。
那么可以使用非对称加密算法,也就是发送方使用对方**公钥**进行加密,然后接收方使用自己的**私钥**进行解密。但是非对称加密算法需要消耗大量的资源,速度比较的慢。
那么可以中和一下。对于**公钥**我们使用**非对称加密**,对于要发送的信息使用**对称加密**,这里面存在的问题是如果我把**密钥**用另一个伪装的密钥进行全文替换,依然存在安全的风险。
那么可以加上一个**身份验证**的环节。
- 首先将**接收方**的公钥+个人信息进行Hash,得到一个消息摘要,这样如果传输过程中公钥被篡改,则**消息摘要**肯定会改变。
- 然后对消息摘要使用第三方证书中心的**私钥**进行加密,这样就可以保证消息摘要不会再传输过程中被篡改。
也就是说CA证书中心的私钥加密的是公钥+个人信息进行hash以后的消息摘要,得到数字签名。
这个数字签名里面包含了**公钥**的信息,而且被加密过了,不担心被人篡改,可以作为**基线**
![image.png](https://upload-images.jianshu.io/upload_images/1323506-37811ec702ed9b28.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- 那么如何进行**校验**呢?
发送方会把公钥信息+通过公钥等信息生成的数字签名一起发送过去。
接收方首先对数字签名进行解密,这样就可以获得消息摘要。
同样,再对公钥信息进行Hash,同样可以获得消息摘要。
这两者一核对,如果相同,则验证通过,不同,则出现了问题呗。
![image.png](https://upload-images.jianshu.io/upload_images/1323506-2e41fd5e351f2fac.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
也就是由一个第三方证书中心使用其**私钥**对接收方的**公钥**进行一次加密,也就是一个**基线**,
# HTTPS
![image.png](http://upload-images.jianshu.io/upload_images/1323506-94b719a51c27b504.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- 首先浏览器请求服务器的**公钥**
- 服务器返回一个含有公钥的**数字证书**,这个数字证书怎么得到的呢?由含有公钥的原始数据进行HASH以后,再使用CA私钥加密得到**数字签名**,再和原始数据一起组成了**数字证书**
- 浏览器通过数字证书,既验证了服务器的身份,又得到了**公钥**
- 使用公钥加密**对称加密**的密钥
- 使用对称加密进行通信
# 参考
[一个故事讲完https](https://mp.weixin.qq.com/s?__biz=MzAxOTc0NzExNg==&mid=2665513779&idx=1&sn=a1de58690ad4f95111e013254a026ca2&chksm=80d67b70b7a1f26697fa1626b3e9830dbdf4857d7a9528d22662f2e43af149265c4fd1b60024&scene=21#wechat_redirect)