网络-存档

端口及对应的服务

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LCIVcP4g-1659580889382)(F:\markdown笔记\面经\网络\Snipaste_2022-04-10_10-47-44.png)]

DNS解析

DNS,英文全称是domain name system,域名解析系统,是Internet上作为域名和IP相互映射的一个分布式数据库。它的作用很明确,就是可以根据域名查出对应的IP地址。本地是一个相对的概念,因为DNS服务是有很多级的,所以更靠近用户的那级服务器就叫做本地DNS服务器。很多运营商都会在当地架设自己的DNS服务器储存着常用的域名映射,用来为用户提供更快的域名解析服务。

DNS的解析过程如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7V30dDfB-1659580889384)(F:\markdown笔记\面经\网络\648.webp)]

假设要查询www.baidu.com的IP地址:从后往前解析

  • 首先会查找浏览器的缓存,看看是否能找到www.baidu.com对应的IP地址,找到就直接返回;否则进行下一步。在Windows操作系统的DNS缓存找,若没有,则尝试读取hosts文件(位于C:\Windows\System32\drivers\etc),看看这里面有没有该域名对应的IP地址,如果在hosts文件中也没有找到对应的条目,浏览器就会发起一个DNS的系统调用,就会向本地配置的首选DNS服务器(一般是电信运营商提供的)发起域名解析请求(通过的是UDP协议向DNS的53端口发起请求)
  • 将请求发往给本地DNS服务器,如果查找到就直接返回,否则继续进行下一步;
  • 本地DNS服务器向根域名服务器发送请求,根域名服务器返回负责.com的顶级域名服务器的IP地址的列表。
  • 本地DNS服务器再向其中一个负责.com顶级域名服务器发送一个请求,返回负责.baidu 的权威域名服务器的IP地址列表。
  • 本地DNS服务器再向其中一个权威域名服务器发送一个请求,返回www.baidu.com所对应的IP地址。

上述是迭代查找,还可以使用递归查找,本地DNS服务器向根域名服务器发送请求,根域名服务器向顶级域名服务器发送请求,顶级域名服务器向权威域名服务器发送请求,再一个个返回。

/etc/hosts 是主机的一个文件列表,一般可以在这里面添加记录: ip 域名111.13.100.92 www.baidu.com 对于简单的主机名解析(点分表示法),默认在请求DNS网络域名服务器前,会先查看此文件。

发送 DNS 查询时,DNS 请求报头部的 RD 字段默认为 1,默认为递归查询。RD 为 1 => 递归查询 RD 为 0 => 迭代查询

计算机网络体系结构

计算机网路体系结构有三层:OSI七层模型、TCP/IP四层模型、五层体系结构。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-flUJlK2M-1659580889385)(F:\markdown笔记\面经\网络\Snipaste_2022-04-10_10-51-10.png)]

OSI七层模型

开放式系统互联通信参考模型(Open System Interconnection Reference Model,缩写为 OSI),简称为OSI模型。OSI七层模型是国际标准化组织制定的一个用于计算机或通信系统间互联的标准体系。

  • 应用层:网络服务与最终用户的一个接口,常见的协议有:HTTP FTP SMTP SNMP DNS

  • 表示层:数据的表示、安全、压缩。确保一个系统的应用层所发送的信息可以被另一个系统的应用层读取。

  • 会话层:建立、管理、终止会话,对应主机进程,指本地主机与远程主机正在进行的会话。

  • 传输层:定义传输数据的协议端口号,以及流控和差错校验,协议有 TCP UDP

  • 网络层:进行逻辑地址寻址,实现不同网络之间的路径选择,协议有 ICMP IGMP IP等

  • 数据链路层:在物理层提供比特流服务的基础上,建立相邻结点之间的数据链路。

  • 物理层:建立、维护、断开物理连接。

TCP/IP 四层模型
  • 应用层:对应于OSI参考模型的(应用层、表示层、会话层)

  • 传输层:对应OSI的传输层,为应用层实体提供端到端的通信功能,保证了数据包的顺序传送及数据的完整性

  • 网际层:对应于OSI参考模型的网络层,主要解决主机到主机的通信问题

  • 网络接口层:与OSI参考模型的数据链路层、物理层对应

    TCP/IP的传输层用一个16位端口号来标志一个端口(port)。虽然通信的终点是应用程序,但只要把所传送的报文交到目的主机的某个合适的目的端口,剩下的工作(即最后交付的进程)就由TCP或UDP来完成。

    TCP和UDP的首部格式中,它们都有源端口目的端口这两个重要字段。当传输层收到网络层交上来的传输层报文时,就能够根据其首部中的目的端口号把数据交付到应用层目的应用进程

    两个计算机中的进程要互相通信,不仅必须知道对方的IP地址,而且要知道对方的端口号(为了找到对方计算机中的应用程序)。互联网上的计算机通信是采用客户端-服务器方式。客户端在发起通信请求时,必须先知道对方的服务器的IP地址端口号

    (1)服务器端使用的端口号:数值为0 ~ 1023

    (2)客户端使用的端口号:数值为49152 ~ 65535 这类端口号仅在客户进程运行时才动态选择,因此又叫做短暂端口号。这类端口号留给客户进程选择暂时使用。当服务器进程收到客户进程的报文时,就知道了客户进程所使用的端口号,因而可以把数据发送给客户进程。通信结束后,刚才已使用过的客户端口号就不存在了,这个端口号就可以供其他客户进程使用。

五层体系结构
  • 应用层:对应于OSI参考模型的(应用层、表示层、会话层)
  • 传输层:对应OSI参考模型的的传输层
  • 网络层:对应OSI参考模型的的网络层
  • 数据链路层:对应OSI参考模型的的数据链路层
  • 物理层:对应OSI参考模型的的物理层
每层对应的网络协议

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7HG9Otgv-1659580889386)(F:\markdown笔记\面经\网络\650.webp)]

IP地址分类

一般可以这么认为,IP地址 = 网络号+主机号。

  1. 网络号:它标志主机所连接的网络地址表示属于互联网的哪一个网络。
  2. 主机号:它标志主机地址表示其属于该网络中的哪一台主机。

IP地址分为A,B,C,D,E五大类:

  • A类地址(1~126):以0开头,网络号占前8位,主机号占后面24位。
  • B类地址(128~191):以10开头,网络号占前16位,主机号占后面16位。
  • C类地址(192~223):以110开头,网络号占前24位,主机号占后面8位。
  • D类地址(224~239):以1110开头,保留为多播地址。
  • E类地址(240~255):以11110开头,保留为将来使用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yXcS1Lqp-1659580889387)(F:\markdown笔记\面经\网络\654.webp)]

ARP 协议

ARP 协议协议,Address Resolution Protocol,地址解析协议,用于实现IP地址到MAC地址的映射。(只对同网段需要连接的机器的mac层访问,不同网段主机之间需要路由访问)

  1. 首先,每台主机都会在自己的ARP缓冲区中建立一个ARP列表,以表示IP地址和MAC地址的对应关系。
  2. 当源主机需要将一个数据包要发送到目的主机时,会首先检查自己的ARP列表,是否存在该IP地址对应的MAC地址;如果有,就直接将数据包发送到这个MAC地址;如果没有,就向本地网段发起一个ARP请求的广播包,查询此目的主机对应的MAC地址(局域网内所有主机)。此ARP请求的数据包里,包括源主机的IP地址、硬件地址、以及目的主机的IP地址。
  3. 本地网段中所有的主机收到这个ARP请求后,会检查数据包中的目的IP是否和自己的IP地址一致。如果不相同,就会忽略此数据包;如果相同,该主机首先将发送端的MAC地址和IP地址添加到自己的ARP列表中,如果ARP表中已经存在该IP的信息,则将其覆盖,然后给源主机发送一个 ARP响应数据包,告诉对方自己是它需要查找的MAC地址。
  4. 源主机收到这个ARP响应数据包后,将得到的目的主机的IP地址和MAC地址添加到自己的ARP列表中,并利用此信息开始数据的传输。如果源主机一直没有收到ARP响应数据包,表示ARP查询失败。
IP地址 MAC地址
  • 简而言之,标识网络中的一台计算机,比较常用的就是IP地址和MAC地址,但计算机的IP地址可由用户自行更改,管理起来就相对困难,而MAC地址不可更改,所以一般会把IP地址和MAC地址组合起来使用。
  • 那只使用MAC地址不用IP地址行不行呢?不行的!因为最早就是MAC地址先出现的,并且当时并不用IP地址,只用MAC地址,后来随着网络中的设备越来越多,整个路由过程越来越复杂,便出现了子网的概念。对于目的地址在其他子网的数据包,路由只需要将数据包送到那个子网即可。
  • 那为什么要用IP地址呢?是因为IP地址是和地域相关的,对于同一个子网上的设备,IP地址的前缀都是一样的,这样路由器通过IP地址的前缀就知道设备在在哪个子网上了,而只用MAC地址的话,路由器则需要记住每个MAC地址在哪个子网,这需要路由器有极大的存储空间,是无法实现的。
  • IP地址可以比作为地址,MAC地址为收件人,在一次通信过程中,两者是缺一不可的。
ICMP协议

ICMP,(Internet Control Message Protocol) ,Internet控制消息协议。

  • ICMP协议是一种面向无连接的协议,用于传输出错报告控制信息。
  • 它是一个非常重要的协议,它对于网络安全具有极其重要的意义。它属于网络层协议,主要用于在主机与路由器之间传递控制信息,包括报告错误、交换受限控制和状态信息等。
  • 当遇到IP数据无法访问目标、IP路由器无法按当前的传输速率转发数据包等情况时,会自动发送ICMP消息。

ping,就是基于ICMP的。

ping的原理

ping,Packet Internet Groper,是一种因特网包探索器,用于测试网络连接量的程序。Ping是工作在TCP/IP网络体系结构中应用层的一个服务命令, 主要是向特定的目的主机发送ICMP(Internet Control Message Protocol 因特网报文控制协议) 请求报文,测试目的站是否可达及了解其有关状态

一般来说,ping可以用来检测网络通不通。它是基于ICMP协议工作的。假设机器Aping机器B,工作过程如下:

  1. ping通知系统,新建一个固定格式的ICMP请求数据包
  2. ICMP协议,将该数据包和目标机器B的IP地址打包,一起转交给IP协议层
  3. IP层协议将本机IP地址为源地址,机器B的IP地址为目标地址,加上一些其他的控制信息,构建一个IP数据包
  4. 先获取目标机器B的MAC地址。
  5. 数据链路层构建一个数据帧,目的地址是IP层传过来的MAC地址,源地址是本机的MAC地址
  6. 机器B收到后,对比目标地址,和自己本机的MAC地址是否一致,符合就处理返回,不符合就丢弃。
  7. 根据目的主机返回的ICMP回送回答报文中的时间戳,从而计算出往返时间
  8. 最终显示结果有这几项:发送到目的主机的IP地址、发送 & 收到 & 丢失的分组数、往返时间的最小、最大& 平均值

HTTP

HTTP

超文本(不止是文本 图片视频超链接等)传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。设计 HTTP 最初的目的是为了提供一种发布和接收 HTML 页面的方法。它可以使浏览器更加高效。HTTP 协议是以明文方式发送信息的。是一个基于TCP/IP通信协议来传递明文数据的协议。HTTP会存在这几个问题

  • 请求信息是明文传输,容易被窃听截取。
  • 没有验证对方身份,存在被冒充的风险
  • 数据的完整性未校验,容易被中间人篡改
原理

① 客户端的浏览器首先要通过网络与服务器建立连接,该连接是通过 TCP 来完成的,一般 TCP 连接的端口号是80。 建立连接后,客户机发送一个请求给服务器,请求方式的格式为:统一资源标识符(URI)、协议版本号,后边是 MIME 信息包括请求修饰符、客户机信息和许可内容。

② 服务器接到请求后,给予相应的响应信息,其格式为一个状态行,包括信息的协议版本号、一个成功或错误的代码,后边是 MIME 信息包括服务器信息、实体信息和可能的内容。

为了解决Http存在的问题,Https出现。

HTTPS

是以安全为目标的 HTTP 通道,是 HTTP 的安全版。HTTPS 的安全基础是 SSL。SSL 协议位于 TCP/IP 协议与各种应用层协议之间,为数据通讯提供安全支持。SSL 协议可分为两层:SSL 记录协议(SSL Record Protocol),它建立在可靠的传输协议(如TCP)之上,为高层协议提供数据封装、压缩、加密等基本功能的支持。SSL 握手协议(SSL Handshake Protocol),它建立在 SSL 记录协议之上,用于在实际的数据传输开始前,通讯双方进行身份认证、协商加密算法、交换加密密钥等。

HTTPS= HTTP+SSL/TLS,可以理解Https是身披SSL(Secure Socket Layer,安全套接层)的HTTP。也就是用SSL/TLS对数据进行加密和解密,Http进行传输。SSL,即Secure Sockets Layer(安全套接层协议),是网络通信提供安全及数据完整性的一种安全协议。TLS,即Transport Layer Security(安全传输层协议),它是SSL3.0的后续版本。

TLS/SSL 1.2

传输层安全性协议 TLS(Transport Layer Security),及其前身安全套接层 SSL(Secure Sockets Layer)是一种安全协议,目的是为互联网通信提供安全及数据完整性保障。TLS(传输层安全)是更为安全的升级版 SSL

TLS/SSL 的功能实现主要依赖于三类基本算法:散列函数 Hash、对称加密和非对称加密,其利用非对称加密实现身份认证和密钥协商,对称加密算法采用协商的密钥对数据加密,基于散列函数验证信息的完整性。

散列函数

常见的有 MD5、SHA1、SHA256,该类函数特点是函数单向不可逆、对输入非常敏感、输出长度固定,针对数据的任何修改都会改变散列函数的结果,用于防止信息篡改并验证数据的完整性。在信息传输过程中,散列函数不能单独实现信息防篡改,因为明文传输,中间人可以修改信息之后重新计算信息摘要,因此需要对传输的信息以及信息摘要进行加密。

对称加密

常见的有 AES-CBC、DES、3DES、AES-GCM 等,信息的加密和解密用相同的密钥,掌握密钥才能获取信息。在对称加密中,信息安全的基础是保证密钥的安全。

对称加密的特点:对称密码体制中只有一种密钥,并且是非公开的。如果要解密就得让对方知道密钥,所以想要保证其安全性就要保证密钥的安全。

非对称加密

