Android之网络—第二篇(Https原理)

2019-05-11  本文已影响0人  Bzaigege
前言:这篇网络系列的初衷是分享下网络相关的知识,文章属于个人的学习总结博客。部分内容来源网络,如有不适,请私聊。

Android之网络—第一篇(Http原理)
Android之网络—第二篇(Https原理)
Android之网络—第三篇(解读OkHttp)
Android之网络—第四篇(解读Retrofit)

什么是Https:

说的通俗一点就是身披安全衣的Http,本质还是http,只是在http外层嵌套了一个SSL/TLS的安全层,该层做了一些数据的加解密处理。

在讲解Https原理之前,先做点准备工作,因为会涉及到SSL/TLS连接建立、SSL/TLS加解密方面的知识。所以会整体从网络架构和比较重要的知识点回顾下网络知识。

TCP/IP协议

在讲解什么是SSL/TLS之前,回顾下TCP/IP协议的分层概念。通常一个网络的传输中间会经过很多的传输节点,才最终达到服务器。期间过程会包含数据的拆分和拼装、IP的解析、数据的传输等等操作,但是网络传输是很不稳定的,如果这次网络请求在中间的某一节点失败了,难道还要重新再发送一遍么?答案是不应该这么做。

image.png

为了网络传输的统一规范,就设计了这么一套网络通信的规范,每一层都专注做一件事情,即使当前失败了,也在这层做处理就可以了,尽量避免重发。


image.png

简单解释下,每层的含义:

通过上图发现,数据是由上往下传递后,再由下往回传递。这是怎么回事呢?总结就是:在 TCP / IP 协议中数据先由上往下将数据装包,然后由下往上拆包。在装包的时候,每一层都会增加一些信息用于传输,这部分信息就叫报头,当上层的数据到达本层的时候,会将数据加上本层的报头打包在一起,继续往下传递。在拆包的时候,每一层将本层需要的报头读取后,就将剩下的数据往上传。


image.png

简要分析下传输过程:

\color{red}{而Https就是在应用层和传输层之间加一个SSL/TLS的数据加解密层。}

TCP的三次握手和四次挥手

这里简单总结下传输层的两种连接方式:TCP和UDP

三次握手:客户端主动打开连接,服务器被动打开连接。

为什么3次握手:
  • 前两次的握手很显然是必须的,主要是最后一次,即客户端收到服务端发来的确认后为什么还要想服务端再发送一次确认呢?\color{red}{这主要是为了防止已失效的请求报文段突然又传送到了服务端而产生连接的误判。}

  • 考虑如下的情况:客户端发送了一个连接请求报文段到服务端,但是在某些网络节点上长时间滞留了,而后客户端又超时重发了一个连接请求报文段该服务端,而后正常建立连接,数据传输完毕,并释放了连接。如果这时候第一次发送的请求报文段延迟了一段时间后,又到了服务端,很显然,这本是一个早已失效的报文段,但是服务端收到后会误以为客户端又发出了一次连接请求,于是向客户端发出确认报文段,并同意建立连接。但是客户端认为之前的连接已经失效了,不会给服务器发送任何数据,服务端就会一直等待下去,直到超出保活计数器的设定值,而将客户端判定为出了问题,才会关闭这个连接。这样就浪费了很多服务器的资源。

  • 如果采用的是三次握手,就算是那一次失效的报文传送过来了,服务端接受到了那条失效报文并且回复了确认报文,但是客户端不会再次发出确认。由于服务器收不到确认,就知道客户端并没有请求连接。

四次挥手:客户端主动关闭,服务器被动关闭

为什么客户端最后还要等待2MSL:
  • 第一,保证客户端发送的最后一个ACK报文能够到达服务器,因为这个ACK报文可能丢失,站在服务器的角度看来,我已经发送了FIN+ACK报文请求断开了,客户端还没有给我回应,应该是我发送的请求断开报文它没有收到,于是服务器又会重新发送一次,而客户端就能在这个2MSL时间段内收到这个重传的报文,接着给出回应报文,并且会重启2MSL计时器。

  • 第二,防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样使下一个新的连接中不会出现旧连接的请求报文。

名词解释:

现代密码学

说个概念性的东西就是,现代密码学分为对称加密和非对称加密,跟传统密码学不一样的地方就是,除了可以加密文字内容外,还可以用于各种二进制数据的加解密。

对称加密:

通信双方使用同一个密钥,使用加密算法配合上密钥来加密,解密时使用解密算法(加密过程的完全逆运算)配合密钥来进行解密。常用的经典算法:DES(56 位密钥,密钥太短而逐渐被弃用)、AES(128 位、192 位、256 位密钥,现在最流行)。


image.png
非对称加密:

通信双方使用公钥和加密算法对数据进行加密得到密文;使用私钥和加密算法对数据进行解密得到原数据。常用的经典算法:RSA(可用于加密和签名)、DSA(仅用于签名,但速度更快)。


image.png

这个有什么用?其实这个就是后面Https加解密的原理。原理这么简单么?是的,就这么简单。但是要理解还得慢慢往下看。

暴力破解法(穷举法):对于对称加密而言,我只要拿到密钥就可以破解了。同样的,非对称加密只要拿到私钥也就搞定了。所以只要拿一堆密码一个个的试,在最短的时间内找到对应的密钥/私钥就搞定了。

而反破解,或者对一个优秀加密算法的定义标准是,让破解者找不到比穷举法(暴力力破解法)更有效的破解手段,并且穷举法的破解时间足够长(例如数千年)

  • 对称加密:不能在不安全网络上传输密钥,一旦密钥泄露则加密通信失败。
    正常的网络传输是要经过很多个节点的,为了保证通信的双方正常通信,都必须要求知道密钥,但是密钥如果在网络传输中就很容易被劫持。有泄漏的风险。如下场景:在网络传输的过程中在某个节点被C劫持,C就可以解密你传输的内容啦。


    image.png
  • 非对称加密:可以在不安全网络上传输密钥(准确来说是公钥),但是计算复杂,因此性能比对称加密差很多。
    在正常的网络上通信,为保证正常通信,通信的双方都需要持有对方的公钥将数据加密后发送给对方,接收方再将加密的数据通过自己的私钥解密出来。这样即使在传输的某个节点被C劫持了,C也解密不了你的数据,因为数据只能用私钥来解。

    image.png
    \color{red}{但是,这里会有个问题,C解不了数据,但是可以改数据呀。可以冒充给你传输假数据啊。咋办?}

根据上面的场景,A用B的公钥加密的数据发送给B,B用私钥可以解。反过来?B用私钥加密的数据发送给A,A用B的公钥能不能解?答案是可以的。下面举个不规范的例子说明下:

有个数字库:0123456789包含十个数字,加密算法都定义为:两数相加,满十时取个位。

正常逻辑:A 有原数据为110,使用B的公钥4和加法算法后的密文为554;然后B用自己的私钥6和加密算法解密后的数据为110.


image.png

反向逻辑:B有原数据110,使用自己的私钥和加密算法加密后的密文为776;然后A用B的公钥4和加密算法解密后的数据同样为110.


image.png

结论就是:公钥加密的数据用私钥可以解,私钥加密的数据,用公钥也可以解。但是要注意的是,公钥和私钥是不能对调的。

\color{red}{这个结论有什么用呢?可以用来做数字签名,验证数据信息的来源。也就是刚才的冒充数据行为解决方法。}

签名和验证:

A用自己的私钥通过加密算法得到的数据密文数据,这个数据就可以称为签过名。接收方B再用A提供的公钥通过加密算法就可以还原数据,从而就验证了数据的真实性。因为只有A一个人拥有自己的私钥。


image.png

到这里咱们就可以聊聊刚才中间人伪造数据是如何处理了。通过对称加密可以防止中间人偷窥数据,通过数字签名可以防止中间人篡改伪造数据。


image.png

但是完整版的签名信息需要将签名数据取Hash值,减少数据大小


image.png

Https的加密原理分析

好了,看完理解了上面的知识点,到这里我们可以慢慢分析Https是如何工作的了。

先来总结一句话:Https的本质就是在客户端和服务端之间用非对称加密协商出一套对称密钥,每次发送信息之前将内容加密,接收后解密,达到内容的加密传输。解释下,就是整个数据的传输过程是用对称加密的方式来传输的,只是密钥的生成是由客户端和服务端在创建连接的时候通过非对称加密的方式协商生成的。

那这里就会有一系列的问题啦:
Q:为什么不直接用非对称加密的方式直接加密呢?
A:因为非对称加密的计算过程是复杂的数学运算,太复杂了,很慢。
Q:哦哦,那既然使用对称加密的话,这个对称密钥是怎么来的?
A:在实际的场景中,服务端会对接N个客户端,这个对称密钥如果都使用同一个密钥来通信的话,肯定是不合理的,只要破解了其中一个,其他所有的都会被破解。所以整体的网络架构应该是使用不同加密方式用不同的密钥来进行数据传输的。模型如下图


image.png

Q:但是在网络场景中,对称加密的密钥是不能直接在网络上传输的。服务端和客户端是如何都知道的呢?
A:这个是服务端和客户端一起协商根据只有它俩知道的规则分别生成,就不用通过网络传输啦。
Q:如果保证它俩协商出来的密钥不被破解呢?
A:当然是使用非对称加密的方式啦。通过之前的加密知识,可以知道非对称加密是目前来说是绝对安全的。而且一个私钥可以有多个公钥,正好满足一个服务端对N个客户端的场景。模型如下图:


image.png

实际在协商通讯的过程中,这个公钥是服务端给客户端发送的。而且需要注意这个公钥是用来协商生成对称密钥的,不是用来做数据的加密传输的

Q:哦哦,原来是这样,但是这样子还是有问题啊,客户端与服务端在协商生成密钥的过程中为了保证数据被偷窥和被篡改的风险,一般会要求有两套公钥和私钥分别做加解密和签名验证处理的,上面的模型只有一套公钥和私钥,没法规避数据被被篡改的风险呀。
A:能提出这个问题,说明之前的学习理解得很好。从上面的模型,可以保证在协商的过程中客户端A/B/C/D分别向服务器传输的数据是安全。但是服务器发送给客户端的数据是如何保证的呢?换句话说就是,客户端如何验证数据是服务端发送过来的,而不是被中间假冒掉包的数据。这不就是之前讲的数字签名的内容么?而实际情况中,就是通过CA证书来处理这个问题的。
Q:那这个CA证书是怎么验证的呢?
A:请看下面的CA证书的分析。

CA证书链分析。

回归之前的分析,我们的问题点卡在了“服务器发送给客户端的数据是如何保证的呢”。对吧。实际上在协商通信的过程中,服务端会先给客户端下发证书信息,这个证书信息里面会包含非对称加密的公钥。但是考虑一个问题,如何保证这个公钥就是客户端要的公钥呢?或者说怎么保证这个证书就是真实的证书,而不是被篡改假冒的证书。只有验证了这一步,客户端才完全信赖服务端,才给服务器发消息,也才接受服务器的消息。这时候就只需要一套公钥和私钥客户端和服务端就可以通信了。

Q:那客户端如何验证服务端下发的证书和公钥是正确的呢?
A:先换个概念,将证书里面的公钥假设为一串数据。要验证这个数据,只需要提供这串数据的签名以及加密这段数据的签名的私钥对应的公钥就可以了,如下图框框所示。


image.png image.png

Q:那这样子又有另外的一个问题产生了怎么去验证这段数据的签名的私钥对应的公钥了?
A:同样的,也是需要提供对应的签名和对应签名的私钥对应的公钥。

image.png

Q:但是这样子下去就会变成一个循环了,怎么办?
其实在这里还会有一个场景问题:第三方签发机构不可能只给你一家公司制作证书,它也可能会给中间人这样有坏心思的公司发放证书。这样的,中间人就有机会对你的证书进行调包,客户端在这种情况下是无法分辨出是接收的是你的证书,还是中间人的。因为不论中间人,还是你的证书,都能使用第三方签发机构的公钥进行解密。

A:是的,为处理这个问题,就需要讲一个根证书的东西。先举个例子:假设你是HR,你手上拿到候选人的学历证书,证书上写了持证人,颁发机构,颁发时间等等,同时证书上,还写有一个最重要的:证书编号!我们怎么鉴别这张证书是的真伪呢?只要拿着这个证书编号上相关机构去查,如果证书上的持证人与现实的这个候选人一致,同时证书编号也能对应上,那么就说明这个证书是真实的。同样的,Https请求验证时,会用到手机操作系统内置的根证书去验证这个证书的真伪的。

到这里就简要分析完了证书的验证过程。证书会包含很多信息,包括服务器公钥,服务器名字,服务器地区等等信息。这个是没法篡改的。其中对Https连接来说最重要的就是服务器的公钥。


image.png
Https连接

之前学习完TCP的连接过程,现在我们开始来唠唠Https连接。什么是Https连接呢?准确来说就是SSL/TLS加解密层的连接。

大致的建立流程:

详细的建立流程:


image.png

为啥要这么处理呢?主要是防止消息被扔回来。如果只有一个密钥的话,场景是:A:“分手吧” 。期待B看到后有回应“别分手”。但是中间劫持后,虽然看不懂,但是直接扔回来。然后A解密看到就是“分手吧”。那就凉凉了

客户端MAC secret,服务端MAC secret的主要作用:用来认证这个消息是正确的,完整的,解决对称加密方式没法验证消息的缺点。

至此完整的Https在TLS层连接过程分析完毕。

后序:关于Https原理篇主要涉及到的知识点比较多,主要是请求连接的过程及数据的加解密模块。后续文章会针对原理的内容从源码角度去解读OkHttp和Retrofit两个官方开源的网络库。

如果觉得我的文章对你有帮助,请随意赞赏。您的支持将鼓励我继续创作!

上一篇 下一篇

猜你喜欢

热点阅读