本文主要围绕TCP、UDP、HTTP以及HTTPS服务进行描述。同时,针对TCP服务中的三次握手四次挥手、HTTPS服务的加密算法及过程也会进行阐述。
TCP服务
TCP全名为传输控制协议(Transmission Control Protocol),在OSI模型(由七层组成,分别为物理层、数据链路层、网络层、传输层、会话层、表示层、应用层)中属于传输层协议,而HTTP、SMTP等协议便是基于TCP构建。
首先TCP是面向连接的协议,而在使用TCP传输数据之前需要进行三次握手。客户端只有与服务端成功建立连接后才互相发送数据。那么接下来,我们来感受一下三次握手。
三次握手
1. 我们首先要明白为什么要进行三次握手?
在没有三次握手的前提下:只要服务端发出确认报文段后,便认为TCP建立,但是由于客户端发出的第一个报文在某个节点滞留时间过长,而服务端并不知道,便客户端发送确认报文,对于客户端来说,此报文已失效,导致服务端一直等待客户端的响应,即死锁状态。
所以说,三次握手的主要作用就是客户端与服务端都要知道对方
和自己
的接收
和发送
能力。
2.三次握手的过程
首先建立连接之前TCP客户端和服务端都处于关闭状态(CLIOSED
),在客户端主动打开连接,服务端被动打开连接(LISTEN状态
):
- 客户端给服务端发送一个SYN报文(
这时,服务端知道客户端的发送能力和自己的接收能力
),客户端进入同步已发送状态(SYN_SENT
); - 服务端收到客户端SYN报文后,应答客户端一个SYN+ACK报文(
这时,客户端知道自己的发送/接收能力和服务端的接收/发送能力
),服务端进入同步已接收状态(SYN_RCVD
); - 客户端接收到SYN+ACK报文后,应答服务端一个ACK报文,服务端接收到ACK报文(
这时,服务端知道自己的发送/接收能力和客户端的接收/发送能力
),客户端和服务端都进入已创建状态(ESTABLISHED
)便可以建立连接,即三次握手完成。
当然,如果是HTTPS协议,握手过程中,还会进行数字证书的验证以及加密密钥的生成。
客户端发送能力 | 客户端接收能力 | 服务端发送能力 | 服务端接收能力 | |
---|---|---|---|---|
第一握手 | S知道 | S知道 | ||
第二握手 | B知道/S知道 | B知道 | B知道 | B知道/S知道 |
第三握手 | B知道/S知道 | B知道/S知道 | B知道/S知道 | B知道/S知道 |
注:B
:客户端,S
:服务端。
四次挥手
说完三次握手,我们再了解一下四次挥手。首先TCP连接是双向传输的对等模式,就是说双方都可以同时向对方发送或接收数据。
首先,客户端和服务端都处于已创建状态(ESTABLISHED
),此时,客户端主动关闭TCP连接:
- 客户端发送FIN报文,此时客户端处于终止等待1状态(
FIN_WAIT_1
); - 服务端收到后,向客户端返回ACK报文,此时服务端进入关闭等待状态(
CLOSE_WAIT
); - 若服务端也要关闭连接,则向客户端发送FIN报文,此时服务端进入最后确认状态(
LAST_ACK
); - 客户端收到服务端报文,则向服务端返回ACK报文,此时客户端进入时间等待状态(
TIME_WAIT
),服务端进入关闭状态(CLOSED
); - 经过时间等待计时器设置的时间
2MSL
(最长报文段寿命Maximum Segment Lifetime)后,此时客户端进入关闭状态(CLOSED
)。
注:为什么客户端关闭需要等待2MSL呢?
- 首先要确保服务端是否已经收到客户端的报文;
- 当
1MSL
后,服务端还没有收到,这时服务端会重新发送FIN报文; - 当
2MSL
后,若客户端没有收到服务端重新发送的报文,则说明客户端最后1次发送的报文,服务端已经收到,即客户端可以进入关闭状态。
UDP服务
UDP称用户数据包协议(User Datagram Protocol),与TCP同属网络传输层。与TCP最大的不同是UDP是无连接的,同时,TCP连接是1对1的,即一个客户端想与另一个TCP服务通信,需要创建新的TCP连接;而UDP则是可以多个通信。由于UDP在网络环境差的情况下丢包严重,所以它常常应用于对偶尔丢失一俩个包不严重的场景,即视频、音频、DNS域名转换等场景。
TCP和UDP区别
类型 | 面向连接 | 传输可靠性 | 传输方式 | 传输效率 | 首部字节 | 应用场景 |
---|---|---|---|---|---|---|
TCP | 面向连接 | 可靠 | 字节流 | 慢 | 20-60 | 要求通信数据可靠(如文件传输、邮件传输) |
UDP | 无连接 | 不可靠 | 数据报文段 | 快 | 8个字节 | 要求通信速度高(如域名转换、视频通话) |
HTTP服务
HTTP全称是超文本传输协议(HyperText Transfer Protocol),构建在TCP之上,属于应用层协议,更多信息请查看HTTP-MDN。
1. 特点
- 无连接:限制每次连接只处理一个请求,请求完成后断开连接。
- 无状态:服务器根据客户端请求,发送数据返回,发送完成后,不会记录任何信息。
- 简单快速:客户端向服务器发送请求时,只需传送请求方法和路径。
- 灵活:http允许传输任意类型的数据对象。
- 支持B/S模式。
2. HTTP报文
http的请求报文由请求行
、请求头
以及请求体
组成。
- 请求行:请求方法 + 请求路径 + 协议版本
- 请求头:以键值对的方式组成,如
Content-Type:"text/html;charset=utf-8"
- 请求体:需要发送给服务器的信息
2.1. 请求方法
方法 | 介绍 |
---|---|
GET | 请求一个指定资源的表示形式,被用于获取数据 |
HEAD | 请求一个与GET请求的响应相同的响应,但没有响应体 |
POST | 将实体提交到指定的资源,通常导致在服务器上的状态变化或副作用 |
PUT | 更新指定资源 |
DELETE | 删除指定资源 |
OPTIONS | 描述目标资源的通信选项 |
2.2. 状态码
- 1xx:服务器接收到信息,需要请求者继续执行操作
- 2xx:操作被成功接收并处理
- 3xx:重定向,需要进一步的操作以完成请求
- 4xx:客户端错误,请求包含语法错误或无法完成请求
- 5xx:服务器错误,服务器在处理请求过程中发生错误
常见状态码:
- 100 Continue:继续,客户端继续其请求
- 301 Moved Permanently:永久移动,请求资源被永久的移动到新URI,返回新URI,浏览器会自动重定向新的URI,接下来后面的任何请求都会使用新的URI代替
- 302 Found:临时移动,资源只是临时移动,客户端继续使用原来的URI
- 304 Not Modified:未修改,请求资源未发生更改,服务端返回304时,不会返回任何资源。
3. 附加:http缓存
浏览器缓存主要分为强缓存(本地缓存)和协商缓存(弱缓存)。
强缓存
强缓存由http请求头里的
Expires
和Cache-Control
两个字段控制,用来表示资源的到期时间或缓存时间。
-
Expires
Expires
是HTTP/1.0的规范,它的值是一个绝对时间的GMT格式的时间字符串。由于是服务端返回的绝对时间,所以若客户端与服务端时间偏差较大时,会导致缓存混乱。Expires: Wed Mar 11 2020 15:15:15 GMT
-
Cache-Control
Cache-Control
是HTTP/1.1的规定,有以下多个字段:- max-age:代表资源的有效期,单位为s,如:Cache-Control:max-age=6000。
- no-cache:强制确认缓存,需要使用缓存协商。
- no-store:禁止使用缓存,每次客户端请求,都会下载完整的响应内容。
- public:可以被任何中间人(中间代理、CDN)对其进行缓存。
- private:专用某单个用户,中间人不能对其进行缓存。
- must-revalidate:缓存验证确认,使用一个缓存时,必须先验证它的状态,已过期的缓存将不被使用。
-
Pragma
Pragma
是HTTP/1.0中定义的一个header属性,请求中包含Pragma的效果跟在头信息中定义Cache-Control: no-cache相同,但是HTTP的响应头没有明确定义这个属性,所以它不能拿来完全替代HTTP/1.1中定义的Cache-control头。通常定义Pragma以向后兼容基于HTTP/1.0的客户端。
协商缓存
协商缓存是由服务器来确定缓存资源是否可用,客户端需要通过某种标示来和服务器进行通信,来获知当前主要是否可用缓存访问。
协商缓存主要由两组头字段控制:
Etag
和If-None-Match
浏览器在首次请求资源后,服务端会返回Etag
字段,在再次请求该资源时,客户端发送If-None-Match
字段,服务端通过If-None-Match
的值,来判断是否命中缓存。Last-Modified
和If-Modified-Since
同样,浏览器首次请求资源时,服务端返回Last-Modified
字段,代表资源文件最后修改的时间(也是绝对时间),再次请求时,客户端发送If-Modified-Since
字段,服务端通过对比最后修改时间,来判断是否命中缓存。
在这两组头字段中,服务端会优先对比
Etag
/If-None-Match
,若一致,继续对比Last-Modified
和If-Modified-Since
。如果命中缓存,响应头中还会返回Etag
,但是不会返回资源内容以及Last-Modified
字段。
Etag
的优势:
- 首先资源文件的内容经过多次更改,最后内容依旧和之前的一致,这时
Etag
是不变的,但是它的最后修改时间会随着文件更改而变化,而我们可以通过Etag
避免资源文件重新获取; Last-Modified
只能精确到一秒,无法对在秒以下修改的内容进行判断。
如何计算缓存的优先级?
- 若存在
Cache-Control:max-age
,首先会判断Cache-Control
,即Cache-control: max-age=N
,就代表缓存Ns后过期; - 若不存在
Cache-Control
,这个时候会判断Expires
和头里面的Date
判断缓存是否有效; - 若
max-age
和Expires
都不存在,就找Last-Modified
,缓存时间就等于头里面的Date
减去Last-Modified
的值除以10。
HTTPS服务
由于HTTP传输的数据是以明文的形式存在,那一旦被中间人监控到,就很容易被篡改。HTTPS是基于HTTP协议的,通过SSL/TLS提供加密处理数据,验证以及保证数据的完整性。既然说到加密,就不得说一下加密的不同算法,以及它们之间的安全性对比。
1. 对称加密
对称加密也可以称为共享密钥加密,加密和解密通过相同密钥的一种加密方式。
处理过程如下:
- 客户端通过密码加密数据,然后将密文发送给服务端;
- 服务端通过密钥解密,得到原始数据,这样就可以避免数据被第三方窃听。
那么问题来了:A如何把密钥交给B呢?
- A又在网络上把向B发送密钥;
- 但是,密钥同样可能会被第三方窃听,这样导致数据也可以被第三方窃听。
既然密钥被窃听,那么我们可不可以先加密密钥再进行发送呢?问题又回到最初了,加密的密钥如何发送呢?所以解决这个问题,可以使用密钥交换协议
和非对称加密
。
2. 密钥交换协议
密钥交换协议是一种可以在通信双方之间安全交换密钥的方法。通过讲双方共有的秘密数值隐藏在公开数值相关的运算中,来实现双方之间密钥的安全交换。
在讲解处理过程之前,首先了解一下这个算法的概念。
假设有一种方法可以合成两个密钥。即密钥P和密钥S,合成后得到密钥P-S。这种合成有三个特点:
- 即使持有密钥P和合成密钥P-S,也无法将密钥S单独取出来,即密钥之间可以合成,不可以分解;
- 不管是怎样合成的密钥,都可以继续与其他密钥继续合成。比如上面的密钥P-S还可以与密钥K继续合成,得到新的合成密钥P-S-K;
- 密钥的合成与合成顺序无关,只与哪些密钥有关。比如密钥A和密钥B合成后,得到合成密钥A-B,再与密钥C合成,得到新的合成密钥A-B-C;或者密钥A和密钥C合成后,得到合成密钥A-C,再继续与密钥B合成,得到新的合成密钥A-C-B。此时密钥A-B-C和密钥A-C-B是一样的。
接下来,我们看下来客户端和服务端是如何进行交换密钥的:
- 首先A生成密钥P,然后A把密钥P发送给B;
- A和B各自准备自己的私钥SA和SB;
- A利用密钥P和私钥SA合成密钥P-SA,B利用密钥P和私钥SB合成密钥P-SB;
- A将密钥P-SA发送给B,B也就密钥P-SB发送给A;
- A和B用自己的私钥与对方发送的合成密钥合成新的密钥SA-P-SB;
- 此时,密钥SA-P-SB,便可以当成加密和解密的密钥来使用。
那么,整个过程中,密钥P,密钥P-SA,密钥P-SB都有可能会被第三方窃听,由于密钥是无法分解的,所以第三方是无法通过窃听到的密钥合成出P-SA-SB,因此此方法是安全的。
3. 非对称加密
非对称加密也可以叫公开密钥加密。加密和解密使用不同的密钥进行加密。
处理过程如下:
- 首先由接收方B生成公钥和私钥,然后把公钥发送给A;
- A通公钥进行加密数据,B得到密文后,通过私钥解密。
对比对称加密
,使用非对称加密不会出现密钥分配的问题。在使用对称加密的时候,密钥的需求数量会随着发送人数的增多而急剧增多,即:2个需要2个,3个人就需要3个,4个人就需要6个......n个人就需要n*(n-1)/2个。而非对称加密只需要接受方保存私钥即可。
那么问题来了:如果第三方也准备了公钥和私钥呢?
- 在B把公钥发送给A时,第三方把自己的公钥给了A,A又不知情;
- 接下来A用第三方的公钥加密发送,第三方用自己的私钥再解密;
- 第三方用B的公钥加密发送B,B用自己的私钥解密;
- 这个过程中,A和B都不知道数据已经被第三方窃听了。
非对称加密的可靠性出现的问题就是:A无法判断收到的公钥是B的还是第三方?接下来,我们就需要用数字证书来解决这个问题。
非对称加密必须满足下面的条件:
- 可以使用某个数值对数据加密计算;
- 使用另一个数值时对加密数据进行计算,就可以把数据恢复原样;
- 无法从一个密钥推算出另一个密钥。
通过上面的满足条件,我们可以发现非对称加密的整个加密和解密过程都比较耗时,所以说这种加密算法不适用持续发送零碎数据的情况,这个时候就要用到混合加密。
4. 混合加密
通过对称加密和非对称加密的分析,在混合加密的过程中,需要用处理速度快的对称加密算法对数据进行加密,加密的密钥则是由非对称加密的公钥进行处理。
处理过程如下:
- B首先将公钥发送给A,A接收到后,用公钥加密对数据处理的密钥,然后发送给B;
- B用自己的私钥解密后,得到对数据处理的密钥;
- 接下来,A用自己的密钥加密数据和B进行通信。
5. 消息认证码
密文在传输过程中可能会被篡改,这会导致解密后的内容发送变化,而消息认证码可以预防这种情况的发生。
首先A发生密文给B,但是这个过程中,可能会被第三方篡改,而B得到密文后无法感知密文的正确性,从而解密后得到了错误的消息。为了解决这一问题,可以通过消息认证码处理:
- A生成一个用于制作消息认证码的密钥,通过安全的方式将密钥发送给B;
- A在发送消息时,将密文和密钥生成一个hash值,这个值便是消息认证码MAC(Message Authentication Code);
- B在接收到消息时,通过密钥和接收到密文也生成MAC,与A发送的MAC做对比,便可以知道密文是否被篡改。
然而,这种方法也有缺点。在使用消息认证码的过程中,AB双方都可以对消息进行加密并算出MAC。所以,无法证明原本的消息是A生成的还是B生成的。那么,接下来,可以通过数字签名来解决。
6. 数字签名
数字签名不仅可以实现消息认证码的认证和检测篡改功能,还可以预防事后否认问题的发生。
首先,看一下数字签名的特征,假设A向B发生消息:
- 在发送前A给消息加上数字签名,而数字签名只能由A生成;
- B接收到后,验证数字签名,就可以确认发送者是否是A。
接下来,来看一下数字签名是怎么生成的。首先,数字签名的生成使用的是非对称加密,在非对称加密中,加密使用的是公钥,解密是私钥,任何人都可以通过公钥进行数据加密,但只有私钥的持有者才可以解密。然而在数字签名的生成过程正好是相反的:
- 首先A准备好公钥和私钥,A将公钥发送给B;
- 然后A通过私钥加密信息,加密后的信息就是数字签名,A将消息和签名都发送给B;
- B使用公钥对签名解密,通过判断解密后的信息与消息对比是否一致,来确认消息。
虽然解决了预防事后否认的问题,但是还是存在问题:B在接收公钥时,无法确认公钥的生成者是否是A。所以接下来,使用数字证书来解决。
7. 数字证书
同样,A持有公钥和私钥,如何安全的将公钥发送给B:
- 首先A需要向认证中心(Certification Authority,CA)申请发行证书,证明公钥确实由自己生成;
- A将公钥和包含邮箱信息的个人资料发送给认证中心;
- 认证中心对资料进行确认,使用认证中心自己的私钥,根据A的资料生成数字签名,将数字签名和资料整理起来;
- 然后将这个文件发送给A,这个文件便是A的数字证书;
- A将数字证书发送给B;
- B接收到数字证书并确认后,获取认证中心的公钥;
- B通过公钥对证书中的签名进行验证,判断是否为认证中心给的签名;
- B确认成功后,从证书中取出A的公钥,这样子,A的公钥就传给B了,接下来就可以继续通信了。
这个时候,来看一下第三方是否还有机会发送自己公钥,第三方只有自己去认证中心登记自己的公钥,然而第三方是无法使用A的邮箱地址的,所以无法获得A的证书。这样子就保证了公钥的安全性。
总结
以上便是笔者在学习网络协议过程中做的笔记,可能有些知识点没有说到或说的很详细,还请各位包涵。当然,做为一名前端开发人员,我认为对于网络协议部分的了解不止于此!