即常见的 RSA 算法,还包括 ECC、DH 等算法,算法特点是,密钥成对出现,一般称为公钥(公开)和私钥(保密)。因此掌握公钥的不同客户端之间不能互相解密信息,只能和掌握私钥的服务器进行加密通信。服务器持有私钥可以实现一对多的通信,而客户端可以用公钥来验证服务器发送的数字签名。服务器只需要维持一个私钥就能够和多个客户端进行加密通信,但该算法的计算复杂,加密速度慢。

非对称加密的特点:算法强度复杂、安全性依赖于密钥但是由于其算法复杂,而使得加密解密速度没有对称加密解密的速度快。非对称密钥体制有两种密钥,其中一个是公开的,这样就可以不需要像对称密码那样传输对方的密钥了,这样安全性就大了很多。

结合三类算法的特点,TLS/SSL 的基本工作方式是,客户端使用非对称加密与服务器进行通信,实现身份验证并协商对称加密使用的密钥,然后对称加密算法采用协商密钥对信息以及信息摘要进行加密通信,不同的节点之间采用的对称密钥不同,从而可以保证信息只能通信双方获取。

密钥协商存在的问题

如何正确地决定某个主体或身份的公钥。如果 A 向 B 发送自已的公钥,M 能够在传输过程中将其修改为自己的公钥。B (也被称为依赖方)可能察觉不到自已使用的是 M 的公钥,而认为这是 A 的公钥。这样就使得 M 能够轻易地扮演 A 的角色

解决办法

依靠中心化的机构,其中包括对公钥基础设施 PKI (Public Key Infrastructure) 的使用。这一方法在特定的理论假设下容易被证明是安全的。 PKI 负责提供创建、吊销、分发以及更新密钥对与证书的服务。它需要一些证书颁发机构 CA (Certificate Authority) 才能运行。证书颁发机构是用于管理与认证一些个体与它们的公钥间的绑定关系的实体。

数字签名 数字证书

数字证书是指在互联网通讯中标志通讯各方身份信息的一个数字认证,人们可以在网上用它来识别对方的身份。它的出现,是为了避免身份被篡改冒充的。比如Https的数字证书,就是为了避免公钥被中间人冒充篡改

数字证书构成

  • 公钥和个人信息,经过Hash摘要算法形成消息摘要;将消息摘要拿到拥有公信力的认证中心(CA),用它的私钥对消息摘要签名,形成数字签名。所以公钥和个人信息、数字签名共同构成数字证书
TLS/SSL 握手过程
  1. client_hello

客户端发起请求,以明文传输请求信息,包含版本信息,加密套件候选列表,压缩算法候选列表,随机数,扩展字段等信息,相关信息如下:

(1) 支持的最高TSL协议版本version,从低到高依次 SSLv2,SSLv3,TLSv1,TLSv1.1,TLSv1.2,TLSv1.3。

(2) 客户端支持的加密套件 cipher suites 列表, 每个加密套件对应前面 TLS 原理中的四个功能的组合:认证算法 Au (身份验证)、密钥交换算法 Key Exchange(密钥协商)、对称加密算法 Enc (信息加密)和信息摘要 Mac(完整性校验)。

(3) 支持的压缩算法 compression methods 列表,用于后续的信息压缩传输。

(4) 随机数 random_C,用于后续的密钥的生成。

(5) 扩展字段 extensions,支持协议与算法的相关参数以及其它辅助信息等,常见的 SNI 就属于扩展字段,后续单独讨论该字段作用。

  1. server_hello + server_certificate + sever_hello_done

(1) server_hello, 服务端返回协商的信息结果,包括选择使用的协议版本 version,选择的加密套件 cipher suite,选择的压缩算法 compression method、随机数 random_S 等,其中随机数用于后续的密钥协商。

(2) server_certificates,服务器端配置对应的证书链,用于身份验证与密钥交换。

(3) server_hello_done,通知客户端 server_hello 信息发送结束。

  1. 证书校验

客户端验证证书的合法性,如果验证通过才会进行后续通信,否则根据错误情况不同做出提示和操作,合法性验证包括如下:

(1) 证书链的可信性 trusted certificate path。

(2) 证书是否吊销 revocation,有两类方式离线 CRL 与在线 OCSP,不同的客户端行为会不同。

(3) 有效期 expiry date,证书是否在有效时间范围。

(4) 域名 domain,核查证书域名是否与当前的访问域名匹配,匹配规则后续分析。

  1. client_key_exchange + change_cipher_spec + encrypted_handshake_message

(1) client_key_exchange,合法性验证通过之后,客户端计算产生随机数字 Pre-master,并用证书公钥加密,发送给服务器。

(2) 此时客户端已经获取全部的计算协商密钥需要的信息:两个明文随机数 random_C 和 random_S 与自己计算产生的 Pre-master,计算得到协商密钥: enc_key = Function(random_C, random_S, Pre-Master);

(3) change_cipher_spec,客户端通知服务器后续的通信都采用协商的通信密钥和加密算法进行加密通信。

(4) encrypted_handshake_message,结合之前所有通信参数的 hash 值与其它相关信息生成一段数据,采用协商密钥 session secret 与算法进行加密,然后发送给服务器用于数据与握手验证。

  1. change_cipher_spec + encrypted_handshake_message

(1) 服务器用私钥解密加密的 Pre-master 数据,基于之前交换的两个明文随机数 random_C 和 random_S,计算得到协商密钥:enc_key = Function(random_C, random_S, Pre-Master);

(2) 计算之前所有接收信息的 hash 值,然后解密客户端发送的 encrypted_handshake_message,验证数据和密钥正确性。

(3) change_cipher_spec, 验证通过之后,服务器同样发送 change_cipher_spec 以告知客户端后续的通信都采用协商的密钥与算法进行加密通信。

(4) encrypted_handshake_message, 服务器也结合所有当前的通信参数信息生成一段数据并采用协商密钥 session secret 与算法加密并发送到客户端。(将随机密码加密的数据响应给客户端)

  1. 握手结束

客户端计算所有接收信息的 hash 值,并采用协商密钥解密 encrypted_handshake_message,验证服务器发送的数据和密钥,验证通过则握手完成。

  1. 加密通信

开始使用协商密钥与算法进行加密通信。注意:

(1) 服务器也可以要求验证客户端,即双向认证,可以在过程 2 要发送 client_certificate_request 信息,客户端在过程 4 中先发送 client_certificate 与 certificate_verify_message 信息,证书的验证方式基本相同,certificate_verify_message 是采用 client 的私钥加密的一段基于已经协商的通信信息得到数据,服务器可以采用对应的公钥解密并验证。

(2) 根据使用的密钥交换算法的不同,如 ECC 等,协商细节略有不同,总体相似。

(3) sever key exchange 的作用是 server certificate 没有携带足够的信息时,发送给客户端以计算 pre-master,如基于 DH 的证书,公钥不被证书中包含,需要单独发送。

(4) change cipher spec 实际可用于通知对端改版当前使用的加密通信方式,当前没有深入解析。

(5) alter message 用于指明在握手或通信过程中的状态改变或错误信息,一般告警信息触发条件是连接关闭,收到不合法的信息,信息解密失败,用户取消操作等,收到告警信息之后,通信会被断开或者由接收方决定是否断开连接。

会话复用
  1. 对于已经建立的SSL会话,使用session id为key(session id来自第一次请求的server hello中的session id字段), 对称密钥为value组成一对键值,保存在本地,服务器和客户端都保存一份。当第二次握手时,客户端若想使用会话复用,则发起的client hello中session id会置上对应的值,服务器收到这个client hello,解析session id,查找本地是否有该session id,如果有,判断当前的加密套件和上个会话的加密套件是否一致,一致则允许使用会话复用,于是自己的server hello 中session id也置上和client hello中一样的值。如果服务器未查到客户端的session id指定的会话(可能是会话已经老化),则会重新握手,session id要么重新计算(和client hello中session id不一样),要么置成0,这两个方式都会告诉客户端这次会话不进行会话复用。

  2. 服务器加密整个会话状态并将其作为"票证"发送给客户端。 当重新连接时,在初始连接时将状态发送到服务器。 这种机制避免了服务器端会话缓存的需要。 如果服务器不使用票证,出于任何原因(无法解密、太旧等),则它将创建新的会话并发送新的票证。

    客户端发起client hello,拓展中带上空的session ticket TLS,表明自己支持session ticket。服务器在握手过程中,如果支持session ticket,则发送New session ticket类型的握手报文,其中包含了能够恢复包括主密钥在内的会话信息,当然,最简单的就是只发送master key。为了让中间人不可见,这个session ticket部分会进行编码、加密等操作。客户端收到这个session ticket,就把当前的master key和这个ticket组成一对键值保存起来。服务器无需保存任何会话信息。当客户端尝试会话复用时,会在client hello的拓展中加上session ticket,然后服务器收到session ticket,回去进行解密、解码能相关操作,来恢复会话信息。如果能够恢复会话信息,那么就提取会话信息的主密钥进行后续的操作。

TLS1.3

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J5tKupVc-1659580889388)(F:\markdown笔记\面经\网络\2573196-4a8b031890d27ff3.png)]

TLS 1.3 仅用两条消息就共享了 4 个信息:Client RandomServer RandomClient ParamsServer Params。两边就可以各自用 DH 算出 “Pre-Master”,再用 HKDF 生成主密钥 “Master Secret”,效率比 TLS 1.2 提高了一大截。在计算出主密钥后,服务器立刻发出 “Change Cipher Spec” 消息,比 TLS 1.2 提早进入加密通信,后面的证书等就都是加密的了,减少握手时明文信息泄露。TLS 1.3 还多了一个 “Change Cipher Spec” 消息,服务器用私钥把前面的曲线、套件、参数等握手数据加了签名,作用和 “Finished” 握手结束消息差不多。但由于是私钥签名,所以强化了身份认证和防篡改。

(1)客户端:生成随机数 a,选择公开的大数 G 和 P,计算 A=a*G%P,将 A 和 G 发送给服务器,也就是 Client Hello 消息

(2)服务器:生成随机数 b,计算 B=b*G%P,将 B 发送给客户端,也就是 Server Hello 消息

(3)客户端:使用 ECDH 算法生成通信密钥 KEY = a*B = a*b*G%P

(4)服务器:使用 ECDH 算法生成通信密钥 KEY = b*A = b*a*G%P

签名过程

发送报文时,发送方用一个哈希函数从报文文本中生成报文摘要,然后用发送方的私钥对这个摘要进行加密,这个加密后的摘要将作为报文的数字签名和报文一起发送给接收方。接收方首先用与发送方一样的哈希函数从接收到的原始报文中计算出报文摘要,接着再用公钥来对报文附加的数字签名进行解密,如果这两个摘要相同、那么接收方就能确认该报文是发送方的。

数字签名有两种功效:一是能确定消息确实是由发送方签名并发出来的,因为别人假冒不了发送方的签名。二是数字签名能确定消息的完整性。因为数字签名的特点是它代表了文件的特征,文件如果发生改变,数字摘要的值也将发生变化。不同的文件将得到不同的数字摘要。 一次数字签名涉及到一个哈希函数、接收者的公钥、发送方的私钥。

Https流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L6rCLvAX-1659580889388)(F:\markdown笔记\面经\网络\4c1f297dbe0e4cc3e93ab4258bb39e19.jpg)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9GXwsMD6-1659580889389)(F:\markdown笔记\面经\网络\647.webp)]

先使用tcp建立连接

① 客户端的浏览器向服务器发送请求,连接到服务器的443端口。并传送客户端 SSL 协议的版本号,加密算法的种类,产生的随机数,以及其他服务器和客户端之间通讯所需要的各种信息。

② 服务器必须要有一套数字证书(证书内容有公钥、证书颁发机构、失效日期等)。

③ 服务器向客户端传送 SSL 协议的版本号,加密算法的种类,随机数以及其他相关信息,同时服务器还将向客户端传送自己的证书。

④ 客户端利用服务器传过来的信息验证服务器的合法性,服务器的合法性包括:证书是否过期,发行服务器证书的 CA 是否可靠,发行者证书的公钥能否正确解开服务器证书的 “发行者的数字签名”,服务器证书上的域名是否和服务器的实际域名相匹配。如果合法性验证没有通过,通讯将断开;如果合法性验证通过,将继续

⑤ 用户端计算得到协商密钥: enc_key = Function(random_C, random_S, Pre-Master); 然后用服务器的公钥(服务器的公钥从步骤③中的服务器的证书中获得)对Pre-Master加密,传给服务器。

如果服务器要求客户的身份认证(在握手过程中为可选),服务器必须检验客户证书和签名随机数的合法性,具体的合法性验证过程包括:客户的证书使用日期是否有效,为客户提供证书的 CA 是否可靠,发行 CA 的公钥能否正确解开客户证书的发行 CA 的数字签名,检查客户的证书是否在证书废止列表(CRL)中。检验如果没有通过,通讯立刻中断;如果验证通过,才执行一系列步骤。

⑥ 服务器接收到客户端发来的Pre-Master之后,用自己之前保留的私钥对其进行非对称解密,解密之后计算得到协商密钥: enc_key = Function(random_C, random_S, Pre-Master); 然后用客户端密钥对返回数据进行对称加密,传输的数据都是密文啦。

⑦ 服务器将加密后的密文返回到客户端。

⑧ 客户端收到后,用自己的密钥对其进行对称解密,得到服务器返回的数据。

HTTPS 的优点

1、使用 HTTPS 协议可认证用户和服务器,确保数据发送到正确的客户机和服务器。

2、HTTPS 协议是由SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,要比 HTTP 协议安全,可防止数据在传输过程中不被窃取、修改,确保数据的完整性。

3、HTTPS 是现行架构下最安全的解决方案,虽然不是绝对安全,但它大幅增加了中间人攻击的成本。

HTTPS 的缺点

1、HTTPS 协议握手阶段比较费时,会使页面的加载时间延长近。

2、HTTPS 连接缓存不如 HTTP 高效,会增加数据开销,甚至已有的安全措施也会因此而受到影响。

3、HTTPS 协议的安全是有范围的,在黑客攻击、拒绝服务攻击和服务器劫持等方面几乎起不到什么作用。

4、SSL 证书通常需要绑定 IP,不能在同一 IP 上绑定多个域名,IPv4 资源不能支撑这个消耗。

5、成本增加。部署 HTTPS 后,因为 HTTPS 协议的工作要增加额外的计算资源消耗,例如 SSL 协议加密算法和 SSL 交互次数将占用一定的计算资源和服务器成本。

6、HTTPS 协议的加密范围也比较有限。最关键的,SSL 证书的信用链体系并不安全,特别是在某些国家可以控制 CA 根证书的情况下,中间人攻击一样可行。

HTTP与HTTPS

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E4RB4c5m-1659580889390)(F:\markdown笔记\面经\网络\646.webp)]

1、HTTPS 协议需要到 CA (Certificate Authority,证书颁发机构)申请证书,一般免费证书较少,因而需要一定费用。

2、HTTP 是超文本传输协议,信息是明文传输,HTTPS 则是具有安全性的 SSL 加密传输协议。

3、HTTP 和 HTTPS 使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。

4、HTTP 的连接很简单,是无状态的。HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,比 HTTP 协议安全。(无状态的意思是其数据包的发送、传输和接收都是相互独立的。通信双方都不长久的维持对方的任何信息。)

HTTPS改进
双向身份认证

客户端和服务端在传输数据之前,会通过基于X.509证书对双方进行身份认证 。具体过程如下:

客户端发起 SSL 握手消息给服务端要求连接。服务端将证书发送给客户端。客户端检查服务端证书,确认是否由自己信任的证书签发机构签发(客户端内置了所有受信任 CA 的证书)。 如果不是,将是否继续通讯的决定权交给用户选择 ( 注意,这里将是一个安全缺陷 )。如果检查无误或者用户选择继续,则客户端认可服务端的身份。

服务端要求客户端发送证书,并检查是否通过验证。失败则关闭连接,认证成功则从客户端证书中获得客户端的公钥,一般为 1024 位或者 2048 位。到此,服务器客户端双方的身份认证结束,双方确保身份都是真实可靠的。

注意:

(1) 采用 HTTPS 协议的服务器必须要有一套数字证书,可以自己制作,也可以向组织申请。区别就是自己颁发的证书需要客户端验证通过,才可以继续访问。这套证书其实就是一对公钥和私钥。

(2) 互联网有太多的服务需要使用证书来验证身份,以至于客户端(操作系统或浏览器等)无法内置所有证书,需要通过服务端将证书发送给客户端。

(3) 客户端内置的是 CA 的根证书(Root Certificate),HTTPS 协议中服务器会发送证书链(Certificate Chain)给客户端。

数据传输的机密性

客户端和服务端在开始传输数据之前,会协商传输过程需要使用的加密算法。 客户端发送协商请求给服务端, 其中包含自己支持的非对称加密的密钥交换算法 ( 一般是RSA),数据签名摘要算法 ( 一般是SHA或者MD5) ,加密传输数据的对称加密算法 ( 一般是DES),以及加密密钥的长度。 服务端接收到消息之后,选中安全性最高的算法,并将选中的算法发送给客户端,完成协商。客户端生成随机的字符串,通过协商好的非对称加密算法,使用服务端的公钥对该字符串进行加密,发送给服务端。 服务端接收到之后,使用自己的私钥解密得到该字符串。在随后的数据传输当中,使用这个字符串作为密钥进行对称加密。

防止重放攻击

SSL 使用序列号来保护通讯方免受报文重放攻击。这个序列号被加密后作为数据包的负载。在整个 SSL 握手中,都有一个唯一的随机数来标记 SSL 握手。 这样防止了攻击者嗅探整个登录过程,获取到加密的登录数据之后,不对数据进行解密,而直接重传登录数据包的攻击手法。

HTTPS 的改进点在于创造性的使用了非对称加密算法,在不安全的网路上,安全的传输了用来进行非对称加密的密钥,综合利用了非对称加密的安全性和对称加密的快速性。

HTTP常用的状态码及含义

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ddwUyFXl-1659580889390)(F:\markdown笔记\面经\网络\Snipaste_2022-04-10_10-26-53.png)]

302和301
  • 301:(永久性转移)请求的网页已被永久移动到新位置。服务器返回此响应时,会自动将请求者转到新位置。
  • 302:(暂时性转移)服务器目前正从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。此代码与响应GET和HEAD请求的301代码类似,会自动将请求者转到不同的位置。

对于暂时重定向的A网址,请求后发现状态码是302,所以去请求B网址。第二次访问A的时候也是一样的流程
对于永久重定向的A网址,请求后发现状态码是301,所以去请求B网址。第二次访问A时直接请求B网址

forward和redirect
  • 直接转发方式(Forward) ,客户端和浏览器只发出一次请求,Servlet、HTML、JSP或其它信息资源,由第二个信息资源响应该请求,在请求对象request中,保存的对象对于每个信息资源是共享的。 forword是服务器内部的重定向,服务器直接访问目标地址的 url网址,把里面的东西读取出来,但是客户端并不知道,因此用forward的话,客户端浏览器的网址是不会发生变化的。相当于:“A找B借钱,B说没有,B去找C借,借到借不到都会把消息传递给A”;
  • 间接转发方式(Redirect) 实际是两次HTTP请求,服务器端在响应第一次请求的时候,让浏览器再向另外一个URL发出请求,从而达到转发的目的。 redirect是服务器根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,所以地址栏显示的是新的地址。相当于:“A找B借钱,B说没有,让A去找C借”。

forword 一般用于用户登录的时候,根据角色转发到相应的模块,redirect一般用于用户注销登录时返回主页面或者跳转到其他网站。forword效率高,而redirect效率低;forword转发是服务器上的行为,而redirect重定向是客户端的行为。

HTTP 常用的请求方式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9rurL16K-1659580889391)(F:\markdown笔记\面经\网络\Snipaste_2022-04-10_10-43-52.png)]

POST和GET

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QL1C3GWm-1659580889391)(F:\markdown笔记\面经\网络\645.webp)]

GET和POST本质上没有区别,GET/POST都是TCP链接。GET和POST能做的事情是一样的。要给GET加上request body,给POST带上url参数,技术上是完全行的通的。(大多数)浏览器通常都会限制url长度在2K个字节,而(大多数)服务器最多处理64K大小的url。超过的部分,恕不处理。如果你用GET服务,在request body偷偷藏了数据,不同服务器的处理方式也是不同的,有些服务器会帮你卸货,读出数据,有些服务器直接忽略。所以,虽然GET可以带request body,却不能保证一定能被接收到。

GET 方法参数在约定中,我们的参数是写在 ? 后面,用 & 分割。我们知道,解析报文的过程是通过获取 TCP 数据,用正则等工具从数据中获取 Header 和 Body,从而提取参数。比如header请求头中添加token,来验证用户是否登录等权限问题。也就是说,我们可以自己约定参数的写法,只要服务端能够解释出来就行,万变不离其宗。

有人说POST 比 GET 安全,因为数据在地址栏上不可见。然而,从传输的角度来说,他们都是不安全的,因为 HTTP 在网络上是明文传输的,只要在网络节点上抓包,就能完整地获取数据报文。其实,要想安全传输,就只有加密,也就是 HTTPS。

Get、Post请求发送的数据包有什么不同

大多数http post请求,都是一个tcp包发出去的,也就是不存在所谓的先发一个头,然后发body的。

大多数框架都是尽量在一个tcp包里面把HTTP请求发出去的,但是也确实存在先发HTTP头,然后发body的框架。但是具体发多少个TCP包,这个是代码的问题,是tcp协议栈的问题,跟HTTP协议没关系。

悖论GET产生一个TCP数据包;POST产生两个TCP数据包。

对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);

而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。

也就是说,GET只需要汽车跑一趟就把货送到了,而POST得跑两趟,第一趟,先去和服务器打个招呼“嗨,我等下要送一批货来,你们打开门迎接我”,然后再回头把货送过去。因为POST需要两步,时间上消耗的要多一点,看起来GET比POST更有效。

  1. GET与POST都有自己的语义,不能随便混用。

  2. 据研究,在网络环境好的情况下,发一次包的时间和发两次包的时间差别基本可以无视。而在网络环境差的情况下,两次包的TCP在验证数据包完整性上,有非常大的优点。

  3. 并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次。

HTTP协议无状态

当浏览器第一次发送请求给服务器时,服务器响应了;如果同个浏览器发起第二次请求给服务器时,它还是会响应,但是呢,服务器不知道就是刚才的那个浏览器。简言之,服务器不会去记住你是谁,所以是无状态协议。

有状态场景:

  • 小红:今天吃啥子?
  • 小明:罗非鱼~
  • 小红:味道怎么样呀?
  • 小明:还不错,好香。

无状态的场景:

  • 小红:今天吃啥子?
  • 小明:罗非鱼~
  • 小红:味道怎么样呀?
  • 小明:?啊?什么味道怎么样?

Http加了Cookie的话

  • 小红:今天吃啥子?
  • 小明:罗非鱼~
  • 小红:你今天吃的罗非鱼,味道怎么样呀?
  • 小明:还不错,好香。
Session和Cookie
  • Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。 但是cookie需要保存的数据太多,而这些信息其实已经保存到服务器了。
  • Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是Session,向用户返回session id。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。

Session 和Cookie的区别主要有这些:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sqJdndzU-1659580889392)(F:\markdown笔记\面经\网络\652.webp)]

来看个图吧:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5cQe16ri-1659580889392)(F:\markdown笔记\面经\网络\653.webp)]

  • 用户第一次请求服务器时,服务器根据用户提交的信息,创建对应的Session,请求返回时将此Session的唯一标识信息SessionID返回给浏览器,浏览器接收到服务器返回的SessionID信息后,会将此信息存入Cookie中,同时Cookie记录此SessionID是属于哪个域名。
  • 当用户第二次访问服务器时,请求会自动判断此域名下是否存在Cookie信息,如果存在,则自动将Cookie信息也发送给服务端,服务端会从Cookie中获取SessionID,再根据 SessionID查找对应的 Session信息,如果没有找到,说明用户没有登录或者登录失效,如果找到Session证明用户已经登录可执行后面操作。
session痛点

实际在生产上,为了保障高可用,一般服务器至少需要两台机器,通过负载均衡的方式来决定到底请求该打到哪台机器上。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cmRrXg6B-1659580889393)(F:\markdown笔记\面经\网络\743.webp)]

如图示:客户端请求后,由负载均衡器(如 Nginx)来决定到底打到哪台机器

假设登录请求打到了 A 机器,A 机器生成了 session 并在 cookie 里添加 sessionId 返回给了浏览器,那么问题来了:下次添加购物车时如果请求打到了 B 或者 C,由于 session 是在 A 机器生成的,此时的 B,C 是找不到 session 的,那么就会发生无法添加购物车的错误,就得重新登录了,此时请问该怎么办。主要有以下三种方式

1、session 复制

A 生成 session 后复制到 B, C,这样每台机器都有一份 session,无论添加购物车的请求打到哪台机器,由于 session 都能找到,故不会有问题,这种方式虽然可行,但缺点也很明显:

  1. 同一样的一份 session 保存了多份,数据冗余
  2. 如果节点少还好,但如果节点多的话,特别是像阿里,微信这种可能需要部署成千上万台机器,这样节点增多复制造成的性能消耗也会很大。

2、session 粘连

这种方式是让每个客户端请求只打到固定的一台机器上,比如浏览器登录请求打到 A 机器后,后续所有的添加购物车请求也都打到 A 机器上,支持按 ip 或 cookie 粘连等等

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OLI2Bqeu-1659580889393)(F:\markdown笔记\面经\网络\744.webp)]

这样的话每个 client 请求到达 Nginx 后,只要它的 ip 不变,根据 ip hash 算出来的值会打到固定的机器上,也就不存在 session 找不到的问题了,当然不难看出这种方式缺点也是很明显,对应的机器挂了怎么办?

3、session 共享

这种方式也是目前各大公司普遍采用的方案,将 session 保存在 redis,memcached 等中间件中,请求到来时,各个机器去这些中间件取一下 session 即可。缺点其实也不难发现,就是每个请求都要去 redis 取一下 session,多了一次内部连接,消耗了一点性能,另外为了保证 redis 的高可用,必须做集群,当然了对于大公司来说, redis 集群基本都会部署,所以这方案可以说是大公司的首选了。

JWT Token

通过在服务端共享 session 的方式可以完成用户的身份定位,但是不难发现也有一个小小的瑕疵:搞个校验机制还得搭个 redis 集群。对于小厂来说可能它的业务量还未达到用 redis 的程度,所以有没有其他不用 server 存储 session 的用户身份校验机制呢:token:用户登录服务器成功后,server 生成 token,客户端拿到 token 后会保存到本地,之后向 server 请求时在请求头带上此 token 即可。server 会有一套校验机制,校验这个 token 是否合法。token 本身携带 uid 信息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GWxMjzWC-1659580889393)(F:\markdown笔记\面经\网络\745.webp)]

token校验

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zU5UboA5-1659580889394)(F:\markdown笔记\面经\网络\746.webp)]

token 主要由三部分组成

  1. header:指定了签名算法
  2. payload:可以指定用户 id,过期时间等非敏感数据
  3. Signature: 签名,server 根据 header 知道它该用哪种签名算法,再用密钥根据此签名算法对 head + payload 带密钥哈希。这样一个 token 就生成了。

当 server 收到浏览器传过来的 token 时,它会首先取出 token 中的 header + payload,根据密钥哈希,然后再与 token 中的签名比对,如果成功则说明签名是合法的,即 token 是合法的。而且你会发现 payload 中存有我们的 userId,所以拿到 token 后直接在 payload 中就可获取 userid,避免了像 session 那样要从 redis 去取的开销。header, payload 实际上是以 base64 的形式存在的

只要 server 保证密钥不泄露,那么生成的 token 就是安全的,因为如果伪造 token 的话在签名验证环节是无法通过的,即可判定 token 非法。可以看到通过这种方式有效地避免了 token 必须保存在 server 的弊端,实现了分布式存储,不过需要注意的是,token若没有设置过期时间,则一旦由 server 生成,它就是有效的,除非在 server 为 token 设立一个黑名单,在校验 token 前先过一遍此黑名单,如果在黑名单里则此 token 失效,但一旦这样做的话,那就意味着黑名单就必须保存在 server,这又回到了 session 的模式。所以一般的做法是当客户端登出要让 token 失效时,直接在本地移除 token 即可,下次登录重新生成 token 就好。另外需要注意的是 token 一般是放在 header 的 Authorization 自定义头里,不是放在 Cookie 里的,这主要是为了解决跨域不能共享 Cookie 的问题。

若token泄露:可以使用ip校验、或者设置问题(以下哪个是你使用过的wifi、以下哪些是你的好友)再次校验合法性

token缺点

1、 token 太长

token 是 header, payload 编码后的样式,所以一般要比 sessionId 长很多,很有可能超出 cookie 的大小限制(cookie 一般有大小限制的,如 4kb),如果你在 token 中存储的信息越长,那么 token 本身也会越长,这样的话由于你每次请求都会带上 token,对请求来是个不小的负担

2、 不太安全

token的存储存在问题,另外,token 一旦生成无法让其失效,必须等到其过期才行,这样的话如果服务端检测到了一个安全威胁,也无法使相关的 token 失效。

  1. 存在 localStorage
  2. 保存在 sessionStorage
  3. 保存在 cookie
  4. 保存在 cookie 并设置 HttpOnly

第一种和第二种其实可以归为一类,这一类有个特点,就是该域内的 js 脚本都可以读取,这种情况下 JWT 通过 js 脚本放入 Header 里的 Authorization 字段,会存在 XSS 攻击风险。

没有标记 HttpOnly 的 cookie ,客户端可以将cookie中的 JWT 通过 js 脚本放入 Header 里的 Authorization 字段。服务端利用 header 里的 Authorization 去鉴权,因此这种方法有 XSS 攻击风险。

而第四种,加了 HttpOnly 标记,意味着这个 cookie 无法通过js脚本进行读取和修改,所以js 脚本无法利用 cookie 设置 header 的Authorization 字段,杜绝了 XSS 攻击的发生。所以服务器只能通过 cookie 里的 JWT 去鉴权,所以存在 CSRF 攻击风险。

浏览器地址栏输入url到显示主页

HTTP是一个基于TCP/IP协议来传递数据的超文本传输协议,传输的数据类型有HTML,图片等。

以访问百度为例子,Http请求过程

  1. 客户端进行DNS域名解析,得到对应的IP地址
  2. 根据这个IP,找到对应的服务器通过三次握手,建立TCP连接
  3. 建立TCP连接后,发起HTTP请求(一个完整的http请求报文)+cookies
  4. 服务器响应HTTP请求,返回网页内容,客户端得到html代码
  5. 客户端解析html代码,用html代码中的资源(如js,css,图片等等)渲染页面。
  6. 服务器关闭TCP连接,TCP四次挥手

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MPyEo1R6-1659580889394)(F:\markdown笔记\面经\网络\644.webp)]

URI和URL
  • URI,全称是Uniform Resource Identifier),中文翻译是统一资源标志符,主要作用是唯一标识一个资源
  • URL,全称是Uniform Resource Location),中文翻译是统一资源定位符,主要作用是提供资源的路径
  • URI像是身份证,可以唯一标识一个人,而URL更像一个住址,可以通过URL找到这个人。
HTTP/1.0,1.1,2.0
HTTP/1.0
  • 默认使用短连接,每次请求都需要建立一个TCP连接。 服务器完成请求处理后立即断开TCP连接,服务器不跟踪每个客户也不记录过去的请求 。可以设置Connection: keep-alive 字段,强制开启长连接。
  • 客户端必须等待上一次请求结果返回,才可以发出下一次请求 线头阻塞
  • 不支持文件断点续传
HTTP/1.1
  • 引入了持久连接,即TCP连接默认不关闭,可以被多个请求复用。

  • 客户端不用等待上一次请求结果返回,就可以发出下一次请求,但服务器端必须按照接收到客户端请求的先后顺序依次回送响应结果,以保证客户端能够区分出每次请求的响应内容 线头阻塞

  • 支持浏览器只发送header信息(不带任何body信息),如果服务器认为客户端有权限请求服务器,则返回100,客户端接收到100才开始把请求body发送到服务器;如果返回401未授权,客户端就可以不用发送请求body了,节约了带宽。

  • <code>RANGE:bytes=XXXX</code>
    

    表示要求服务器从文件XXXX字节处开始传送,这就是我们平时所说的断点续传!

  • 新增了24个错误状态响应码,如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除。

  • 消息主体会经过gzip压缩,但状态行和头部却没有经过任何压缩,直接以纯文本传输。

HTTP/2.0
  • HTTP/2在 应用层(HTTP/2)和传输层(TCP or UDP)之间增加一个二进制分帧层。在不改动 HTTP/1.x 的语义、方法、状态码、URI 以及首部字段的情况下, 解决了HTTP1.1 的性能限制,改进传输性能,实现低延迟和高吞吐量。在二进制分帧层中, HTTP/2 会将所有传输的信息分割为更小的消息和帧(frame),并对它们采用二进制格式的编码 ,其中 HTTP1.x 的首部信息会被封装到 HEADER frame,而相应的 Request Body 则封装到 DATA frame 里面。
  • HTTP/1.1并不支持 HTTP 首部压缩, HTTP/2 则使用了专门为首部压缩而设计的 HPACK 算法。
  • 完全多路复用,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,而且不用按照顺序一一对应。 每一个TCP连接中承载了多个双向流通的流,每一个流都有一个独一无二的标识和优先级,而流就是由二进制帧组成的。二进制帧的头部信息会标识自己属于哪一个流,所以这些帧是可以交错传输,然后在接收端通过帧头的信息组装成完整的数据。这样就解决了线头阻塞的问题,同时也提高了网络速度的利用率。
  • 服务端推送是一种在客户端请求之前发送数据的机制。在 HTTP/2 中,服务器可以对客户端的一个请求发送多个响应。

HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式较为多样,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,二进制分帧层,实现方便且健壮。

二进制和文本协议

其实无论是文本协议还是二进制协议,数据从a电脑传到b电脑的过程,传输的数据都是二进制的也就是0和1。

现在向服务端发送一条消息,内容是:Name=“xxl”,Age=22,Des=“贼帅贼帅的”

  1. 二进制协议的做法是:客户端告诉服务端协议的结构:比如客户端说:我给你发送的数据结构是:多长字符串的名字,int类型的年龄,多长字符串的Des,就按照这个结构解释得到的二进制数据就行。protobuf

  2. 文本协议的做法是:客户端不需要和服务端定什么结构,比如json:{Name:“xxl”,Age:22,Des:“贼帅贼帅的”},客户端会直接把这个变成二进制发过去(0和1),json被转化成二进制数据的时候,json自己根据拿到的文本数据做了结构,然后把这个结构的信息也变成二进制的数据发给服务器,只要服务器那边用json解析就可以了。

同一个数据转化成二进制协议的数据量相比文本协议的要小,因为不需要包含定义数据的结构信息。 二进制协议很方便使用异或 或者压缩的方式进行加密,防止协议被破解,从而保护了传递的信息,增加协议破解的难度。 对于每一条消息,因为无法自解释,所以对于每一条消息都必须要有对应的文档进行说明。文档和代码的一致性就显得很重要了。

文本协议的优点就是:不用去定义数据的传输结构,省下了开发时间。二进制协议和文本协议传输的都是二进制数据,只不过二进制协议需要自己制定结构,而文本协议不需要。 因为文本协议方便解读,所以如果不希望跟其他的程序共享通信协议,就最好不要采用文本协议。

对于公司内部的服务程序之间进行通信,采用二进制协议好一些。对于需要提供给外部的接口,提供文本格式的协议更好。

长连接

HTTP的长连接实质是指TCP的长连接。

HTTP长连接
  1. HTTP分为长连接和短连接,本质上说的是TCP的长短连接。TCP连接是一个双向的通道,它是可以保持一段时间不关闭的,因此TCP连接才具有真正的长连接和短连接这一说法。

  2. TCP长连接可以复用一个TCP连接,来发起多次的HTTP请求,这样就可以减少资源消耗,比如请求HTML,可能还需要请求后续的JS/CSS ,如果是短连接的话,需要进行多次tcp

  3. TCP的keepalive是侧重在保持客户端和服务端的连接,一方会不定期发送心跳包给另一方,没有断掉一方的定时发送几次心跳包。如果间隔发送几次,对方都返回的是RST,而不是ACK,那么就释放当前连接。

    HTTP的keep-alive一般我们都会带上中间的横杠,普通的HTTP连接是客户端连接上服务端,然后结束请求后,由客户端或者服务端进行http连接的关闭。下次再发送请求的时候,客户端再发起一个连接,传送数据,关闭连接。这么个流程反复。但是一旦客户端发送connection: keep-alive头给服务端,且服务端也接受这个keep-alive的话,这个连接就可以复用了。一个HTTP处理完之后,另外一个HTTP数据包也直接从这个连接发送。减少新建和断开TCP连接的消耗。

    二者的作用简单来说:

    HTTP协议的keep-alive意图在于短时间内连接复用,希望可以短时间内在同一个连接上进行多次请求/响应。TCP的KeepAlive机制意图在于保活、心跳、检测连接错误。当一个TCP连接两端长时间没有数据传输时(通常默认配置是2小时),发送keepalive探针,探测链接是否存活。TCP的keepalive是在ESTABLISHED状态的时候,双方如何检测连接的可用性。而HTTP的keep-alive说的是如何避免进行重复的TCP三次握手和四次挥手的环节。

设置长连接

通过在头部(请求和响应头)设置Connection字段指定为keep-alive,HTTP/1.0协议支持,但是是默认关闭的,从HTTP/1.1以后,连接默认都是长连接。

超时
  • HTTP一般会有httpd守护进程,里面可以设置keep-alive timeout,当tcp连接闲置超过这个时间就会关闭,也可以在HTTP的header里面设置超时时间。
  • TCP 的保活计时器 keep-alive包含三个参数,支持在系统内核的net.ipv4里面设置;当 TCP 连接之后,闲置了tcp_keepalive_time,则会发送侦测包,如果没有收到对方的ACK,那么会每隔 tcp_keepalive_intvl再发一次,直到发送了tcp_keepalive_probes,就会丢弃该连接。认为对方crash
保活计时器

TCP 有一个保活计时器(keepalive timer)。设想这样的场景:客户已主动与服务器建立了TCP连接。但后来客户端的主机突然发生故障。显然,服务器以后就不能再收到客户端发来的数据。因此,应当有措施使服务器不要再白白等待下去。这就需要使用保活计时器了。

服务器每收到一次客户的数据,就重新设置保活计时器,时间的设置通常是两个小时。若两个小时都没有收到客户端的数据,服务端就发送一个探测报文段,以后则每隔 75秒钟发送一次。若连续发送10个探测报文段后仍然无客户端的响应,服务端就认为客户端出了故障,接着就关闭这个连接。

CSRF攻击

什么是CSRF 攻击

CSRF,跨站请求伪造(英文全称是Cross-site request forgery),是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。

CSRF是如何攻击的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yHZgwEAA-1659580889395)(F:\markdown笔记\面经\网络\649.webp)]

受害者 Bob 在银行有一笔存款,通过对银行的网站发送请求 http://bank.example/withdraw?account=bob&amount=1000000&for=bob2 可以使 Bob 把 1000000 的存款转到 bob2 的账号下。通常情况下,该请求发送到网站后,服务器会先验证该请求是否是一个合法的 cookie,并且判断该 cookie的用户 Bob 是否已经成功登陆。 CRSF 是利用 cookie,而不是盗取 cookie。 用 cookie 做鉴权会有 CSRF 风险

黑客 Mallory 自己在该银行也有账户,他知道上文中的 URL 可以把钱进行转帐操作。Mallory 可以自己发送一个请求给银行:http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory。但是这个请求来自 Mallory 而非 Bob,没有bob的cookie,该请求不会起作用。

这时,Mallory 想到使用 CSRF 的攻击方式,他先自己做一个网站,在网站中放入如下代码: src=”http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory ”,并且通过广告等诱使 Bob 来访问他的网站。当 Bob 访问该网站时,上述 url 就会从 Bob 的浏览器发向银行,而这个请求会**默认附带 Bob 浏览器中的 cookie **一起发向银行服务器(但是攻击者无法直接窃取用户信息)。大多数情况下,该请求会失败,因为他要求 Bob 的认证信息。但是,如果 Bob 当时恰巧刚访问他的银行后不久,他的浏览器与银行网站之间的 cookie尚未过期,浏览器的 cookie之中含有 Bob 的认证信息。这时,悲剧发生了,这个 url 请求就会得到响应,钱将从 Bob 的账号转移到 Mallory 的账号,而 Bob 当时毫不知情。等以后 Bob 发现账户钱少了,即使他去银行查询日志,他也只能发现确实有一个来自于他本人的合法请求转移了资金,没有任何被攻击的痕迹。而 Mallory 则可以拿到钱后逍遥法外。

CSRF 攻击的根本原因在于**对于同样域名的每个请求来说,它的 cookie 都会被自动带上,**这个是浏览器的机制决定的,所以很多人据此认定 cookie 不安全。

解决CSRF攻击

(1) 验证码。应用程序和用户进行交互过程中,特别是账户交易这种核心步骤,强制用户输入验证码,才能完成最终请求。在通常情况下,验证码够很好地遏制CSRF攻击。但增加验证码降低了用户的体验,网站不能给所有的操作都加上验证码。所以只能将验证码作为一种辅助手段,在关键业务点设置验证码。

(2) Referer Check。HTTP Referer是header的一部分,当浏览器向web服务器发送请求时,一般会带上Referer信息告诉服务器是从哪个页面链接过来的,服务器籍此可以获得一些信息用于处理。可以通过检查请求的来源来防御CSRF攻击。正常请求的referer具有一定规律,如在提交表单的referer必定是在该页面发起的请求。所以通过检查http包头referer的值是不是这个页面,来判断是不是CSRF攻击。**但在某些情况下如从https跳转到http,浏览器处于安全考虑,不会发送referer,服务器就无法进行check了。**若与该网站同域的其他网站有XSS漏洞,那么攻击者可以在其他网站注入恶意脚本,受害者进入了此类同域的网址,也会遭受攻击。出于以上原因,无法完全依赖Referer Check作为防御CSRF的主要手段。但是可以通过Referer Check来监控CSRF攻击的发生。

CSRF 攻击之所以能够成功,是因为黑客可以完全伪造用户的请求,该请求中所有的用户验证信息都是存在于 cookie 中 .

(3) Anti CSRF Token。目前比较完善的解决方案是加入Anti-CSRF-Token,即发送请求时在HTTP 请求中以参数的形式加入一个随机产生的token,并在服务器建立一个拦截器来验证这个token。当用户访问表单页面时,服务器会生成一个随机的crsf字符串,并将token隐藏在 HTML 表单上,当用户提交数据时,若无此token或token不一致,就会提交失败。攻击者无法拿到随机的token,所以无法攻击。

(4) JSON Web Token 不存于 cookie 之中

XSS攻击

XSS,叫跨站脚本攻击(Cross-Site Scripting),它指的是恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的代码会被执行,从而达到恶意攻击用户的特殊目的。导致用户安全信息泄露(获取用户的敏感信息),危害数据安全。例如盗取各类用户帐号、网站挂马、盗窃企业重要信息等。

XSS主要分为两大类:非持久型攻击、持久型攻击。

  • 非持久型攻击(反射型XSS, DOM-based 型)
  • 持久型攻击(存储型XSS)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3iJyqVIk-1659580889395)(F:\markdown笔记\面经\网络\1fb7b3bcbf1648aa8e2ba9a8e76bab79.png)]

存储型 XSS 一般出现在网站留言、评论、博客日志等交互处,恶意脚本存储到客户端或者服务端的数据库中。

反射型 XSS 通常出现在网站的搜索栏、用户登录口等地方,常用来窃取客户端 Cookies 或进行钓鱼欺骗。

DOM-based 型

基于文档对象模型Document Objeet Model,DOM)的一种漏洞。DOM是一个与平台、编程语言无关的接口,它允许程序或脚本动态地访问和更新文档内容、结构和样式,处理后的结果能够成为显示页面的一部分。客户端的脚本程序可以通过DOM动态地检查和修改页面内容,它不依赖于提交数据到服务器端,而是直接从客户端获得DOM中的数据在本地执行,如果DOM中的数据没有经过严格确认,就会产生DOM—based XSS漏洞。

HTTP请求http://www.DBXSSed.site/welcome.html?name=zhangsan
使用以下的脚本打印出登录用户zhangsan的名字,即
<SCRIPT>
    var pos=docmnent.URL.indexOf("name=") + 5:
    document.write(document.URL.substring(pos,document.URL.1ength))< /SCRIPT>
如果这个脚本用于请求http://www.DBXSSed.site/wPJconle.html?name=<script>alert("XSS")</script>时,就会导致XSS攻击的发生。
解决XSS攻击问题
  1. 将用户输入的数据都进行转译,也就是将代码中的[<,>,”,&]等符号都进行转义。当这些html标签符号被转义后,浏览器就会拿它当作一个普通字符串对待,而不是当作一个标签的开始/结束标志对待。从而不会执行恶意代码。
  2. 不仅要验证数据的类型,还要验证其格式、长度、范围和内容。不仅在客户端做数据的验证与过滤,关键的过滤步骤在服务端进行。
  3. 对输出的数据也要检查,数据库里的值有可能会在一个大网站的多处都有输出,即使在输入做了编码等操作,在各处的输出点时也要进行安全检查。
  4. 在发布应用程序之前测试所有已知的威胁。

DoS、DDoS、DRDoS

  • DOS: (Denial of Service),翻译过来就是拒绝服务,最常见的DoS攻击就有计算机网络宽带攻击连通性攻击

  • DDoS: (Distributed Denial of Service),翻译过来是分布式拒绝服务。是指处于不同位置的多个攻击者同时向一个或几个目标发动攻击,或者一个攻击者控制了位于不同位置的多台机器并利用这些机器对受害者同时实施攻击。常见的DDos有SYN Flood、Ping of Death、UDP Flood等。

    Ping of Death

    许多操作系统的TCP/IP协议栈都规定ICMP包大小为64KB,且在对包的标题头进行读取之后,要根据该标题头里包含的信息来为有效载荷生成缓冲区。"PingofDeath"就是故意产生畸形的测试Ping(PacketInternetGroper)包,声称自己的尺寸超过ICMP上限,也就是加载的尺寸超过64KB上限,使未采取保护措施的网络系统出现内存分配错误,导致TCP/IP协议栈崩溃,最终接收方宕机。

    SYN Flood

    TCP(TransmissionControlProtocol)连接时,首先请求服务方发送一个SYN(SynchronizeSequenceNumber)消息,当服务方回复SYN-ACK确认消息后,请求方由于采用源地址欺骗等手段使得服务方收不到ACK回应,于是服务方会在一定时间处于等待接收请求方ACK消息的状态。而对于某台服务器来说,可用的TCP连接是有限的,因为他们只有有限的内存缓冲区用于创建连接,如果恶意攻击方快速连续地发送此类连接请求,该服务器可用的TCP连接队列将很快被阻塞,系统可用资源急剧减少,网络可用带宽迅速缩小,长此下去,服务器将无法向用户提供正常的合法服务。

    UDP Flood

    如今在Internet上UDP(用户数据包协议)的应用比较广泛,很多提供WWW和Mail等服务设备通常是使用Unix的服务器,它们默认打开一些被黑客恶意利用的UDP服务。如echo服务会显示接收到的每一个数据包,而原本作为测试功能的chargen服务会在收到每一个数据包时随机反馈一些字符。UDPflood假冒攻击就是利用这两个简单的TCP/IP服务的漏洞进行恶意攻击,通过伪造与某一主机的Chargen服务之间的一次的UDP连接,回复地址指向开着Echo服务的一台主机,通过将Chargen和Echo服务互指,来回传送毫无用处且占满带宽的垃圾数据,在两台主机之间生成足够多的无用数据流,这一拒绝服务攻击飞快地导致网络可用带宽耗尽。

  • DRDoS: (Distributed Reflection Denial of Service),中文是分布式反射拒绝服务,该方式靠的是发送大量带有被害者IP地址的数据包给攻击主机,然后攻击主机对IP地址源做出大量回应,从而形成拒绝服务攻击。

SQL注入

SQL注入是一种代码注入技术,一般被应用于攻击web应用程序。它通过在web应用接口传入一些特殊参数字符,来欺骗应用服务器,执行恶意的SQL命令,以达到非法获取系统信息的目的。它目前是黑客对数据库进行攻击的最常用手段之一。

SQL注入攻击

在web表单搜索框输入员工名字,然后后台查询出对应名字的员工。这种场景下,一般都是前端页面,把一个名字参数name传到后台,然后后台通过SQL把结果查询出来

name = "田螺"; // 前端传过来的SQL= "select * from staff where name=" + name; // 根据前端传过来的name参数,查询数据库员工表staff

因为SQL是直接拼接的,如果我们完全信任前端传的参数的话。假如前端传这么一个参数时'' or '1'='1',SQL就变成

select * from staff where name='' or '1'='1';

这个SQL会把所有的员工信息全都查出来了,请求用户已经越权啦。请求者可以获取所有员工的信息,信息已经泄露。

预防SQL注入问题

1). 不要暴露一些不必要的日志或者安全信息,比如避免直接响应一些sql异常信息。(防止攻击者知道使用的是什么数据库)

如果SQL发生异常了,不要把这些信息暴露响应给用户,可以自定义异常进行响应

2). 不相信任何外部输入参数,过滤参数中含有的一些数据库关键词关键词

可以加个参数校验过滤的方法,过滤 union,or 等数据库关键词

3). 适当的权限控制

在你查询信息时,先校验下当前用户是否有这个权限。比如说,实现代码的时候,可以让用户多传一个企业Id什么的,或者获取当前用户的session信息等,在查询前,先校验一下当前用户是否是这个企业下的等等,是的话才有这个查询员工的权限。

WebSocket与socket

  • Socket其实就是等于IP地址 + 端口 + 协议(tcp/udp)。 网络中的 Socket 并不是什么协议,而是为了使用 TCP,UDP 而抽象出来的一层 API,它是位于应用层和传输层之间的一个抽象层。具体来说,Socket是一套标准,它完成了对TCP/IP的高度封装(一套接口),屏蔽网络细节,以方便开发者更好地进行网络编程。Socket 是传输控制层的接口。用户可以通过 Socket 来操作底层 TCP/IP 协议族通信。 Socket是网编编程的标准接口

  • WebSocket,即 Web 浏览器与 Web 服务器之间全双工通信标准。位于OSI模型的应用层 。 客户端和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输 。在websocket出现之前,开发实时web应用的方式为轮询,不停地向服务器发送 HTTP 请求,问有没有数据,有数据的话服务器就用响应报文回应。如果轮询的频率比较高,那么就可以近似地实现“实时通信”的效果。轮询的缺点也很明显,反复发送无效查询请求耗费了大量的带宽和 CPU资源。WebSocket 是长轮询。具体比如在一个电商场景,商品的库存可能会变化,所以需要及时反映给用户,所以客户端会不停的发请求,然后服务器端会不停的去查变化,不管变不变,都返回,这个是短轮询。而长轮询则表现为如果没有变,就不返回,而是等待变或者超时(一般是十几秒)才返回,如果没有返回,客户端也不需要一直发请求,所以减少了双方的压力。 定义了ws://以及wss://模式来分别表示WebSocket和安全WebSocket连接 使用场景:需要网络传输的实时更新和连续数据流应用,实时应用程序

    websocket分为握手和数据传输两部分,其中握手使用了http进行。 在顺利握手后, 服务器端返回101切换协议, 更新为应用层协议websocket,并在当前的套接字上应用新的协议。 开始websocket的数据帧协议,实现客户端与服务器的数据交换。

TCP和UDP

UDP

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wpN9ha5R-1659580889395)(F:\markdown笔记\面经\网络\78310a55b319ebc4c57a3f358c26cffc1e17161f.webp)]

基于UDP的应用层协议
  • DNS : Domain Name Service (域名服务),默认端口 53
  • TFTP: Trivial File Transfer Protocol (简单文件传输协议),默认端口69
UDP实现可靠传输

QUIC(Quick UDP Internet Connections)基于UDP的传输层协议,提供像TCP一样的可靠性。在提高web应用性能上,可以选择在应用层使用HTTP2.0实现多路传输 。 基于 QUIC 承载的 HTTP 协议进一步被标准化为 HTTP3.0。

QUIC 协议组成

QUIC 的 packet 除了个别报文比如 PUBLIC_RESET 和 CHLO,所有报文头部都是经过认证的,报文 Body 都是经过加密的。这样只要对 QUIC 报文任何修改,接收端都能够及时发现,有效地降低了安全风险。红色部分是 Stream Frame 的报文头部,有认证。绿色部分是报文内容,全部经过加密。

img

  • Flags: 用于表示 Connection ID 长度、Packet Number 长度等信息;
  • Connection ID:客户端随机选择的最大长度为 64 位的无符号整数。但是,长度可以协商;
  • QUIC Version:QUIC 协议的版本号,32 位的可选字段。如果 Public Flag & FLAG_VERSION != 0,这个字段必填。客户端设置 Public Flag 中的 Bit0 为 1,并且填写期望的版本号。如果客户端期望的版本号服务端不支持,服务端设置 Public Flag 中的 Bit0 为 1,并且在该字段中列出服务端支持的协议版本(0 或者多个),并且该字段后不能有任何报文;
  • Packet Number:长度取决于 Public Flag 中 Bit4 及 Bit5 两位的值,最大长度 6 字节。发送端在每个普通报文中设置 Packet Number。发送端发送的第一个包的序列号是 1,随后的数据包中的序列号的都大于前一个包中的序列号;
  • Stream ID:用于标识当前数据流属于哪个资源请求;
  • Offset:标识当前数据包在当前 Stream ID 中的字节偏移量。

QUIC 报文的大小需要满足路径 MTU 的大小以避免被分片。QUIC 在 IPV6 下的最大报文长度为 1350,IPV4 下的最大报文长度为 1370。

连接重连
tcp的连接重连之痛

一条 TCP 连接是由四元组标识的(源 IP,源端口,目的 IP,目的端口)。当其中任何一个元素发生变化时,这条连接就会失效需要重新连接。我们需要他依然维持着,能够保持业务逻辑不中断。这里面主要关注的是客户端的变化,因为客户端不可控并且网络环境经常发生变化,而服务端的 IP 和端口一般都是固定的。比如使用手机在 WIFI 和 4G 移动网络切换时,客户端的 IP 肯定会发生变化,需要重新建立和服务端的 TCP 连接。又比如大家使用公共 NAT 出口时,有些连接竞争时需要重新绑定端口,导致客户端的端口发生变化,同样需要重新建立 TCP 连接。

基于UDP的QUIC的连接迁移实现

当用户的地址发生变化时,如 WIFI 切换到 4G 场景,基于 TCP 的 HTTP 协议无法保持连接的存活。QUIC 基于连接ID唯一识别连接。当源地址发生改变时,QUIC 仍然可以保证连接存活和数据正常收发。QUIC 是基于 UDP 协议的,任何一条 QUIC 连接不再以IP及端口四元组标识,而是以一个64位的随机数作为 ID 来标识,这样就算IP或者端口发生变化时,只要 ID 不变,这条连接依然维持着,上层业务逻辑感知不到变化,不会中断,也就不需要重连。由于这个 ID 是客户端随机产生的,并且长度有 64 位,所以冲突概率非常低。

低连接延时
TLS 的连接时延问题

以一次简单的浏览器访问为例,在地址栏中输入https://www.abc.com,实际会产生以下动作:

  1. DNS 递归查询 www.abc.com,获取地址解析的对应 IP;
  2. TCP 握手,我们熟悉的 TCP 三次握手需要需要 1.5 个 RTT;
  3. TLS 握手,以目前应用最广泛的 TLS 1.2 而言,需要 2 个 RTT。对于非首次建连,可以选择启用会话重用,则可缩小握手时间到 1 个 RTT;
  4. HTTP 业务数据交互,假设 abc.com 的数据在一次交互就能取回来。那么业务数据的交互需要 1 个 RTT;经过上面的过程分析可知,要完成一次简短的 HTTPS 业务数据交互,需要经历:新连接 3RTT + DNS;会话重用 2RTT + DNS。

所以,对于数据量小的请求而言,单一次的请求握手就占用了大量的时间,对于用户体验的影响非常大。同时,在用户网络不佳的情况下,RTT 延时会变得较高,极其影响用户体验。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Sn4ctQGq-1659580889396)(F:\markdown笔记\面经\网络\20200217141825874.png)]

真0-RTT的QUIC握手

QUIC 由于基于 UDP,无需 TCP 连接,在最好情况下,短连接下 QUIC 可以做到 0RTT 开启数据传输。 所谓的0RTT就是,通信双方发起通信连接时,第一个数据包便可以携带有效的业务数据。 对于 RTT 敏感的业务,QUIC 可以有效的降低连接建立延迟。究其原因一方面是 TCP 和 TLS 分层设计导致的:分层的设计需要每个逻辑层次分别建立自己的连接状态。另一方面是 TLS 的握手阶段复杂的密钥协商机制导致的。要降低建连耗时,需要从这两方面着手。 对于QUIC协议,客户端第一次建连的握手协商需1-RTT,而已建连的客户端重新建连可以使用之前协商好的缓存信息来恢复TLS连接,仅需0-RTT时间。 由于 QUIC 的握手是基于 TLS1.3 实现的,所以首次建立连接时也是需要 1 次 RTT .

(1)客户端:生成随机数 a,选择公开的大数 G 和 P,计算 A=a*G%P,将 A 和 G 发送给服务器,也就是 Client Hello 消息

(2)服务器:生成随机数 b,计算 B=b*G%P,将 B 发送给客户端,也就是 Server Hello 消息

(3)客户端:使用 ECDH 算法生成通信密钥 KEY = a*B = a*b*G%P

(4)服务器:使用 ECDH 算法生成通信密钥 KEY = b*A = b*a*G%P

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RvIOREAL-1659580889396)(F:\markdown笔记\面经\网络\20200618193517905.png)]

  1. 客户端缓存了 ServerConfig(B=b*G%P),下次建连直接使用缓存数据计算通信密钥

  2. (1)客户端:生成随机数 c,选择公开的大数 G 和 P,计算 A=c*G%P,将 A 和 G 发送给服务器,也就是 Client Hello 消息

    (2)客户端:客户端直接使用缓存的 ServerConfig 计算通信密钥 KEY = c*B = c*b*G%P,加密发送应用数据

    (3)服务器:根据 Client Hello 消息计算通信密钥 KEY = b*A = b*c*G%P

  3. 一旦服务器的随机数 b(私钥)泄漏了,那之前通信的所有数据就都可以破解了。为了解决这个问题,需要为每次会话都创建一个新的通信密钥,来保证前向安全性,前向安全:是指用来产生会话密钥的长期密钥泄露出去,不会泄漏以前的通讯内容。

    (1)客户端:生成随机数 a,选择公开的大数 G 和 P,计算 A=a*G%P,将 A 和 G 发送给服务器,也就是 Client Hello 消息

    (2)客户端:客户端直接使用缓存的 ServerConfig 计算初始密钥 initKey = a*B = a*b*G%P,加密发送应用数据 1

    (3)服务器:根据 Client Hello 消息计算初始密钥 initKey = b*A = b*a*G%P

    (4)服务器:生成随机数 c,计算 C=c*G%P,使用 initKey 加密 C,发送给客户端,也就是 Server Hello 消息

    (5)客户端:使用 initKey 解码获取 C,计算会话密钥 sessionKey = a*C = a*c*G%P,加密发送应用数据 2

    (6)服务器:计算会话密钥 sessionKey = c*A = c*a*G%P,解密获取应用数据 2

可自定义的拥塞控制

Quic 使用可插拔的拥塞控制,相较于 TCP,它能提供更丰富的拥塞控制信息。比如对于每一个包,不管是原始包还是重传包,都带有一个新的序列号(seq),这使得 Quic 能够区分 ACK 是重传包还是原始包,从而避免了 TCP 重传模糊的问题。Quic 同时还带有收到数据包与发出 ACK 之间的时延信息。这些信息能够帮助更精确的计算 rtt。QUIC 的传输控制不再依赖内核的拥塞控制算法,而是实现在应用层上,这意味着我们根据不同的业务场景,实现和配置不同的拥塞控制算法以及参数。

无队头阻塞
TCP 的队头阻塞问题

虽然 HTTP2 实现了多路复用,但是因为其基于面向字节流的 TCP,因此一旦丢包,将会影响多路复用下的所有请求流。QUIC 基于 UDP,在设计上就解决了队头阻塞问题。TCP 队头阻塞的主要原因是数据包超时确认或丢失阻塞了当前窗口向右滑动,我们最容易想到的解决队头阻塞的方案是不让超时确认或丢失的数据包将当前窗口阻塞在原地。QUIC 也正是采用上述方案来解决 TCP 队头阻塞问题的。TCP 为了保证可靠性,使用了基于字节序号的 Sequence Number 及 Ack 来确认消息的有序到达。

img

如上图,应用层可以顺利读取 stream1 中的内容,但由于 stream2 中的第三个 segment 发生了丢包,TCP 为了保证数据的可靠性,需要发送端重传第 3 个 segment 才能通知应用层读取接下去的数据。所以即使 stream3 stream4 的内容已顺利抵达,应用层仍然无法读取,只能等待 stream2 中丢失的包进行重传。在弱网环境下,HTTP2 的队头阻塞问题在用户体验上极为糟糕。

QUIC 的无队头阻塞解决方案

QUIC 同样是一个可靠的协议,它使用 Packet Number 代替了 TCP 的 Sequence Number,并且每个 Packet Number 都严格递增,也就是说就算 Packet N 丢失了,重传的 Packet N 的 Packet Number 已经不是 N,而是一个比 N 大的值,比如 Packet N+M。

QUIC 使用的 Packet Number 单调递增的设计,可以让数据包不再像 TCP 那样必须有序确认,QUIC 支持乱序确认,当数据包 Packet N 丢失后,只要有新的已接收数据包确认,当前窗口就会继续向右滑动。待发送端获知数据包 Packet N 丢失后,会将需要重传的数据包放到待发送队列,重新编号比如数据包 Packet N+M 后重新发送给接收端,对重传数据包的处理跟发送新的数据包类似,这样就不会因为丢包重传将当前窗口阻塞在原地,从而解决了队头阻塞问题。那么,既然重传数据包的 Packet N+M 与丢失数据包的 Packet N 编号并不一致,我们怎么确定这两个数据包的内容一样呢?QUIC 使用 Stream ID 来标识当前数据流属于哪个资源请求,这同时也是数据包多路复用传输到接收端后能正常组装的依据。重传的数据包 Packet N+M 和丢失的数据包 Packet N 单靠 Stream ID 的比对一致仍然不能判断两个数据包内容一致,还需要再新增一个字段 Stream Offset,标识当前数据包在当前 Stream ID 中的字节偏移量。有了 Stream Offset 字段信息,属于同一个 Stream ID 的数据包也可以乱序传输了(HTTP/2 中仅靠 Stream ID 标识,要求同属于一个 Stream ID 的数据帧必须有序传输),通过两个数据包的 Stream ID 与 Stream Offset 都一致,就说明这两个数据包的内容一致。

img

TCP
基于TCP的应用层协议
  • HTTP:HyperText Transfer Protocol(超文本传输协议),默认端口80
  • FTP: File Transfer Protocol (文件传输协议), 默认端口(20用于传输数据,21用于传输控制信息)
  • SMTP: Simple Mail Transfer Protocol (简单邮件传输协议) ,默认端口25
  • TELNET: Teletype over the Network (网络电传), 默认端口23
  • SSH:Secure Shell(安全外壳协议),默认端口 22
TCP三次握手

TCP提供可靠的连接服务,连接是通过三次握手进行初始化的。三次握手的目的就是同步连接双方的序列号和确认号并交换TCP窗口大小信息。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1TID6uz1-1659580889397)(F:\markdown笔记\面经\网络\Snipaste_2022-04-10_16-29-07.png)]

  • 第一次握手(SYN=1, seq=x),发送完毕后,客户端就进入SYN_SEND状态
  • 第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1), 发送完毕后,服务器端就进入SYN_RCV状态。
  • 第三次握手(ACK=1,ACKnum=y+1),发送完毕后,客户端进入ESTABLISHED状态,当服务器端接收到这个包时,也从LISTEN进入ESTABLISHED状态。
半连接队列和 SYN Flood攻击

TCP进入三次握手前,服务端会从CLOSED状态变为LISTEN状态,同时在内部创建了两个队列:半连接队列(SYN队列)和全连接队列(ACCEPT队列)。

  • TCP三次握手时,客户端发送SYN到服务端,服务端收到之后,便回复ACK和SYN,状态由LISTEN变为SYN_RCVD,此时这个连接就被推入了SYN队列,即半连接队列。
  • 当客户端回复ACK, 服务端接收后,三次握手就完成了。这时连接会等待被具体的应用取走,在被取走之前,它被推入ACCEPT队列,即全连接队列。

SYN Flood是一种典型的DDos攻击,它在短时间内,伪造不存在的IP地址,向服务器大量发起SYN报文。当服务器回复SYN+ACK报文后,不会收到ACK回应报文,导致服务器上建立大量的半连接,半连接队列满了,这就无法处理正常的TCP请求啦。

syn cookieSYN Proxy防火墙

  • syn cookie:在收到SYN包后,服务器根据一定的方法,以数据包的源地址、端口等信息为参数计算出一个cookie值作为自己的SYN ACK包的序列号,回复SYN+ACK后,服务器并不立即分配资源进行处理,等收到发送方的ACK包后,重新根据数据包的源地址、端口计算该包中的确认序列号是否正确,如果正确则建立连接,否则丢弃该包。
  • SYN Proxy防火墙:服务器防火墙会对收到的每一个SYN报文进行代理和回应,并保持半连接。等发送方将ACK包返回后,再重新构造SYN包发到服务器,建立真正的TCP连接。(半连接由防火墙代劳)
为什么是三次

第一次握手 是客户端告诉服务器·我要和你连接·,第二次是服务器端告诉客户端·知道了,我也要和你进行连接·,第三次是客户端回复服务器·知道了·

为什么握手不能是两次呢?

如果只有两次握手,服务器端可能就不知道客户端的回复,无法确认客户端的接收能力。

为什么握手不能是四次呢?

四次以上都可以,只不过 三次就够了

TCP的粘包和拆包

TCP是面向流,没有界限的一串数据。TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可能会被TCP拆分成多个包进行发送也有可能把多个小的包封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oBgydnlN-1659580889397)(F:\markdown笔记\面经\网络\659.webp)]

为什么会产生粘包和拆包呢?

  • 要发送的数据小于TCP发送缓冲区的大小,TCP将多次写入缓冲区的数据一次发送出去,将会发生粘包;
  • 接收数据端的应用层没有及时读取接收缓冲区中的数据,将发生粘包;
  • 要发送的数据大于TCP发送缓冲区剩余空间大小,将会发生拆包;
  • 待发送数据大于MSS(最大报文长度),TCP在传输前将进行拆包。即TCP报文长度-TCP头部长度>MSS。

解决方案:

  • 发送端将每个数据包封装为固定长度,接收端根据固定长度拆包
  • 在数据尾部增加特殊字符进行分割,数据包之间设置边界
  • 将数据分为两部分,一部分是头部,一部分是内容体;其中头部结构大小固定,且有一个字段声明内容体的大小。
TCP的流量控制

TCP三次握手后,发送端和接收端进入到ESTABLISHED状态,就可以愉快地传输数据啦。TCP 发送一个数据,需要收到确认应答,才会发送下一个数据。这样的话就会有个缺点:效率会比较低。为了解决这个问题,TCP引入了窗口,它是操作系统开辟的一个缓存空间。窗口大小值表示无需等待确认应答,还可以继续发送数据的最大值。

滑动窗口

TCP头部有个字段叫win,它告诉对方本端的TCP接收缓冲区还能容纳多少字节的数据,这样对方就可以控制发送数据的速度,从而达到流量控制的目的。通俗点讲,就是接受方每次收到数据包,在发送确认报文的时候,同时告诉发送方,自己的缓存区还有多少空余空间,缓冲区的空余空间,我们就称之为接受窗口大小。这就是win。

TCP 滑动窗口分为两种: 发送窗口和接收窗口。发送端的滑动窗口包含四大部分,如下:

  • 已发送且已收到ACK确认
  • 已发送但未收到ACK确认
  • 未发送但可以发送
  • 未发送也不可以发送

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AObgN8sZ-1659580889398)(F:\markdown笔记\面经\网络\Snipaste_2022-04-19_21-21-57.png)]

  • 虚线矩形框,就是发送窗口。
  • SND.WND: 表示发送窗口的大小,上图虚线框的格子数是14个,即发送窗口大小是14。
  • SND.NXT:下一个发送的位置,它指向未发送但可以发送的第一个字节的序列号。
  • SND.UNA: 一个绝对指针,它指向的是已发送但未确认的第一个字节的序列号。

接收方的滑动窗口包含三大部分,如下:

  • 已成功接收并确认
  • 未收到数据但可以接收
  • 未收到数据并不可以接收的数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8w4zdlG8-1659580889398)(F:\markdown笔记\面经\网络\663.webp)]

  • 虚线矩形框,就是接收窗口。
  • REV.WND: 表示接收窗口的大小,上图虚线框的格子就是9个。
  • REV.NXT:下一个接收的位置,它指向未收到但可以接收的第一个字节的序列号。

但是发送端不能疯狂地向接收端发送数据,因为接收端接收不过来的话,接收方只能把处理不过来的数据存在缓存区里。如果缓存区都满了,发送方还在疯狂发送数据的话,接收方只能把收到的数据包丢掉,这就浪费了网络资源啦。TCP 提供一种机制可以让发送端根据接收端的实际接收能力控制发送的数据量,这就是流量控制。TCP通过滑动窗口来控制流量,首先双方三次握手,初始化各自的窗口大小,均为 400 个字节。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TGJDDbE3-1659580889399)(F:\markdown笔记\面经\网络\660.webp)]

TCP的流量控制

  1. 假如当前发送方给接收方发送了200个字节,那么,发送方的SND.NXT会右移200个字节,也就是说当前的可用窗口减少了200 个字节。
  2. 接受方收到后,放到缓冲队列里面,REV.WND =400-200=200字节,所以win=200字节返回给发送方。接收方会在 ACK 的报文首部带上缩小后的滑动窗口200字节
  3. 发送方又发送200字节过来,200字节到达,继续放到缓冲队列。不过这时候,由于大量负载的原因,接受方处理不了这么多字节,只能处理100字节,剩余的100字节继续放到缓冲队列。这时候,REV.WND = 400-200-100=100字节,即win=100返回发送方。
  4. 发送方继续干活,发送100字节过来,这时候,接受窗口win变为0。
  5. 发送方停止发送,开启一个定时任务,每隔一段时间,就去询问接受方,直到win大于0,才继续开始发送。
TCP的拥塞控制

拥塞控制是作用于网络的,防止过多的数据包注入到网络中,避免出现网络负载过大的情况。它的目标主要是最大化利用网络上瓶颈链路的带宽。流量控制是作用于接收者的,根据接收端的实际接收能力控制发送速度,防止分组丢失的。发送方维护一个拥塞窗口cwnd(congestion window) 的变量,用来估算在一段时间内网络的拥塞程度,并且是动态变化的。

只要网络中没有出现拥塞,拥塞窗口的值就可以再增大一些,以便把更多的数据包发送出去,但只要网络出现拥塞,拥塞窗口的值就应该减小一些,以减少注入到网络中的数据包数。其实只要「发送⽅」没有在规定时间内接收到 ACK 应答报⽂,也就是发⽣了超时重传,就会认为⽹络出现了拥塞

慢启动算法

慢启动算法,表面意思就是,别急慢慢来。它表示TCP建立连接完成后,一开始不要发送大量的数据,而是先探测一下网络的拥塞程度。由小到大逐渐增加拥塞窗口的大小,如果没有出现丢包,当发送⽅每收到⼀个 ACK,拥塞窗⼝cwnd的⼤⼩就会加1。

  • TCP连接完成,初始化cwnd = 1,表明可以传一个MSS单位大小的数据。
  • 当收到⼀个 ACK 确认应答后,cwnd 增加 1,于是⼀次能够发送 2 个 ,当收到 2 个的 ACK 确认应答后, cwnd 增加 2,于是就可以⽐之前多发2 个,所以这⼀次能够发送 4 个 ,当这 4 个的 ACK 确认到来的时候,每个确认 cwnd 增加 1, 4 个确认 cwnd 增加 4,于是就可以⽐之前多发4 个,所以这⼀次能够发送 8 个。
  • 可以看出慢启动算法,发包的个数是指数性的增⻓

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eiDRblgB-1659580889399)(F:\markdown笔记\面经\网络\665.webp)]

为了防止cwnd增长过大引起网络拥塞,还需设置一个慢启动阀值ssthresh(slow start threshold)状态变量。当cwnd >ssthresh时,进入拥塞避免算法。

拥塞避免算法

一般来说,慢启动阀值ssthresh是65535字节,cwnd到达慢启动阀值

  • 每收到一个ACK时,cwnd = cwnd + 1/cwnd 每当收到⼀个ACK 时,cwnd 增加1/cwnd。

显然这是一个线性上升的算法,避免过快导致网络拥塞问题。当16个 ACK 应答确认到来时,每个确认增加 1/16,16 个 ACK 确认 cwnd ⼀共增加 1,于是这⼀次能够发送 17个 MSS ⼤⼩的数据,变成了线性增⻓。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QsgNFa0c-1659580889400)(F:\markdown笔记\面经\网络\666.webp)]

拥塞避免算法就是将原本慢启动算法的指数增⻓变成了线性增⻓,还是增⻓阶段,但是增⻓速度缓慢了⼀些。 就这么⼀直增⻓着后,⽹络就会慢慢进⼊了拥塞的状况了,于是就会出现丢包现象,这时就需要对丢失的数据包进⾏重传。当触发了重传机制,也就进⼊了「拥塞发⽣算法」。

拥塞发生

当网络拥塞发生丢包时,会有两种情况:

  • RTO超时重传
  • 快速重传

超时重传,其原理是在发送某一个数据以后就开启一个计时器,在一定时间内如果没有得到发送的数据报的ACK报文,那么就重新发送数据,直到发送成功为止。如果是发生了RTO超时重传,就会使用拥塞发生算法

  • 慢启动阀值sshthresh = cwnd /2
  • cwnd 重置为 1
  • 进入新的慢启动过程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1olV5kFr-1659580889400)(F:\markdown笔记\面经\网络\667.webp)]

这个拥塞发生算法太过于激进。

其实还有更好的处理方式,就是快速恢复算法,快速重传不以时间驱动,而是以数据驱动。它是基于接收端的反馈信息来引发重传的。发送方收到3个连续重复的ACK时,就会快速地重传,使用快速恢复算法,不必等待RTO超时后使用拥塞发生算法。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iIzDZTZC-1659580889401)(F:\markdown笔记\面经\网络\668.webp)]

快速恢复

快速重传和快速恢复算法一般同时使用。快速恢复算法认为,还有3个重复ACK收到,说明网络也没那么糟糕,所以没有必要像RTO超时那么强烈。进入快速恢复之前,cwnd 和 sshthresh已被更新:

cwnd = cwnd /2
sshthresh = cwnd

然后,真正的快速算法如下:

  • cwnd = sshthresh + 3 3 的意思是确认有 3 个数据包被收到了
  • 重传重复的那几个ACK(即丢失的那几个数据包)
  • 如果再收到重复的 ACK,那么 cwnd = cwnd +1
  • 如果收到新数据的 ACK 后, cwnd = sshthresh。因为收到新数据的 ACK,表明恢复过程已经结束,可以再次进入拥塞避免的算法了。
Nagle 算法与延迟确认
Nagle算法

如果发送方疯狂地向接收方发送很小的数据包,比如一次就发送1个字节,那么显然会有问题。TCP/IP协议中,无论发送多少数据,总是需要在数据前面加上协议头,同时,对方接收到数据,也需要发送ACK表示确认。为了尽可能的利用网络带宽,TCP总是希望尽可能的发送足够大的数据。Nagle算法就是为了尽可能发送大块数据,避免网络中充斥着许多小数据块。

Nagle算法:任意时刻,最多只能有一个未被确认的小段。所谓“小段”,指的是小于MSS尺寸的数据块,所谓“未被确认”,是指一个数据块发送出去后,没有收到对方发送的ACK确认该数据已收到。

Nagle算法的实现规则:

  • 如果包长度达到MSS,则允许发送;
  • 如果该包含有FIN,则允许发送;
  • 设置了TCP_NODELAY选项,则允许发送;
  • 未设置TCP_CORK选项时,若所有发出去的小数据包(包长度小于MSS)均被确认,则允许发送;
  • 上述条件都未满足,但发生了超时(一般为200ms),则立即发送。
延迟确认

如果接受方刚接收到发送方的数据包,在很短很短的时间内,又接收到第二个包。那么请问接收方是一个一个地回复好点,还是合在一起回复好呢?

接收方收到数据包后,如果暂时没有数据要发给对端,它可以等一小段时间,再确认(Linux上默认是40ms)。如果这段时间刚好有数据要传给对端,ACK就随着数据传输,而不需要单独发送一次ACK。如果超过时间还没有数据要发送,也发送ACK,避免对端以为丢包。

但是有些场景不能用延迟确认,比如发现了乱序包、需要调整窗口大小等。一般情况下,Nagle算法和延迟确认不能一起使用,Nagle算法意味着延迟发,延迟确认意味着延迟接收,会造成更大的延迟,会产生性能问题。

捎带应答

在一个 TCP 包中既发送数据又发送确认应答的一种机制,由此,网络利用率会提高,计算机的负荷也会减轻,但是这种应答必须等到应用处理完数据并将作为回执的数据返回为止。

TCP的重传机制
超时重传

超时重传,是TCP协议保证数据可靠性的另一个重要机制,其原理是在发送某一个数据以后就开启一个计时器,在一定时间内如果没有得到发送的数据报的ACK报文,那么就重新发送数据,直到发送成功为止。这个一定时间内,一般是多少比较合理呢?来看下什么叫RTT(Round-Trip Time,往返时间)。RTT就是数据完全发送完,到收到确认信号的时间,即数据包的一次往返时间。超时重传时间,就是RTO(Retransmission Timeout)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I9uBmJqo-1659580889401)(F:\markdown笔记\面经\网络\671.webp)]

那么,RTO到底设置多大呢?

  • 如果RTO设置很大,等了很久都没重发,这样肯定就不行。
  • 如果RTO设置很小,那很可能数据都没有丢失,就开始重发了,这会导致网络阻塞,从而恶性循环,导致更多的超时出现。

一般来说,RTO略微大于RTT,效果是最佳的。其实,RTO有个标准方法的计算公式,也叫Jacobson / Karels 算法。一起来看下吧:

1. 首先计算SRTT(即计算平滑的RTT)

SRTT = (1 - α) * SRTT + α * RTT //求 SRTT 的加权平均

2. 其次,计算RTTVAR (round-trip time variation)

RTTVAR = (1 - β) * RTTVAR + β * (|RTT - SRTT|) //计算 SRTT 与真实值的差距

3. 最后,得出最终的RTO

RTO = µ * SRTT + ∂ * RTTVAR = SRTT + 4·RTTVAR

一般情况,α、β等的参数取值如下:

α = 0.125,β = 0.25, μ = 1,∂ = 4

别问这些参数是怎么来的,它们是大量实践,调出的最优参数。

超时重传不是十分完美的重传方案,它有这些缺点:

  • 当一个报文丢失时,会等待一定的超时周期,才重传分组,增加了端到端的时延。
  • 当一个报文丢失时,在其等待超时的过程中,可能会出现这种情况:其后的报文段已经被接收端接收但却迟迟得不到确认,发送端会认为也丢失了,从而引起不必要的重传,既浪费资源也浪费时间。

并且,对于TCP,如果发生一次超时重传,时间间隔下次就会加倍。

快速重传

可以使用快速重传,来解决超时重发的时间等待问题。它不以时间驱动,而是以数据驱动。它是基于接收端的反馈信息来引发重传的。快速重传流程如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1vLTaYFI-1659580889401)(F:\markdown笔记\面经\网络\672.webp)]

发送方发送了 1,2,3,4,5,6份数据:

  • 第一份 Seq=1 先送到了,于是就 Ack回2;
  • 第二份 Seq=2 也送到了,于是ACK回3;
  • 第三份 Seq=3 由于网络等某些原因,没送到;
  • 第四份 Seq=4 送到了,但是由于Seq=3没收到。因此ACK还是回3;
  • 后面的 Seq=5,6的也送到了,ACK还是回复3,因为Seq=3没有收到。
  • 发送方连着收到三个重复冗余ACK=3的确认(其实是4个哈,但是因为前面的一个是正常的ACK,后面三个才是重复冗余的),于是知道3报文段在传输过程中丢失了;发送方在定时器过期之前,重传该报文段。
  • 最后,接收方收到了 Seq=3,此时因为 Seq=4,5,6都收到了,于是它回ACK=7。

但是呢,快速重传也可能有问题:ACK只向告知发送方,最大的有序报文段。到底是哪个报文丢失了呢?并不确定!那到底该重传多少个包呢?

是重传 Seq=3 ?还是重传 Seq=3、Seq=4、Seq=5、Seq=6 呢?因为发送端并不清楚这三个连续的 ACK=3 是谁传回来的。

带选择确认的重传(SACK)

为了解决:应该重传多少个包的问题? TCP提供了带选择确认的重传(即SACK,Selective Acknowledgment)。

SACK机制就是,在快速重传的基础上,接收方返回最近收到报文段的序列号范围,这样发送方就知道接收方哪些数据包是没收到的。这样就很清楚应该重传哪些数据包啦。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g9xP0u9b-1659580889402)(F:\markdown笔记\面经\网络\673.webp)]

如上图中,发送方收到了三次同样的ACK=30的确认报文,于是就会触发快速重发机制,通过SACK信息发现只有30~39这段数据丢失,于是重发时,就只选择了这个30~39的TCP报文段进行重发。

重复SACK(D-SACK)

D-SACK,英文是Duplicate SACK,是在SACK的基础上做了一些扩展,主要用来告诉发送方,有哪些数据包,自己重复接受了。DSACK的目的是帮助发送方判断,是否发生了包失序、ACK丢失、包重复或伪重传。让TCP可以更好的做网络流控。来看个图吧:

ACK= 30 表示30没发送, SACK = 40-50,告诉「发送⽅」40-50 的数据失序。 SACK = 10-20 40-50,告诉「发送⽅」10-20 的数据失序,40-50的数据包失序

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cbCYUw43-1659580889402)(F:\markdown笔记\面经\网络\674.webp)]

TCP四次挥手

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iGq0riWS-1659580889403)(F:\markdown笔记\面经\网络\Snipaste_2022-04-10_16-30-53.png)]

  1. 第一次挥手(FIN=1,seq=u),发送完毕后,客户端进入FIN_WAIT_1状态。
  2. 第二次挥手(ACK=1,ack=u+1,seq =v),发送完毕后,服务器端进入CLOSE_WAIT状态,客户端接收到这个确认包之后,进入FIN_WAIT_2状态。
  3. 第三次挥手(FIN=1,ACK1,seq=w,ack=u+1),发送完毕后,服务器端进入LAST_ACK状态,等待来自客户端的最后一个ACK。
  4. 第四次挥手(ACK=1,seq=u+1,ack=w+1),客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入TIME_WAIT状态,等待了某个固定时间(两个最大段生命周期,2MSL,2 Maximum Segment Lifetime)之后,没有收到服务器端的ACK ,认为服务器端已经正常关闭连接,于是自己也关闭连接,进入CLOSED状态。服务器端接收到这个确认包之后,关闭连接,进入CLOSED状态。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K0I1IlkB-1659580889403)(F:\markdown笔记\面经\网络\微信图片_20220413100237.png)]

因为TCP是全双工的,所以,发送方和接收方都需要Fin和Ack。只不过,有一方是被动的,所以看上去就成了所谓的4次挥手。如果两边同时断连接,那就会就进入到fin_wait状态,然后到达TIME_WAIT状态。

为什么需要四次

能变为三次的前提是 二三步之间 服务器端无消息可以发送

如果是三次的话,那么服务端的 ACK 和 FIN 合成一个挥手,那么长时间的延迟可能让 TCP 以为FIN 没有达到服务器端,然后让客户端不断的重发 FIN 。

TIME_WAIT等待2MSL

2MSL,two Maximum Segment Lifetime,即两个最大段生命周期(报文最大生存时间)。假设主动发起挥手的是客户端,那么需要2MSL的原因是:

  • 1.为了保证客户端发送的最后一个ACK报文段能够到达服务端。 这个ACK报文段有可能丢失,处在LAST-ACK状态的服务端就收不到对已发送的FIN + ACK报文段的确认。服务端会超时重传这个FIN+ACK 报文段,而客户端就能在 2MSL 时间内收到这个重传的 FIN+ACK 报文段。接着客户端重传一次确认,重新启动2MSL计时器。最后,客户端和服务器都正常进入到CLOSED状态。否则被动方会重新发fin, 如果这时主动方处于 CLOSED 状态 ,就会响应 rst 而不是 ack。所以主动方要处于 TIME_WAIT 状态,而不能是 CLOSED 。
  • 2. 防止已失效的连接请求报文段出现在本连接中。客户端在发送完最后一个ACK报文段后,再经过时间2MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样就可以使下一个连接中不会出现这种旧的连接请求报文段。

对于访问量大的Web Server,会存在大量的TIME_WAIT状态,维护这些状态给Server带来负担。 发生大量TIME_WAIT的情况是自己可控的,自己没有迅速回收资源。

大量CLOSE_WAIT

ESTABLISHED 表示正在通信,TIME_WAIT 表示主动关闭,CLOSE_WAIT 表示被动关闭。 如果一直保持在CLOSE_WAIT状态,那么只有一种情况,就是在对方关闭连接之后服务器程序自己没有进一步发出ack信号。换句话说,就是在对方连接关闭之后,程序里没有检测到,或者程序压根就忘记了这个时候需要关闭连接,于是这个资源就一直被程序占着。

  • 服务器端收到客户端发送的FIN后,TCP协议栈就会自动发送ACK,接着进入CLOSE_WAIT状态。
  • 但是如果服务器端不执行socket的close()操作,那么就没法进入LAST_ACK,导致大量连接处于CLOSE_WAIT状态。所以,如果服务器出现了大量CLOSE_WAIT状态,一般是程序Bug,或者关闭socket不及时。 大量socket的fd 文件句柄 被占用,这个是有上限的,超过了就不能接受新的连接了。
TCP报文首部

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2UaerB9Z-1659580889404)(F:\markdown笔记\面经\网络\670.webp)]

  • 16位端口号:源端口号,主机该报文段是来自哪里;目标端口号,要传给哪个上层协议或应用程序
  • 32位序号:一次TCP通信(从TCP连接建立到断开)过程中某一个传输方向上的字节流的每个字节的编号。保证接收到的报文是有序的。 主机每次发送数据时,TCP就给每个数据包分配一个序列号(连续的)并且在一个特定的时间内等待接收主机对分配的这个序列号进行确认,如果发送主机在一个特定时间内没有收到接收主机的确认,则发送主机会重传此数据包。接收主机利用序列号对接收的数据进行确认,以便检测对方发送的数据是否有丢失或者乱序等,接收主机一旦收到已经顺序化的数据,它就将这些数据按正确的顺序重组成数据流并传递到高层进行处理。 使用了基于字节序号的 Sequence Number 及 Ack 来确认消息的有序到达。
  • 32位确认号:用作对另一方发送的tcp报文段的响应。其值是收到的TCP报文段的序号值加1。
  • 4位头部长度:表示tcp头部有多少个32bit字(4字节)。因为4位最大能标识15,所以TCP头部最长是60字节。
  • 6位标志位:URG(紧急指针是否有效),ACK(表示确认号是否有效),PSH(缓冲区尚未填满),RST(表示要求对方重新建立连接),SYN(建立连接消息标志接),FIN(表示告知对方本端要关闭连接了)
  • 16位窗口大小:是TCP流量控制的一个手段。这里说的窗口,指的是接收通告窗口。它告诉对方本端的TCP接收缓冲区还能容纳多少字节的数据,这样对方就可以控制发送数据的速度。
  • 16位校验和:由发送端填充,接收端对TCP报文段执行CRC算法以检验TCP报文段在传输过程中是否损坏。注意,这个校验不仅包括TCP头部,也包括数据部分。这也是TCP可靠传输的一个重要保障。CRC校验确保报文的完整性
  • 16位紧急指针:一个正的偏移量。它和序号字段的值相加表示最后一个紧急数据的下一字节的序号。因此,确切地说,这个字段是紧急指针相对当前序号的偏移,不妨称之为紧急偏移。TCP的紧急指针是发送端向接收端发送紧急数据的方法。

(1)为了保证数据包的可靠传递,发送方必须把已发送的数据包保留在缓冲区;
(2)并为每个已发送的数据包启动一个超时定时器;
(3)如在定时器超时之前收到了对方发来的应答信息(可能是对本包的应答,也可以是对本包后续包的应答),则释放该数据包占用的缓冲区;
(4)否则,重传该数据包,直到收到应答或重传次数超过规定的最大次数为止。
(5)接收方收到数据包后,先进行CRC校验,如果正确则把数据交给上层协议,然后给发送方发送一个累计应答包,表明该数据已收到,如果接收方正好也有数据要发给发送方,应答包也可方在数据包中捎带过去。

tcp报文首部的前20个字节是固定的,后面有4n字节是需要根据需要增加的选项,因此tcp首部的最小长度是20字节。 MTU(最大传输单元) 是1500 字节 - IP层协议的20字节, TCP层协议的20字节, 所以数据部分最大为1460byte。

TCP和UDP的区别
  • TCP 是面向连接的、可靠的传输层通信协议,面向字节流
  • UDP 是无连接的、不可靠的传输层通信协议,继承 IP 特性,面向数据报文

为什么 TCP 可靠

连接和断开的可靠性(三次握手,四次挥手)、有状态(哪些数据发送了,哪些没发)、可控制(超时重传、流量控制、拥塞控制等)。

  • 首先,TCP的连接是基于三次握手,而断开则是基于四次挥手。确保连接和断开的可靠性。

  • 会精准记录那些数据发送了,那些数据被对方接收了,那些没有被接收,而且保证数据包按序到达,不允许半点差错,这就是有状态

  • 它有数据包校验、ACK应答、超时重传(发送方)、失序数据重传(接收方)、丢弃重复数据、流量控制(滑动窗口)和拥塞控制等机制。这就是可控制

UDP 是无连接无状态的和不可控制的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Axd4M61m-1659580889404)(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==)]TCP和UDP对比

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yyO9q375-1659580889404)(F:\markdown笔记\面经\网络\669.webp)]

一个TCP报文从发送方发出去经历了哪些过程
  1. 封装报文是从上层到下层(应用层 --> 传输层 --> 网络层 – > 数据链路层 --> 物理层),解封装报文是从下层到上层。协议数据单元在应用层、表示层和会话层被称做数据(Data),在传输层被称做分段(Segment),在网络层被称做(Packet),在数据链路层被称做(Frame),在物理层被称做比特(Bit)。
  2. 数据包传输的过程中,源IP和目标IP不会变,除非遇到NAT(网络地址转换 掩码),源MAC和目标MAC遇到网关会变。二层内通过MAC寻址,三层通过IP寻址。
PC1发送http请求到Server的详细流程

img

数据包会在PC1中先封装好

当数据包从PC1发出时,它已经是一个完整的包了

应用层:HTTP协议是生成针对目标WEB服务器的HTTP请求报文,该报文就是需要传递的数据

传输层:HTTP协议使用的是TCP协议,为了方便通信,将HTTP请求报文按序号分为多个报文段(segment),并对每个报文段进行封装。PC1使用本地一个大于1024的随机TCP源端口(这里假设是1030)建立到目的服务器TCP80号端口的连接,TCP源端口和目的端口加入到报文段中,学名叫协议数据单元(Protocol Data Unit, PDU)。因TCP是一个可靠的传输控制协议,传输层还会加入序列号、窗口大小等参数。

网络层:下沉到网络层后,封装网络层的头部,主要就是添加源和目的IP地址,成为数据包。用户通常使用主机名或域名来访问服务器,这时就需要通过应用层的DNS服务来通过域名查找IP地址,或逆向从IP地址反查域名。这里的源IP地址是193.1.1.2,目的IP地址是195.1.1.2。

数据链路层:下沉到数据链路层,封帧的头部,源MAC和目标MAC。PC1比较去往的目标IP,发现Server IP 195.1.1.2不在本地网络中,PC1通过查找本地路由表,会有一条默认路由指向网关R1,知道数据包要先发到网关R1的Fa0/0口。PC1查找本地arp cache,如果找到193.1.1.1对应的MAC地址则进行封装; 如果在ARP cache中没有找到193.1.1.1对应的MAC地址,则用ARP协议,査询到网关对应的MAC地址 “00-11-BC-7D-25-03” 。于是,这里的源MAC地址是PC1的MAC地址“00-1B-24-7D-25-01”,目的MAC地址是网关的MAC地址“00-11-BC-7D-25-03。

从PC1发出的数据帧格式:

img

物理层:数据链路层封装后的数据帧下沉到物理层,转换成二进制形式的比特(Bit)流,从PC1的网卡发送出去。

数据包到达集线器

PC1发出的比特流到达集线器,集线器简单地对比特流转发,从除接收端口以外的所有端口转发出去。PC2接收到这个数据包,把比特流转换成帧上传到数据链路层,PC2比较数据帧的目的MAC地址,发现与本机网卡的MAC地址不同,PC2丢弃该数据帧,放弃处理,数据到达路由器。

数据包到达路由器R1

路由器R1收到该比特流,转换成帧上传到数据链路层,路由器R1比较数据帧的目的MAC地址,发现与路由器接收端口Fa0/0(快速以太网,简写成Fa0/0,指的是0号插槽上编号为0的接口)的MAC地址相同,路由器知道该数据帧是发往本路由器的。路由器R1的数据链路层把数据帧进行解封装,然后上传到路由器R1的网络层,路由器R1看到数据包的目的IP地址是195.1.1.2,并不是发给本路由器的,需要路由器进行转发。路由器R1査询自己的路由表,发现数据包应该从串行接口S1/1发出。路由器R1把数据包从Fa0/0接口交换到S1/1接口。此时R1并不能直接把这个数据包发出去,因为在R1的Fa0/0接口被解封装,现在需要被重新再封装。在路由器的入接口解封装,在路由器的出接口需要再封装。网络层的封装并没有被解开,但并不意味着网络层的信息一点都没有改变,其实网络层的数据包中源和目的IP地址都没有被改变(除非在网络地址转换的情况下),但TTL(生存周期)会减1。网络层把数据包交给下层的数据链路层,数据链路层需要封装二层的地址。串行链路不同于以太网,因为以太网是一个多路访问的网络,要定位到目的设备需要借助于MAC地址,但串行线路一般的封装协议都是PPP(Point-to-Point Protocol,点到点协议)或HDLC(High-Level Data Link Control,高级数据链路控制协议)封装,这种封装被用于点对点线路,也就是说,一根线缆只连接两台设备,一端发出,另一端肯定可以收到(有点像容器网络中用的veth)。假设串行线缆上使用的是PPP协议,则数据链路层封装的源和目的地址都是PPP。数据链路层封装后的数据帧被传到物理层,转换成二进制形式的比特流,从路由器R1的S1/1接口发送出去,从R1的S1/1发送出去的包的数据帧格式:

img

数据包到达R2

路由器R2收到这个比特流,上传至数据链路层,数据链路层去掉PPP的封装。路由器R2査询数据包的目的IP地址,发现该IP网络直接连接在Fa0/0接口,路由器R2把数据包交换到Fa0/0接口。路由器查看本地的ARP缓存,如果找到195.1.1.2对应的MAC地址,则直接进行封裝;如果没有找到,则发送ARP的查询包。路由器R2发出数据帧的源地址是Fa0/0接口的MAC地址,目的地址是服务器网卡的MAC地址。数据链路层封装后的数据帧被传到物理层,转换成二进制形式的比特流,从路由器R2的Fa0/0接口发送出去。

img源MAC已经变为R2的F0/0的MAC,目标MAC则根据ARP求得

交换机处理

路由器R2发出的比特流到达交换机,根据目的MAC地址进行转发。交换机根据数据帧中的目的MAC地址査询MAC地址表,把比特流从对应的端口发送出去,交换机把比特流发往服务器,并没有发往PC3。可以看到交换机并没有像集线器那样进行广播转发,而是有针对性的进行了转发。

服务器处理

服务器接收到这个比特流,把比特流转换成帧格式,上传到数据链路层,服务器发现数据帧中的目的MAC地址与本网卡的MAC地址相同,服务器拆除数据链路层的封装后,把数据包上传到网络层。服务器的网络层比较数据包中的目的IP地址,发现与本机的IP地址相同,服务器拆除网络层的封装后,把数据分段上传到传输层。传输层对数据分段进行确认、排序、重组,确保数据传输的可靠性。数据最后被传到服务器的应用层。

反向传输

服务器收到PC1发过来的数据后,对PC1进行响应。和PC1处理的过程类似,服务器也知道要发往一个远程的网络,数据链路层的目的MAC地址需要封装网关的MAC地址;网络层源和目的IP地址与PC1发送过来的包相反,即把源地址变成目的地址,目的地址变成源地址;传输层源和目的端口与PC1发送过来的包相反,即把源端口变成目的端口,目的端口变成源端口。

img

对于服务器,其通信流程一般如下所述

调用socket函数创建socket(监听socket)。
调用bind函数将socket绑定到某个IP和端口的二元组上。
调用listen函数开启监听。
当有客户端请求连接上来时,调用accept函数接收连接,产生一个新的socket(客户端socket)。
通信结束后,调用close函数关闭监听socket。

对于客户端,其通信流程一般如下所述

调用socket函数创建客户端socket。
调用connect函数尝试连接服务器
连接成功后调用send或recv函数,开始与服务器进行数据交流。
通信结束后,调用close函数关闭监听socket。
拔掉网线几秒,再插回去,原本的 TCP 连接还存在吗
拔掉网线后,有数据传输

如果在服务端重传报文的过程中,客户端刚好把网线插回去了,由于拔掉网线并不会改变客户端的 TCP 连接状态,并且还是处于 ESTABLISHED 状态,所以这时客户端是可以正常接收服务端发来的数据报文的,然后客户端就会回 ACK 响应报文。 此时,客户端和服务端的 TCP 连接依然存在的,就感觉什么事情都没有发生。

但是,如果在服务端重传报文的过程中,客户端一直没有将网线插回去,服务端超时重传报文的次数达到一定阈值后,内核就会判定出该 TCP 有问题,然后通过 Socket 接口告诉应用程序该 TCP 连接出问题了,于是服务端的 TCP 连接就会断开。 而等客户端插回网线后,如果客户端向服务端发送了数据,由于服务端已经没有与客户端相同四元组的 TCP 连接了,因此服务端内核就会回复 RST 报文,客户端收到后就会释放该 TCP 连接。此时,客户端和服务端的 TCP 连接都已经断开了。

tcp_retries2 设置了 15 次,并不代表 TCP 超时重传了 15 次才会通知应用程序终止该 TCP 连接,内核还会基于「最大超时时间」来判定。 每一轮的超时时间都是倍数增长的,比如第一次触发超时重传是在 2s 后,第二次则是在 4s 后,第三次则是 8s 后,以此类推。 内核会根据 tcp_retries2 设置的值,计算出一个最大超时时间。 在重传报文且一直没有收到对方响应的情况时,先达到「最大重传次数」或者「最大超时时间」这两个的其中一个条件后,就会停止重传,然后就会断开 TCP 连接。

拔掉网线后,没有数据传输

如果没有开启 TCP keepalive 机制,在客户端拔掉网线后,并且双方都没有进行数据传输,那么客户端和服务端的 TCP 连接将会一直保持存在。

而如果开启了 TCP keepalive 机制,在客户端拔掉网线后,即使双方都没有进行数据传输,在持续一段时间后,TCP 就会发送探测报文:

  • 如果对端是正常工作的。当 TCP 保活的探测报文发送给对端, 对端会正常响应,这样 TCP 保活时间会被重置,等待下一个 TCP 保活时间的到来。
  • 如果对端主机崩溃,或对端由于其他原因导致报文不可达。当 TCP 保活的探测报文发送给对端后,石沉大海,没有响应,连续几次,达到保活探测次数后,TCP 会报告该 TCP 连接已经死亡

所以,TCP 保活机制可以在双方没有数据交互的情况,通过探测报文,来确定对方的 TCP 连接是否存活。 这个机制的原理是这样的: 定义一个时间段,在这个时间段内,如果没有任何连接相关的活动,TCP 保活机制会开始作用,每隔一个时间间隔,发送一个探测报文,该探测报文包含的数据非常少,如果连续几个探测报文都没有得到响应,则认为当前的 TCP 连接已经死亡,系统内核将错误信息通知给上层应用程序。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我顶得了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值