计网 - 图36 应用层

应用层协议定义了应用进程间的交互通信规则,不同主机的应用进程间如何互相传递报文,比如报文类型,格式,字段等等。

HTTP协议

超文本传输协议,定义了客户端和服务器之间交换报文的格式和方式,默认用80端口,使用TCP作为传输层协议,保证了数据传输的可靠性。

HTTP 是一种无状态 (stateless) 协议, HTTP协议本身不会对发送过的请求和相应的通信状态进行持久化处理。这样做的目的是为了保持HTTP协议的简单性,从而能够快速处理大量的事务, 提高效率。

然而,在许多应用场景中,我们需要保持用户登录的状态或记录用户购物车中的商品。由于HTTP是无状态协议,所以必须引入一些技术来记录管理状态,例如Cookie

HTTP报文

http请求由请求行,消息报头,请求正文三部分构成

请求报文

计网 - 图37

  1. GET / HTTP/1.1
  2. User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5)
  3. Accept: */*

HTTP 请求报文的第一行叫做请求行,后面的行叫做首部行,首部行后还可以跟一个实体主体。请求首部之后有一个空行,这
个空行不能省略,它用来划分首部与实体。

请求行包含三个字段:方法字段、URL 字段和 HTTP 版本字段。

方法字段可以取几种不同的值,一般有 GET、POST、HEAD、PUT 和 DELETE。

  • GET 方法只被用于向服务器获取数据
  • POST 方法用于将实体提交到指定的资源,通常会造成服务器资源的修改
  • HEAD 方法与 GET 方法类似,但是在返回的响应中,不包含请求对象
  • PUT 方法用于上传文件到服务器
  • DELETE 方法用于删除服务器上的对象。虽然请求的方法很多,但更多表达的是一种语义上的区别,并不是说 POST 能做的事情,GET 就不能做了,主要看我们如何选择

响应报文

计网 - 图38

  1. HTTP/1.0 200 OK
  2. Content-Type: text/plain
  3. Content-Length: 137582
  4. Expires: Thu, 05 Dec 1997 16:00:00 GMT
  5. Last-Modified: Wed, 5 August 1996 15:55:28 GMT
  6. Server: Apache 0.84
  7. <html>
  8. <body>Hello World</body>
  9. </html>

HTTP 响应报文的第一行叫做状态行,后面的行是首部行,最后是实体主体。

状态行包含了三个字段:协议版本字段、状态码和相应的状态信息。

实体部分是报文的主要部分,它包含了所请求的对象。

常见的状态有

  • 200-请求成功、202-服务器端已经收到请求消息,但是尚未进行处理
  • 301-永久移动、302-临时移动、304-所请求的资源未修改、
  • 400-客户端请求的语法错误、404-请求的资源不存在
  • 500-服务器内部错误。

一般 1XX 代表服务器接收到请求、2XX 代表成功、3XX 代表重定向、4XX 代表客户端错误、5XX 代表服务器端错误。

首部行

首部可以分为四种首部,请求首部、响应首部、通用首部和实体首部。通用首部和实体首部在请求报文和响应报文中都可以设置,区别在于请求首部和响应首部。

常见的请求首部有

  • Accept 可接收媒体资源的类型
  • Accept-Charset 可接收的字符集
  • Host 请求的主机名

常见的响应首部有

  • ETag 资源的匹配信息
  • Location 客户端重定向的 URI

常见的通用首部有

  • Cache-Control 控制缓存策略
  • Connection 管理持久连接。

常见的实体首部有

  • Content-Length 实体主体的大小
  • Expires 实体主体的过期时间
  • Last-Modified 资源的最后修改时间。

HTTP各版本

HTTP0.9

计网 - 图391991年发布, 没有header,功能非常简单,只支持GET。

HTTP1.0

计网 - 图401996年发布,明文传输安全性差,header特别大。它相对0.9有以下增强:

  • 增加了header(使用元数据与数据解耦)
  • 增加了status code,用于声明请求的结果。
  • content-type可以传输其它文件。
  • 请求头增加了http/1.0版本号。

缺点:每请求一次资源就新建一次tcp连接

HTTP1.1

计网 - 图411997发布,是现在使用最广泛的版本。它相对1.0有以下增强:

  • 可以设置 keepalive 让 http 重用tcp连接(请求必需串行发送)
  • 支持pipeline传输,请求发出后可以继续发送请求
  • 增加了HOST头,让服务端知道用户请求的是哪个域名
  • 增加了type、language、encoding等header

2014年更新了内容:

  • 增加了TLS支持,即https传输
  • 支持四种模型: 短连接,可重用tcp的长链接,服务端push模型(服务端主动将数据推送到客户端cache中),websocket模型

缺点:还是文本协议,客户端服务端都需要利用cpu解压缩

队头堵塞

HTTP1.1 默认使用持久连接,多个请求可以复用同一个TCP连接,但是在同一个TCP连接里面,数据请求的通讯次序是固定的。服务器只有处理完一个请求连接后,才会进行下一个请求处理,如果前面请求的响应特别慢的话,就会造成许多请求排队等待的情况,这种情况被称为 队头堵塞 。队头堵塞会导致持久连接在到达最大数量时,剩余的资源需要等待其他资源请求完成后才能发起请求。

计网 - 图42 如何避免队头堵塞

  1. 一个是减少请求数,一个是同时打开多个持久连接。这就是我们对网站优化时,使用雪碧图、合并脚本的原因。

实现断点续传的原理
  • http1.1推出了range字段,以提供客户端对服务器请求特定部分资源的能力,利用该字段就可以实现断点续传,当然前提是服务器支持range分块传输。在连接建立后,客户端维护当前收到的资源大小,当连接或传输因某些原因中断时,客户端会再次向服务器发起资源请求,在这时的请求报文中range字段写入已收到的资源大小。服务器收到该请求报文后解析range字段就知道需要发给客户端的是哪部分内容,并在响应报文的content-range字段写明是报文实体是哪部分的资源。这样就实现了断点续传。需要注意的是,如果服务器支持断点续传,那么在续传的响应报文状态码会是**206**而不是**200**,如果服务器不支持断点续传也就是**range**字段,那么将会重新返回整个资源并返回**200**状态码。
  • 在这个过程中,如果在客户端发起断点续传时服务器的该资源已经发生改动,那么响应要发生响应变化。一般通过last-modified字段或者eTag字段来确定一个资源有没有被修改。

1.1模型

轮询

短轮询的基本思路就是浏览器每隔一段时间向浏览器发送http请求,服务器端在收到请求后,不论是否有数据更新,都直接进行响应。这种方式实现的即时通信,本质上还是浏览器发送请求,服务器接受请求的一个过程,通过让客户端不断的进行请求,使得客户端能够模拟实时地收到服务器端的数据的变化。

这种方式的优点是比较简单,易于理解,实现起来也没有什么技术难点。缺点是显而易见的,这种方式由于需要不断的建立http连接,严重浪费了服务器端和客户端的资源。尤其是在客户端,距离来说,如果有数量级想对比较大的人同时位于基于短轮询的应用中,那么每一个用户的客户端都会疯狂的向服务器端发送http请求,而且不会间断。人数越多,服务器端压力越大,这是很不合理的。

长轮询

当服务器收到客户端发来的请求后,服务器端不会直接进行响应,而是先将这个请求挂起,然后判断服务器端数据是否有更新。如果有更新,则进行响应,如果一直没有数据,则到达一定的时间限制(服务器端设置)才返回。 。 客户端JavaScript响应处理函数会在处理完服务器返回的信息后,再次发出请求,重新建立连接。

长轮询和短轮询比起来,明显减少了很多不必要的http请求次数,相比之下节约了资源。长轮询的缺点在于,连接挂起也会导致资源的浪费。

计网 - 图43

SSE(服务器推送事件)

SSE是HTML5新增的功能,全称为Server-Sent Events。它可以允许服务推送数据到客户端。SSE在本质上就与之前的长轮询、短轮询不同,虽然都是基于http协议的,但是轮询需要客户端先发送请求。而SSE最大的特点就是不需要客户端发送请求,可以实现只要服务器端数据有更新,就可以马上发送到客户端。

SSE的优势很明显,它不需要建立或保持大量的客户端发往服务器端的请求,节约了很多资源,提升应用性能。

  1. if (!!window.EventSource) { // 判断是否支持SSE
  2. var source = new EventSource('http://127.0.0.1/');
  3. source.addEventListener('message', function (e) {
  4. // 连接时触发
  5. }
  6. source.addEventListener('open', function (e) {
  7. // 在服务器接受新事件触发
  8. }
  9. source.addEventListener('error', function (e) {
  10. // 无法建立连接时触发
  11. }
  12. source.close() // 关闭连接
  13. }

WebSocket

WebSocket是Html5定义的一个新协议,与传统的http协议不同,该协议可以实现服务器与客户端之间全双工通信。简单来说,首先需要在客户端和服务器端建立起一个连接,这部分需要http。连接一旦建立,客户端和服务器端就处于平等的地位,可以相互发送数据,不存在请求和响应的区别。

步骤

  1. 浏览器、服务器建立TCP连接,三次握手。这是通信的基础,传输控制层,若失败后续都不执行。
  2. TCP连接成功后,浏览器通过HTTP协议向服务器传送WebSocket支持的版本号等信息。(开始前的HTTP握手)
  3. 服务器收到客户端的握手请求后,同样采用HTTP协议回馈数据。
  4. 当收到了连接成功的消息后,通过TCP通道进行传输通信。

特点

(1)建立在 TCP 协议之上,服务器端的实现比较容易。

(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。

(3)数据格式比较轻量,性能开销小,通信高效。

(4)可以发送文本,也可以发送二进制数据。

(5)没有同源限制,客户端可以与任意服务器通信。

(6)协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。

  1. ws://example.com:80/some/path

计网 - 图44

对比

计网 - 图45

HTTP2

计网 - 图462015年发布,主要是提升安全性与性能。它相对1.1的增强有:

  • 头部压缩(合并同时发出请求的相同部分)
  • 二进制分帧传输,更方便头部只传输差异部分
  • 流多路复用,同一服务下只需要用一个连接,节省了连接
  • 服务器推送,一次客户端请求服务端可以多次响应。
  • 可以在一个tcp连接中并发发送请求

缺点:基于tcp传输,会有队头阻塞问题(丢包停止窗口滑动),tcp会丢包重传。tcp握手延时长,协议僵化问题。

因为 HTTP/2 使用了多路复用,一般来说同一域名下只需要使用一个 TCP 连接。由于多个数据流使用同一个 TCP 连接,遵守同一个流量状态控制和拥塞控制。只要一个数据流遭遇到拥塞,剩下的数据流就没法发出去,这样就导致了后面的所有数据都会被阻塞。HTTP/2 出现的这个问题是由于其使用 TCP 协议的问题,与它本身的实现其实并没有多大关系。

二进制协议

HTTP2是一个二进制协议,在1.1的版本中,报文头信息必须是文本(ASCII编码),数据体是文本或者二进制;但在2.0版本中头信息和数据体都是二进制,并统称为 ,分为头信息帧与数据帧;以实现多路复用

多路复用

在一个TCP连接里,客户端和服务器都可以同时发送多个请求或回应,而且不用按照顺序一一发送,避免队头堵塞问题

数据流

数据包是不按顺序发送的,同一个连接里面的数据包,可能属于不同请求,因此,必须要对数据包做标记,指名属于哪个请求。2版本将每个请求或回应的所有数据包,成为数据流,数据包发送的时候,都必须标记数据流 ID ,用来区分它属于哪个数据流。

头信息压缩

HTTP/2 实现了头信息压缩,由于 HTTP 1.1 协议不带有状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,比如 Cookie 和 User Agent ,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。

HTTP/2 对这一点做了优化,引入了头信息压缩机制。一方面,头信息使用 gzip 或 compress 压缩后再发送;另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就能提高速度了。

服务器推送

HTTP/2 允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送。使用服务器推送,提前给客户端推送必要的资源,这样就可以相对减少一些延迟时间。这里需要注意的是 http2 下服务器主动推送的是静态资源,和 WebSocket 以及使用SSE 等方式向客户端发送即时数据的推送是不同的。

HTTP3

2018年发布,基于谷歌的QUIC,底层使用udp代码tcp协议,

这样解决了队头阻塞问题,同样无需握手,性能大大地提升,默认使用tls加密。

QUIC协议是一个通用的传输层协议,它基于UDP协议创造,旨在保留UDP协议速度的同时拥有几乎与TCP协议相同的可靠性。QUIC协议提高了目前的TCP应用的性能,它通过UDP连接在两个端点之间创建多个多路连接来实现这一目标。

计网 - 图47

HTTPS

HTTPS 指的是超文本传输安全协议,HTTPS 是基于 HTTP 协议的,不过它会使用 TLS/SSL 来对数据加密。使用 TLS/SSL 协议,所有的信息都是加密的,第三方没有办法窃听。并且它提供了一种校验机制,信息一旦被篡改,通信的双方会立刻发现。它还配备了身份证书,防止身份被冒充的情况出现。

HTTP 存在的问题

  1. HTTP 报文使用明文方式发送,可能被第三方窃听。
  2. HTTP 报文可能被第三方截取后修改通信内容,接收方没有办法发现报文内容的修改。
  3. HTTP 还存在认证的问题,第三方可以冒充他人参与通信。

计网 - 图48

TLS/SSL

TLS 的握手过程主要用到了三个方法来保证传输的安全。

对称加密的方法

首先是对称加密的方法,对称加密的方法是,双方使用同一个秘钥对数据进行加密和解密。但是对称加密的存在一个问题,就是如何保证秘钥传输的安全性,因为秘钥还是会通过网络传输的,一旦秘钥被其他人获取到,那么整个加密过程就毫无作用了。这就要用到非对称加密的方法。

非对称加密的方法

非对称加密的方法是,我们拥有两个秘钥,一个是公钥,一个是私钥。公钥是公开的,私钥是保密的。用私钥加密的数据,只有对应的公钥才能解密,用公钥加密的数据,只有对应的私钥才能解密。我们可以将公钥公布出去,任何想和我们通信的客户,都可以使用我们提供的公钥对数据进行加密,这样我们就可以使用私钥进行解密,这样就能保证数据的安全了。但是非对称加密有一个缺点就是加密的过程很慢,因此如果每次通信都使用非对称加密的方式的话,反而会造成等待时间过长的问题。

因此我们可以使用对称加密和非对称加密结合的方式,因为对称加密的方式的缺点是无法保证秘钥的安全传输,因此我们可以非对称加密的方式来对对称加密的秘钥进行传输,然后以后的通信使用对称加密的方式来加密,这样就解决了两个方法各自存在的问题。

数字证书

首先我们使用一种 Hash 算法来对我们的公钥和其他信息进行加密生成一个信息摘要,然后让有公信力的认证中心(简称 CA )用它的私钥对消息摘要加密,形成签名。最后将原始的信息和签名合在一起,称为数字证书。当接收方收到数字证书的时候,先根据原始信息使用同样的 Hash 算法生成一个摘要,然后使用公证
处的公钥来对数字证书中的摘要进行解密,最后将解密的摘要和我们生成的摘要进行对比,就能发现我们得到的信息是否被更改了。这个方法最要的是认证中心的可靠性,一般浏览器里会内置一些顶层的认证中心的证书,相当于我们自动信任了他们,只有这样我们才能保证数据的安全。

握手过程

  1. 第一步,客户端向服务器发起请求,请求中包含使用的协议版本号、生成的一个随机数、以及客户端支持的加密方法。
  2. 第二步,服务器端接收到请求后,确认双方使用的加密方法、并给出服务器的证书、以及一个服务器生成的随机数。
  3. 第三步,客户端确认服务器证书有效后,生成一个新的随机数,并使用数字证书中的公钥,加密这个随机数,然后发给服务器。并且还会提供一个前面所有内容的 hash 的值,用来供服务器检验。
  4. 第四步,服务器使用自己的私钥,来解密客户端发送过来的随机数。并提供前面所有内容的 hash 值来供客户端检验。
  5. 第五步,客户端和服务器端根据约定的加密方法使用前面的三个随机数,生成对话秘钥,以后的对话过程都使用这个秘钥来加密信息。

计网 - 图49

DNS协议

DNS 协议提供的是一种主机名到 IP 地址的转换服务,就是我们常说的域名系统。它是一个由分层的 DNS 服务器组成的分布式数据库,是定义了主机如何查询这个分布式数据库的方式的应用层协议。DNS 协议运行在 UDP 协议之上,使用 53 号端口。

  1. 主机名.次级域名.顶级域名.根域名

根据域名的层级结构,管理不同层级域名的服务器,可以分为根域名服务器、顶级域名服务器和权威域名服务器。

查询过程

DNS 的查询过程一般为,我们首先将 DNS 请求发送到本地 DNS 服务器,由本地 DNS 服务器来代为请求。

  1. 从”根域名服务器”查到”顶级域名服务器”的 NS 记录和 A 记录( IP 地址)。
  2. 从”顶级域名服务器”查到”次级域名服务器”的 NS 记录和 A 记录( IP 地址)。
  3. 从”次级域名服务器”查出”主机名”的 IP 地址。

比如我们如果想要查询 www.baidu.com 的 IP 地址,我们首先会将请求发送到本地的 DNS 服务器中,本地 DNS 服务器会判断是否存在该域名的缓存,如果不存在,则向根域名服务器发送一个请求,根域名服务器返回负责 .com 的顶级域名服务器的 IP 地址的列表。然后本地 DNS 服务器再向其中一个负责 .com 的顶级域名服务器发送一个请求,负责 .com的顶级域名服务器返回负责 .baidu 的权威域名服务器的 IP 地址列表。然后本地 DNS 服务器再向其中一个权威域名服务器发送一个请求,最后权威域名服务器返回一个对应的主机名的 IP 地址列表。

DNS 记录和报文

DNS 服务器中以资源记录的形式存储信息,每一个 DNS 响应报文一般包含多条资源记录。一条资源记录的具体的格式为(Name,Value,Type,TTL)

其中 TTL 是资源记录的生存时间,它定义了资源记录能够被其他的 DNS 服务器缓存多长时间。

常用的一共有四种 Type 的值,分别是 A、NS、CNAME 和 MX ,不同 Type 的值,对应资源记录代表的意义不同。

  1. 如果 Type = A,则 Name 是主机名,Value 是主机名对应的 IP 地址。因此一条记录为 A 的资源记录,提供了标准的主机名到 IP 地址的映射。
  2. 如果 Type = NS,则 Name 是个域名,Value 是负责该域名的 DNS 服务器的主机名。这个记录主要用于 DNS 链式查询时,返回下一级需要查询的 DNS 服务器的信息。
  3. 如果 Type = CNAME,则 Name 为别名,Value 为该主机的规范主机名。该条记录用于向查询的主机返回一个主机名对应的规范主机名,从而告诉查询主机去查询这个主机名的 IP 地址。主机别名主要是为了通过给一些复杂的主机名提供一个便于记忆的简单的别名。
  4. 如果 Type = MX,则 Name 为一个邮件服务器的别名,Value 为邮件服务器的规范主机名。它的作用和 CNAME 是一样的,都是为了解决规范主机名不利于记忆的缺点。

递归查询和迭代查询

递归查询指的是查询请求发出后,域名服务器代为向下一级域名服务器发出请求,最后向用户返回查询的最终结果。使用递归查询,用户只需要发出一次查询请求。

迭代查询指的是查询请求后,域名服务器返回单次查询的结果。下一级的查询由用户自己请求。使用迭代查询,用户需要发出多次的查询请求。

一般我们向本地 DNS 服务器发送请求的方式就是递归查询,因为我们只需要发出一次请求,然后本地 DNS 服务器返回给我们最终的请求结果。而本地 DNS 服务器向其他域名服务器请求的过程是迭代查询的过程,因为每一次域名服务器只返回单次查询的结果,下一级的查询由本地 DNS 服务器自己进行。

DNS 缓存

DNS 缓存的原理非常简单,在一个请求链中,当某个 DNS 服务器接收到一个 DNS 回答后,它能够将回答中的信息缓存在本地存储器中。返回的资源记录中的 TTL 代表了该条记录的缓存的时间。

DNS 实现负载平衡

DNS 可以用于在冗余的服务器上实现负载平衡。因为现在一般的大型网站使用多台服务器提供服务,因此一个域名可能会对应多个服务器地址。当用户发起网站域名的 DNS 请求的时候,DNS 服务器返回这个域名所对应的服务器 IP 地址的集合,但在每个回答中,会循环这些 IP 地址的顺序,用户一般会选择排在前面的地址发送请求。以此将用户的请求均衡的分配到各个不同的服务器上,这样来实现负载均衡。

CDN

内容分发网络(Content Delivery Network),简而言之就是对用户请求通过中心平台服务器调度告诉用户当前请求资源距离用户最近,访问速度最快的缓存服务器地址,用户去请求该服务器获取资源。解决了源服务器服务过载网络拥塞(大量TCP连接过来)以及数据传输慢等问题。

CDN流程:

  1. 浏览器访问www.cdnNews.com/index.html
  2. 浏览器使用本地DNS服务对地址进行解析(DNS解析过程)
  3. DNS解析最后将该地址的权威DNS服务器地址返回给本地DNS服务器
  4. 由于访问的地址做了CDN处理,此时的权威DNS服务器其实就是该网站的CDN专用DNS服务器,该服务器通过负载均衡系统解析请求资源,找到对用户响应最快的缓存服务器IP地址返回
  5. 本地DNS服务器接受到CDN专用DNS服务器返回的IP地址交给浏览器。(DNS解析结束)
  6. 浏览器向该IP地址发送请求。
  7. 缓存服务器接收到浏览器发来的请求,先检查本地有没有该资源,有的话直接将资源返回给浏览器。
  8. 无该资源则缓存服务器向源服务器请求资源,获取资源缓存,并将资源返回给浏览器
    计网 - 图50

CDN缓存:

  1. 浏览器向CDN缓存服务器发送数据请求
  2. CDN缓存服务器先检查本地数据有没有过期,没有直接返回改数据
  3. CDN缓存服务器发现本地缓存过期,则向源服务器请求数据,获取请求数据,本地缓存数据,并返回数据给浏览器。

计网 - 图51 传输层

传输层协议主要是为不同主机上的不同进程间提供了逻辑通信的功能。传输层只工作在端系统中。

多路复用与多路分解

将传输层报文段中的数据交付到正确的套接字的工作被称为多路分解

在源主机上从不同的套接字中收集数据,封装头信息生成报文段后,将报文段传递到网络层,这个过程被称为多路复用

无连接的多路复用和多路分解指的是 UDP 套接字的分配过程,一个 UDP 套接字由一个二元组来标识,这个二元组包含了一个目的地址和一个目的端口号。因此不同源地址和端口号的 UDP 报文段到达主机后,如果它们拥有相同的目的地址和目的端口号,那么不同的报文段将会转交到同一个 UDP 套接字中。

面向连接的多路复用和多路分解指的是 TCP 套接字的分配过程,一个 TCP 套接字由一个四元组来标识,这个四元组包含了源 IP 地址、源端口号、目的地址和目的端口号。因此,一个 TCP 报文段从网络中到达一台主机上时,该主机使用全部 4 个值来将报文段定向到相应的套接字。

UDP 协议

UDP 是一种无连接的,不可靠的传输层协议。它只提供了传输层需要实现的最低限度的功能,除了复用/分解功能和少量的差错检测外,它几乎没有对 IP 增加其他的东西。UDP 协议适用于对实时性要求高的应用场景。

特点:

  1. 使用 UDP 时,在发送报文段之前,通信双方没有握手的过程,因此 UDP 被称为是无连接的传输层协议。因为没有握手过程,相对于 TCP 来说,没有建立连接的时延。因为没有连接,所以不需要在端系统中保存连接的状态。
  2. UDP 提供尽力而为的交付服务,也就是说 UDP 协议不保证数据的可靠交付。
  3. UDP 没有拥塞控制和流量控制的机制,所以 UDP 报文段的发送速率没有限制
  4. 因为一个 UDP 套接字只使用目的地址和目的端口来标识,所以 UDP 可以支持一对一、一对多、多对一和多对多的交互通信。
  5. UDP 首部小,只有 8 个字节。

报文段结构

UDP 报文段由首部和应用数据组成。报文段首部包含四个字段,分别是源端口号、目的端口号、长度和检验和,每个字段的长
度为两个字节。长度字段指的是整个报文段的长度,包含了首部和应用数据的大小。校验和是 UDP 提供的一种差错校验机制。
虽然提供了差错校验的机制,但是 UDP 对于差错的恢复无能为力。

计网 - 图52

TCP 协议

TCP 协议是面向连接的,提供可靠数据传输服务的传输层协议。

特点:

  1. TCP 协议是面向连接的,在通信双方进行通信前,需要通过三次握手建立连接。它需要在端系统中维护双方连接的状态信息。
  2. TCP 协议通过序号、确认号、定时重传、检验和等机制,来提供可靠的数据传输服务
  3. TCP 协议提供的是点对点的服务,即它是在单个发送方和单个接收方之间的连接。
  4. TCP 协议提供的是全双工的服务,也就是说连接的双方的能够向对方发送和接收数据。
  5. TCP 提供了拥塞控制机制,在网络拥塞的时候会控制发送数据的速率,有助于减少数据包的丢失和减轻网络中的拥塞程度。
  6. TCP 提供了流量控制机制,保证了通信双方的发送和接收速率相同。如果接收方可接收的缓存很小时,发送方会降低发送速率,避免因为缓存填满而造成的数据包的丢失。

报文段结构

TCP 报文段由首部和数据组成,它的首部一般为 20 个字节。

源端口和目的端口号用于报文段的多路复用和分解。

32 比特的序号和 32 比特的确认号,用与实现可靠数据运输服务。

16 比特的接收窗口字段用于实现流量控制,该字段表示接收方愿意接收的字节的数量。

4 比特的首部长度字段,该字段指示了以 32 比特的字为单位的 TCP 首部的长度。

6 比特的标志字段,ACK 字段用于指示确认序号的值是有效的,RST、SYN 和 FIN 比特用于连接建立和拆除。设置 PSH 字段指示接收方应该立即将数据交给上层,URG 字段用来指示报文段里存在紧急的数据。校验和提供了对数据的差错检测。

计网 - 图53

TCP握手

第一次握手,客户端向服务器发送一个 SYN 连接请求报文段,报文段的首部中 SYN 标志位置为 1,序号字段是一个任选的随机数。它代表的是客户端数据的初始序号。

第二次握手,服务器端接收到客户端发送的 SYN 连接请求报文段后,服务器首先会为该连接分配 TCP 缓存和变量,然后向客户端发送 SYN ACK 报文段,报文段的首部中 SYN 和 ACK 标志位都被置为 1,代表这是一个对 SYN 连接请求的确认,同时序号字段是服务器端产生的一个任选的随机数,它代表的是服务器端数据的初始序号。确认号字段为客户端发送的序号加一。

第三次握手,客户端接收到服务器的肯定应答后,它也会为这次 TCP 连接分配缓存和变量,同时向服务器端发送一个对服务器端的报文段的确认。第三次握手可以在报文段中携带数据。

在我看来,TCP 三次握手的建立连接的过程就是相互确认初始序号的过程,告诉对方,什么样序号的报文段能够被正确接收。第三次握手的作用是客户端对服务器端的初始序号的确认。如果只使用两次握手,那么服务器就没有办法知道自己的序号是否已被确认。同时这样也是为了防止失效的请求报文段被服务器接收,而出现错误的情况。

TCP 挥手

因为 TCP 连接是全双工的,也就是说通信的双方都可以向对方发送和接收消息,所以断开连接需要双方的确认。

第一次挥手,客户端认为没有数据要再发送给服务器端,它就向服务器发送一个 FIN 报文段,申请断开客户端到服务器端的连接。发送后客户端进入 FIN_WAIT_1 状态。

第二次挥手,服务器端接收到客户端释放连接的请求后,向客户端发送一个确认报文段,表示已经接收到了客户端释放连接的请求,以后不再接收客户端发送过来的数据。但是因为连接是全双工的,所以此时,服务器端还可以向客户端发送数据。服务器端进入 CLOSE_WAIT 状态。客户端收到确认后,进入 FIN_WAIT_2 状态。

第三次挥手,服务器端发送完所有数据后,向客户端发送 FIN 报文段,申请断开服务器端到客户端的连接。发送后进入 LAST_ACK 状态。

第四次挥手,客户端接收到 FIN 请求后,向服务器端发送一个确认应答,并进入 TIME_WAIT 阶段。该阶段会持续一段时间,这个时间为报文段在网络中的最大生存时间,如果该时间内服务端没有重发请求的话,客户端进入 CLOSED 的状态。如果收到服务器的重发请求就重新发送确认报文段。服务器端收到客户端的确认报文段后就进入 CLOSED 状态,这样全双工的连接就被释放了。

TCP 使用四次挥手的原因是因为 TCP 的连接是全双工的,所以需要双方分别释放到对方的连接,单独一方的连接释放,只代表不能再向对方发送数据,连接处于的是半释放的状态。

最后一次挥手中,客户端会等待一段时间再关闭的原因,是为了防止发送给服务器的确认报文段丢失或者出错,从而导致服务器端不能正常关闭。

计网 - 图54

ARQ 协议

ARQ 协议指的是自动重传请求,它通过超时和重传来保证数据的可靠交付,它是 TCP 协议实现可靠数据传输的一个很重要的机制。

它分为停止等待 ARQ 协议和连续 ARQ 协议。

停止等待 ARQ 协议

停止等待 ARQ 协议的基本原理是,对于发送方来说发送方每发送一个分组,就为这个分组设置一个定时器。当发送分组的确认回答返回了,则清除定时器,发送下一个分组。如果在规定的时间内没有收到已发送分组的肯定回答,则重新发送上一个分组。

对于接受方来说,每次接受到一个分组,就返回对这个分组的肯定应答,当收到冗余的分组时,就直接丢弃,并返回一个对冗余分组的确认。当收到分组损坏的情况的时候,直接丢弃。

使用停止等待 ARQ 协议的缺点是每次发送分组必须等到分组确认后才能发送下一个分组,这样会造成信道的利用率过低。

计网 - 图55

连续 ARQ 协议。

连续 ARQ 协议是为了解决停止等待 ARQ 协议对于信道的利用率过低的问题。它通过连续发送一组分组,然后再等待对分组的确认回答,对于如何处理分组中可能出现的差错恢复情况,一般可以使用滑动窗口协议和选择重传协议来实现。

计网 - 图56

  1. 滑动窗口协议

    使用滑动窗口协议,在发送方维持了一个发送窗口,发送窗口以前的分组是已经发送并确认了的分组,发送窗口中包含了已经发送但未确认的分组和允许发送但还未发送的分组,发送窗口以后的分组是缓存中还不允许发送的分组。当发送方向接收方发送分组时,会依次发送窗口内的所有分组,并且设置一个定时器,这个定时器可以理解为是最早发送但未收到确认的分组。如果在定时器的时间内收到某一个分组的确认回答,则滑动窗口,将窗口的首部移动到确认分组的后一个位置,此时如果还有已发送但没有确认的分组,则重新设置定时器,如果没有了则关闭定时器。如果定时器超时,则重新发送所有已经发送但还未收到确认的分组。

    接收方使用的是累计确认的机制,对于所有按序到达的分组,接收方返回一个分组的肯定回答。如果收到了一个乱序的分组,那么接方会直接丢弃,并返回一个最近的按序到达的分组的肯定回答。使用累计确认保证了确认号以前的分组都已经按序到达了,所以发送窗口可以移动到已确认分组的后面。

滑动窗口协议的缺点是因为使用了累计确认的机制,如果出现了只是窗口中的第一个分组丢失,而后面的分组都按序到达的情况的话,那么滑动窗口协议会重新发送所有的分组,这样就造成了大量不必要分组的丢弃和重传。

  1. 选择重传协议

    因为滑动窗口使用累计确认的方式,所以会造成很多不必要分组的重传。使用选择重传协议可以解决这个问题。

    选择重传协议在发送方维护了一个发送窗口。发送窗口的以前是已经发送并确认的分组,窗口内包含了已发送但未被确认的分组,已确认的乱序分组,和允许发送但还未发送的分组,发送窗口以后的是缓存中还不允许发送的分组。选择重传协议与滑动窗口协议最大的不同是,发送方发送分组时,为一个分组都创建了一个定时器。当发送方接受到一个分组的确认应答后,取消该分组的定时器,并判断接受该分组后,是否存在由窗口首部为首的连续的确认分组,如果有则向后移动窗口的位置,如果没有则将该分组标识为已接收的乱序分组。当某一个分组定时器到时后,则重新传递这个分组。

    在接收方,它会确认每一个正确接收的分组,不管这个分组是按序的还是乱序的,乱序的分组将被缓存下来,直到所有的乱序分组都到达形成一个有序序列后,再将这一段分组交付给上层。对于不能被正确接收的分组,接收方直接忽略该分组。

计网 - 图57

可靠运输机制

TCP 的可靠运输机制是基于连续 ARQ 协议和滑动窗口协议的。

TCP 协议在发送方维持了一个发送窗口,发送窗口以前的报文段是已经发送并确认了的报文段,发送窗口中包含了已经发送但未确认的报文段和允许发送但还未发送的报文段,发送窗口以后的报文段是缓存中还不允许发送的报文段。当发送方向接收方发送报文时,会依次发送窗口内的所有报文段,并且设置一个定时器,这个定时器可以理解为是最早发送但未收到确认的报文段。如果在定时器的时间内收到某一个报文段的确认回答,则滑动窗口,将窗口的首部向后滑动到确认报文段的后一个位置,此时如果还有已发送但没有确认的报文段,则重新设置定时器,如果没有了则关闭定时器。如果定时器超时,则重新发送所有已经发送
但还未收到确认的报文段,并将超时的间隔设置为以前的两倍。当发送方收到接收方的三个冗余的确认应答后,这是一种指示,说明该报文段以后的报文段很有可能发生丢失了,那么发送方会启用快速重传的机制,就是当前定时器结束前,发送所有的已发送但确认的报文段。

接收方使用的是累计确认的机制,对于所有按序到达的报文段,接收方返回一个报文段的肯定回答。如果收到了一个乱序的报文段,那么接方会直接丢弃,并返回一个最近的按序到达的报文段的肯定回答。使用累计确认保证了返回的确认号之前的报文段都已经按序到达了,所以发送窗口可以移动到已确认报文段的后面。

发送窗口的大小是变化的,它是由接收窗口剩余大小和网络中拥塞程度来决定的,TCP 就是通过控制发送窗口的长度来控制报文段的发送速率。

但是 TCP 协议并不完全和滑动窗口协议相同,因为许多的 TCP 实现会将失序的报文段给缓存起来,并且发生重传时,只会重传一个报文段,因此 TCP 协议的可靠传输机制更像是窗口滑动协议和选择重传协议的一个混合体。

流量控制机制

TCP 提供了流量控制的服务,这个服务的主要目的是控制发送方的发送速率,保证接收方来得及接收。因为一旦发送的速率大于接收方所能接收的速率,就会造成报文段的丢失。接收方主要是通过接收窗口来告诉发送方自己所能接收的大小,发送方根据接收方的接收窗口的大小来调整发送窗口的大小,以此来达到控制发送速率的目的。

拥塞控制机制

TCP 的拥塞控制主要是根据网络中的拥塞情况来控制发送方数据的发送速率,如果网络处于拥塞的状态,发送方就减小发送的速率,这样一方面是为了避免继续增加网络中的拥塞程度,另一方面也是为了避免网络拥塞可能造成的报文段丢失。

TCP 的拥塞控制主要使用了四个机制,分别是慢启动、拥塞避免、快速重传和快速恢复

  • 慢启动的基本思想是,因为在发送方刚开始发送数据的时候,并不知道网络中的拥塞程度,所以先以较低的速率发送,进行试探,每次收到一个确认报文,就将发动窗口的长度加一,这样每个 RTT 时间后,发送窗口的长度就会加倍。当发送窗口的大小达到一个阈值的时候就进入拥塞避免算法。
  • 拥塞避免算法是为了避免可能发生的拥塞,将发送窗口的大小由每过一个 RTT 增长一倍,变为每过一个 RTT ,长度只加一。这样将窗口的增长速率由指数增长,变为加法线性增长。
  • 快速重传指的是,当发送方收到三个冗余的确认应答时,因为 TCP 使用的是累计确认的机制,所以很有可能是发生了报文段的丢失,因此采用立即重传的机制,在定时器结束前发送所有已发送但还未接收到确认应答的报文段。
  • 快速恢复是对快速重传的后续处理,因为网络中可能已经出现了拥塞情况,所以会将慢启动的阀值减小为原来的一半,然后将拥塞窗口的值置为减半后的阀值,然后开始执行拥塞避免算法,使得拥塞窗口缓慢地加性增大。简单来理解就是,乘性减,加性增。TCP 认为网络拥塞的主要依据是报文段的重传次数,它会根据网络中的拥塞程度,通过调整慢启动的阀值,然后交替使用上面四种机制来达到拥塞控制的目的。

TCP的四个定时器

重传定时器(RTO):

发送端向接收端发送TCP数据包,如果定时器时间计时结束还未接受到接收端返回的确认TCP数据包,则发送端重新发送该TCP数据包且同时重启拥塞机制(后面会具体说该机制)

重传定时器应用场景:重传定时器为了应对报文丢失或阻塞的情况:丢失就是发过去的报文没了,阻塞就是接收端处理不过来大量接收到的数据导致很久没响应发送端的数据包

重传定时器具体流程:

  1. 发送端向接收端发送数据时会开启重传定时器
  2. 如果重传定时器计时结束还没接受到响应数据(报文丢失或阻塞)
  3. 重传定时器重置且重新发送该数据

坚持定时器:

该定时器应用场景为滑动窗口,在发送端接受到零窗口通知之后,保证发送端能够收到之后接收端返回的窗口更新数据包

坚持定时器具体流程:

  1. 当发送端接收到接收端返回的零窗口通知(返回TCP表头中 Window=0
    发送端知道接收端缓冲区满了,暂时不向发送端发送数据,等待接收端处理完缓冲区数据发回窗口更新数据包(Window=大于0) 再发送数据
  2. 过了会接收端发回窗口更新数据包,于是发送端继续发送数据
    但是如果迟迟接收端未发回窗口更新数据包,发送端不能干等着,因为可能时接收端发回了窗口更新数据包,但丢失了导致发送端未接受到窗口更新数据包
  3. 所以在发送端接收到接收端返回的零窗口通知的时候也会同时开启坚持定时器
    坚持定时器计时结束还未收到接收端发回窗口更新数据包,发送端将发送窗口探测数据包向接收端请求窗口更新数据包,同时重置坚持定时器

保活定时器:

客户端与服务端建立TCP连接,如果服务端很久未接受到客户端发送的数据,在保活定时器计时结束的时候开始连续向客户端发送探测报文判断客户端是否发生故障,如果没有收到客户端响应,那么服务端认为客户端故障断开当前TCP连接,以节省资源。

tips:保活定时器每次接受到客户端发送的数据都会重置,一般为2小时,如果保活定时器计时结束,就会发送探测报文(连续发送10次,每次间隔75s)

时间等待计时器:

应用场景为四次挥手时启动,确保服务器能接收到最后一次挥手,即下图报文段7。 计网 - 图58

时间等待计时器具体流程:客户端收到服务器端第三次握手回应第四次握手的时候,会开启2MSL定时器,等待2MSL时间(1MSL即报文段最大存活时间),如果没有再次收到服务端第三次握手包即可以断开连接,如果再次收到了服务端第三次握手,说明客户端第四次握手数据丢失,服务端迟迟接收不到该确认,于是服务端重发第三次握手,客户端再次接收到第三次握手重置2MSL定时器,并重发第四次握手数据,所以等待2MSL就是防止第四次握手数据的丢失,导致客户端断开连接,服务端没断开,一直重发第三次握手。

TCP粘包

粘包:发送方发送两个字符串”hello”+”world”,接收方却一次性接收到了”helloworld”.

有时候,TCP为了提高网络的利用率,会使用一个叫做Nagle的算法.该算法是指,发送端即使有要发送的数据,如果很少的话,会延迟发送.如果应用层给TCP传送数据很快的话,就会把两个应用层数据包“粘”在一起,TCP最后只发一个TCP数据包给接收端.

分包:发送方发送字符串”helloworld”,接收方却接收到了两个字符串”hello”和”world”.

TCP是以段(Segment)为单位发送数据的,建立TCP链接后,有一个最大消息长度(MSS).如果应用层数据包超过MSS,就会把应用层数据包拆分,分成两个段来发送.这个时候接收端的应用层就要拼接这两个TCP包,才能正确处理数据.

KCP协议

KCP是一个快速可靠协议,纯算法实现,并不负责底层协议的收发,需要使用者自己定义下层数据包的发送方式,以callback的方式提供给KCP。

KCP数据发送过程

KCP是一个可靠的传输协议,UDP本身是不可靠的,所以需要额外信息来保证传输数据的可靠性。因此,我们需要在传输的数据上增加一个包头。用于确保数据的可靠、有序

  • 步骤1:待发送队列移至发送队列
  • 步骤2:发送发送队列的数据
    发送队列中包含两种类型的数据:
    • 已发送但是尚未被接收方确认的数据,没被发送过的数据。

      重点在于已经发送了但是还没被接收方确认的数据,该部分的策略直接决定着协议快速、高效与否。KCP主要使用三种策略来决定是否需要重传KCP数据包

      1. 超时重传
      2. 快速重传
      3. 选择重传。
  1. TCP超时计算是RTOx2,这样连续丢三次包就变成RTOx8了,而KCP非快速模式下每次+RTO,急速模式下+0.5RTO(实验证明1.5这个值相对比较好),提高了传输速度。
  1. 发送端发送了1,2,3,4,5几个包,然后收到远端的ACK: 1, 3, 4,
  2. 5,当收到ACK3时,KCP知道2被跳过1次,收到ACK4时,知道2被跳过了2次,此时可以认为2号丢失,不用等超时,直接重传2号包,大大改善了丢包时的传输速度。TCP有快速重传算法,TCP包被跳过3次之后会进行重传。
  3. 注:可以通过统计错误重传(重传的包实际没丢,仅乱序),优化该设置。
  1. 老的TCP丢包时会全部重传从丢的那个包开始以后的数据,KCP是选择性重传,只重传真正丢失的数据包。但是,目前大部分的操作系统,linuxandroid手机均是支持SACK选择重传的。
  • 没发送过的数据比较好处理,直接发送即可。
    • 步骤3:数据发送
      把较小的kcp包进行合并,一次性发送提高效率。

KCP流量控制

KCP的发送机制采用TCP的滑动窗口方式,可以非常容易的控制流量。KCP的主要特色在于实时性高,对于实时性高的应用,如果发生数据堆积会造成延迟的持续增大。建议从应用侧更好的控制发送流量与网络速度持平,避免缓存堆积延迟。

KCP拥塞控制(可关闭)

KCP的优势在于可以完全关闭拥塞控制,非常自私的进行发送。KCP采用的拥塞控制策略为TCP最古老的策略,无任何优势。完全关闭拥塞控制,也不是一个最优策略,它全是会造成更为拥堵的情况。

QUIC

QUIC协议是一个通用的传输层协议,它基于UDP协议创造,旨在保留UDP协议速度的同时拥有几乎与TCP协议相同的可靠性。QUIC协议提高了目前的TCP应用的性能,它通过UDP连接在两个端点之间创建多个多路连接来实现这一目标。

零 RTT 建立连接

Step1:首次连接时,客户端发送 Inchoate Client Hello 给服务端,用于请求连接;

Step2:服务端生成 g、p、a,根据 g、p 和 a 算出 A,然后将 g、p、A 放到 Server Config 中再发送 Rejection 消息给客户端;

Step3:客户端接收到 g、p、A 后,自己再生成 b,根据 g、p、b 算出 B,根据 A、p、b 算出初始密钥 K。B 和 K 算好后,客户端会用 K 加密 HTTP 数据,连同 B 一起发送给服务端;

Step4:服务端接收到 B 后,根据 a、p、B 生成与客户端同样的密钥,再用这密钥解密收到的 HTTP 数据。为了进一步的安全(前向安全性),服务端会更新自己的随机数 a 和公钥,再生成新的密钥 S,然后把公钥通过 Server Hello 发送给客户端。连同 Server Hello 消息,还有 HTTP 返回数据;

Step5:客户端收到 Server Hello 后,生成与服务端一致的新密钥 S,后面的传输都使用 S 加密。

计网 - 图59

连接迁移

TCP 连接基于四元组(源 IP、源端口、目的 IP、目的端口),切换网络时至少会有一个因素发生变化,导致连接发生变化。当连接发生变化时,如果还使用原来的 TCP 连接,则会导致连接失败,就得等原来的连接超时后重新建立连接,所以我们有时候发现切换到一个新网络时,即使新网络状况良好,但内容还是需要加载很久。如果实现得好,当检测到网络变化时立刻建立新的 TCP 连接,即使这样,建立新的连接还是需要几百毫秒的时间。

QUIC 的连接不受四元组的影响,当这四个元素发生变化时,原连接依然维持。那这是怎么做到的呢?道理很简单,QUIC 连接不以四元组作为标识,而是使用一个 64 位的随机数,这个随机数被称为 Connection ID,即使 IP 或者端口发生变化,只要 Connection ID 没有变化,那么连接依然可以维持。

计网 - 图60

解决队头阻塞

  • QUIC 的传输单元是 Packet,加密单元也是 Packet,整个加密、传输、解密都基于 Packet,这样就能避免 TLS 的队头阻塞问题;
  • QUIC 基于 UDP,UDP 的数据包在接收端没有处理顺序,即使中间丢失一个包,也不会阻塞整条连接,其他的资源会被正常处理。

拥塞控制

TCP 拥塞控制由 4 个核心算法组成:慢启动、拥塞避免、快速重传和快速恢复

QUIC 改进的拥塞控制的特性:

  • 热插拔
  • 前向纠错 FEC
  • 单调递增的 Packet Number
  • ACK Delay
  • ACK Delay

流量控制

TCP 会对每个 TCP 连接进行流量控制,流量控制的意思是让发送方不要发送太快,要让接收方来得及接收,不然会导致数据溢出而丢失,TCP 的流量控制主要通过滑动窗口来实现的。

QUIC 只需要建立一条连接,在这条连接上同时传输多条 Stream,好比有一条道路,两头分别有一个仓库,道路中有很多车辆运送物资。QUIC 的流量控制有两个级别:连接级别(Connection Level)和 Stream 级别(Stream Level),好比既要控制这条路的总流量,不要一下子很多车辆涌进来,货物来不及处理,也不能一个车辆一下子运送很多货物,这样货物也来不及处理。

详情见HTTP/3 原理实战 - 知乎 (zhihu.com)

计网 - 图61 网络安全

XSS攻击与预防

XSS(cross-site scripting):跨站脚本攻击,就是攻击者想尽一切办法将可执行代码(主要是恶意代码)注入网页,打开网页将执行这些恶意代码(比如获取用户cookie,token)。常见三种XSS,存储型XSS ,反射型XSS,DOM型XSS

  • 存储型XSS:
    1. 攻击者将恶意代码提交到网站数据库中
    2. 用户打开目标网站,服务器将恶意代码从数据库中取出,拼接在html返回给用户
    3. 浏览器响应解析该html,恶意代码被执行,用户中招。

存储型XSS例子:比如论坛回复中包含恶意代码,服务端未对回复进行校验直接存储进数据库,当人们访问回复列表页面,回复资源来源于数据库,且包含恶意代码导致用户中招。

  • 反射型XSS:
    1. 攻击者构建特殊的url,其中url参数中包含恶意代码
    2. 用户被诱使访问该url,网站服务端将恶意代码从url取出,拼接在html上返回给用户。
    3. 浏览器响应解析该html,恶意代码被执行,用户中招。

反射型XSS例子:比如下图搜索框输入恶意代码,点击百度一下,服务器未对恶意代码进行处理,返回的数据直接拼接搜索内容,浏览器接收解析这些返回数据就会中招。

  • DOM型XSS:
    1. 攻击者构建特殊url,url包含恶意代码
    2. 用户被诱使访问该url,前端获取url中的恶意代码并执行,比如取出url参数使用innerHtml展示在页面上,由于url参数包含恶意代码,导致恶意代码被执行。

DOM型XSS例子:比如前端操作页面的输入框的输入内容会放入url参数中且当前页面会获取url参数展示输入框内容,此时只要攻击者构建包含恶意代码的url诱使用户点击即可。

预防

  1. 输入检查:针对于不同场景限制允许输入的字符,比如对输入电话号码限制电话号码纯数字11位,避免了该输入框输入js脚本的可能。当然如果攻击者直接绕过前端过滤,直接伪造请求输入检查的意义就不大了。
  2. 输出检查:严格的输出编码,html编码,js编码,css编码,url编码等。比如将 &<>"'/ 转义掉。 <div><</div>=> <div>&lt;</div>,浏览器解析到的是 &lt; 而不是 <
  3. 设置CSP(Content-Security-Policy) http header:通过这种自建白名单的方式增加XSS攻击难度,由浏览器进行拦截。比如设置信任的域名。
  4. cookie设置httpOnly属性:response.setHeader('Set-Cookie', 'token=xx;HttpOnly');,该属性能够阻止js读取cookie。
  5. 验证码操作,防止脚本冒充用户提交危险操作。

CSRF攻击与预防

CSRF攻击(cross site request forgery):跨站请求伪造,攻击者借助受害者的凭证(cookie)伪装成用户向服务器发送伪造请求。

  1. 攻击者诱使用户进入第三方网站
  2. 在第三方网站中向被攻击网站发出请求
  3. 利用用户在被攻击网站先前已经获取的注册凭证,绕过网站对请求的验证,从而冒充用户进行某项操作

预防:

  1. 对响应头的Cookie设置SameSite属性
    • SameSite:Strict:cookie不允许跨站发送,只能是同站发送
    • SameSite:Lax:cookie允许跨站发送,但只能是get请求
  2. 验证Referer:服务器验证请求头中的Referer(服务器当前请求来源url,包括协议域名端口以及参数)或者Origin(服务器当前请求来源url,包括协议域名端口),判断是否是第三方网站发起的请求。(refer信息可以伪造不安全)
  3. 使用token:放弃使用cookie对用户校验,而是使用token进行校验,服务器对客户端发放token,客户端保存token,每次请求都会将token放入请求头中,服务器对token进行校验。(crsf只是依靠浏览器自己携带cookie,并不可以进行取出token,将token 放入请求头中的操作。)

中间人攻击

中间人攻击(MITM:MAN IN THE MIDDLE):当数据离开一个端点前往另一个端点时,数据传输的过程便是对数据失去控制的过程,此时当一个中间人位于两个端点之间对数据进行劫持转发,称为中间人攻击。

攻击手段

  • 非HTTPS时:当我们使用http进行传输数据,由于数据为明文传输,此时如果DNS遭到劫持,客户端的数据发送到中间人的服务器上,中间人继续转发客户端的数据至目标服务器,同理,目标服务器的数据回到中间人服务器,中间人继续转发目标服务器的数据给客户端,对于客户端与目标服务器是无感知的,其实数据已经被中间人劫持导致数据泄露。
  • SSL劫持:SSL劫持即SSL证书欺骗,使用HTTPS时,由于SSL协议需要进行握手处理,此时数据依旧是明文传输,如果此时中间人接入到客户端与目标服务器之间,在传输过程中伪造目标服务器发过来的证书,同时将伪造证书发送给客户端,正常客户端是会提示证书错误(因为证书一般由权威机构颁发),如果客户端忽略该错误继续发送数据,那么客户端使用的将是伪造证书中的公钥加密SSL协议第三个随机数,中间人通过私钥解析出客户端发送的第三个随机数,加上传输过程中明文发送的客户端随机数以及服务端随机数还有客户端与目标服务器指定的加密方法生成之后客户端与目标服务端对称加密的密钥,即可获得客户端与目标服务端的通讯信息。
  • SSL剥离:该方式为中间人将服务器返回的https范文替换成http返回给客户端,而中间人与服务端保持https进行沟通,这样客户端的http明文将被中间人获取,同时中间人将该http明文替换成https发送给服务端,伪装成客户端通讯,这样导致客户端与服务端的通讯信息被中间人劫持。
  • tips:关于CA证书被中间人解析出公钥的问题:其实中间人解析出公钥也没事,因为公钥最后还是要发到客户端手上,客户端利用公钥加密最后信息,回到中间人手中,中间人手中只有公钥,无私钥,所以无法解析出加密后的信息,所以CA证书即使中间人劫持了,也用不了其中的公钥。

HSTS(防止301/302重定向劫持)

HSTS最为核心的是一个HTTP响应头(HTTP Response Header)。正是它可以让浏览器得知,在接下来的一段时间内,当前域名只能通过HTTPS进行访问,并且在浏览器发现当前连接不安全的情况下,强制拒绝用户的后续访问要求。

HSTS Header的语法如下:

  1. Strict-Transport-Security: <max-age=>[; includeSubDomains][; preload]
  1. 有些网站开启了HTTPS,但是用户大多输入域名并不会加上协议,比如直接输入baidu.com访问百度服务器
  2. 那么这时候浏览器时先按照http://www.baidu.com进行访问
  3. 百度服务器发现是http请求,这是不安全的,于是响应一个302重定向response让客户端重定向至https://www.baidu.com
  4. 客户端接收到重定向响应信息,于是重定向至https://www.baidu.com让浏览器直接发起HTTPS请求

前面HSTS解决问题第四步:

4,客户端接收到重定向响应信息,于是重定向至: https://www.baidu.com

  1. 在这一步,客户端重定向至https://www.baidu.com,服务器端响应该请求,且该请求响应头会包含Strict-Transport-Security字段,该字段会告诉客户端之后每次请求你都要使用https请求我。当下一次客户端访问baidu.com就会直接浏览器内部307重定向至https://www.baidu.com。

HSTS缺陷:HSTS无法解决第一次访问时的HTTP请求,只能要求客户端第一次以后每次访问都使用HTTPS请求。

解决HSTS缺陷:浏览器发起请求前都会检查一个由浏览器维护的HSTS预加载列表,只要请求地址在该列表中,我们就会强制浏览器使用https请求,所以我们只需要将服务器地址加入到HSTS预加载列表中即可解决HSTS存在的缺陷。当我们在HSTS Preload List的官网申请加入将服务器地址加入HSTS预加载列表时,有诸多要求,其中一个要求就是在HTTP响应头加入Strict-Transport-Security,且必须包含includesSubDomains与preload参数。

HSTS优点 :

  1. 强制使用HTTPS建立安全连接防止重定向劫持以及中间人SSL剥离攻击。
  2. 省略从前http访问服务器,服务器响应,客户端再重定向的步骤,节省时间与资源。
  3. 无HSTS浏览器显示证书错误时用户可以选择忽略警告继续访问,有了HSTS之后证书错误时无目标页链接入口,防止中间人使用SSL劫持攻击。

流量劫持

计网 - 图62

一、Hosts劫持

本劫持是最基本,最简单的一种系统自带的劫持法,是通过修改系统的HOSTS文件来达到劫持的效果,HOSTS的劫持格式一帮位(如:127.0.0.1 http://www.xxxx.com)IP的后面应有一个空格,即表示为把百度劫持到本地,127.0.0.1表示本地IP,http://www.xxxx.com 表示为您要劫持的网站。这种劫持法的效果一般为域名不变内容却被劫持了(如:打开http://www.123.com http://www.1234.com等等,其域名不变还是123和1234,但内容更换了)。

二、 域名劫持功能

本劫持是通过IE浏览器取句柄,判断浏览器地址然后执行跳转,达到跳转劫持的效果!如访问http://www.xxx1.com 则会跳转到http://www.xxx2.com或者是http://www.xxx3.com IE地址栏内的域名则会变成这俩者间的任意一个域名.

三、关键词劫持

本劫持是通过IE浏览器取网页标题,判断浏览器标题然后执行跳转,达到跳转劫持的效果!

四、LSP劫持功能

本劫持插件是网截, LSP劫持后的站其域名不变。内容则是劫持到的网站内容,(如:打开http://www.xxx.com http://www.zzz.com等等,其域名不变还是百度和QQ,但内容改变了,而且鼠标点击网页属性右键还是查看不到您的站,还是原来的域名。其隐蔽性高,被用户发现的几率也很小,不容易引起用户访问后的注意)

五、混合型劫持

本劫持是使用关键词劫持同时也可以使用域名劫持,就是关键词和域名可以同时使用,同时劫持,域名和关键词同时混合到了一起,称之为混合型劫持。混合型劫持功能强大无比,只要混合型劫持了,别人的插件或者第三方软件是无法修改的,手动也删除不掉,修改不了。

六、DNS劫持

本DNS劫持是通过修改客户的DNS主服务器IP和备用服务器IP来达到劫持的效果,只劫持内容,域名不变,也可以跳转新的劫持,也就是说域名和内容都有变化,比如劫持了http://www.xxx1.com劫持到别人的网站,当别人访问http://www.xxx1.com的时候域名还是他原来的域名,但是内容确实我们劫持到的内容了,这个就是叫做只劫持内容其域名不变也可以跳转行的劫持,比如劫持了http://www.xxx2.com那么打开后域名也会跟着随之变化,这个就是叫做跳转性的劫持

计网 - 图63 其他

cookie

cookie是服务端发送给客户端一段文本信息,客户端保存起来,下一次在访问该服务端,客户端自动带上这段文本信息发送给服务端。

cookie用途:http协议是无状态的,第一次请求与第二次请求服务器并不知道是同一个客户端发送的请求,但如果第二次请求带上了第一次请求服务器端返回的cookie那么服务端就知道这两次请求是来自同一个客户端。(比如某个网站的第二次登录就不需要手动登录,直接携带cookie发送给服务器,服务器验证cookie信息正确即可)

cookie特性 :

  • 请求自动携带cookie:简而言之cookie在浏览器发出请求会自动携带一并发出
  • 不可跨域名性:该特性由浏览器维护,浏览器会根据请求地址确定携带哪一个域名下的cookie。
    • 二级域名问题:比如a.com与b.a.com,如果期望一级域名a下二级域名b也可以携带a.com的cookie,可以设置cookie.SetDomain(‘.a.com’),这样a.com下的二级域名就可以使用该cookie
    • 路径问题:比如www.a.com/file路径访问是无法携带www.a.com的cookie的,如果我们期望www.a.com/file可以携带www.a.com的cookie,可以设置cookie.setPath(/file/),如果www.a.com+任意路径都可以携带该cookie,则设置cookie.setPath(/)

服务端设置cookie:

  1. ctx.set('Set-cookie', 'name=value;path=/user;domain=localhost;max-age=30;HttpOnly;SameSite=Strict')

cookie属性:

  • path&domain:指定域名domain+路径path,浏览器请求url与该指定url相同时才携带cookie。
  • expires:expires服务器指定cookie过期时间戳,到期浏览器不再保存该cookie。
  • max-age:max-age指定cookie存活多少秒,过期浏览器不再保存该cookie。与expires同时出现以max-age为准。如果二者都没出现,那么本次cookie仅在本次对话存在,浏览器窗口关闭,则浏览器不再保存此cookie
  • HttpOnly:服务器指定该字段,则浏览器不能使用document.cookie读取cookie。
  • secure:该属性是个标记没有值,包含secure的cookie只有当https或其他安全协议时浏览器才会携带cookie,如果希望在浏览器端设置该字段,需确保网页为https协议,http是无法设置该字段的。
  • sameSite:该字段有两个值strict与lax,默认strict。
    • strict:不允许跨站发送cookie,只允许当前网站发送cookie。
    • lax:允许跨站请求携带,但只能是get,如果是post,则不会携带cookie。

浏览器操作cookie:

  • 读cookie:var cookie_ = document.cookie
  • 新建cookie:document.cookie = ‘name1 = value1;path:/;domain:localhost;max-age=30’
  • 替换cookie:使用新建cookie方式保持同名即可替换原有cookie。document.cookie = ‘name1 = value2;path:/;domain:localhost;max-age=30’
  • 删除cookie:删除name3的cookie:document.cookie = ‘name3=value3;max-age=0’,设置cookie的max-age为0即可删除,设置max-age<0则cookie仅存于当前会话,浏览器窗口关闭,cookie消失。

cookie预防XSS与CRSF

  • cookie设置HttpOnly,禁止客户端使用document.cookie访问cookie,预防xss攻击获取cookie。
  • cookie设置sameSite:strict,禁止所有第三方网站携带cookie访问服务器,预防CRSF攻击。

session

保存在服务端用来记录客户端信息的一块数据。与cookie一样也是为了解决http无状态的特点。

session生成流程:

  1. 客户端第一次访问服务端,服务端为客户端生成一个session与sessionID,session保存客户端信息,sessionID标识session存储位置,并将sessionID返回给客户端(一般放在cookie中)
  2. 客户端下一次访问该服务端会携带cookie
  3. 服务端接受到客户端再一次访问,获取cookie中的sessionID,查找存储中对应的session,获取当前客户端信息。

与cookie区别:

  • session依靠cookie实现,sessionID存放在cookie中(禁用可以使用url重写完成,放在url中)
  • cookie保存在客户端,session保存在服务端
  • cookie一般4kb大小,session无大小限制

计网 - 图64 常考面试题

计网 - 图65 Post 和 Get 的区别?

  1. Post Get HTTP 请求的两种方法。
  2. 1)从应用场景上来说,GET 请求是一个幂等的请求,一般 Get 请求用于对服务器资源不会产生影响的场景,比如说请求一个网页。而 Post 不是一个幂等的请求,一般用于对服务器资源会产生影响的情景。比如注册用户这一类的操作。
  3. 2)因为不同的应用场景,所以浏览器一般会对 Get 请求缓存,但很少对 Post 请求缓存。
  4. 3)从发送的报文格式来说,Get 请求的报文中实体部分为空,Post 请求的报文中实体部分一般为向服务器发送的数据。
  5. 4)但是 Get 请求也可以将请求的参数放入 url 中向服务器发送,这样的做法相对于 Post 请求来说,一个方面是不太安全,因为请求的 url 会被保留在历史记录中。并且浏览器由于对 url 有一个长度上的限制,所以会影响 get 请求发送数据时的长度。这个限制是浏览器规定的,并不是 RFC 规定的。还有就是 post 的参数传递支持更多的数据类型。

计网 - 图66 TLS/SSL 中什么一定要用三个随机数,来生成”会话密钥”?

  1. 客户端和服务器都需要生成随机数,以此来保证每次生成的秘钥都不相同。使用三个随机数,是因为 SSL 的协议默认不信任每个主机都能产生完全随机的数,如果只使用一个伪随机的数来生成秘钥,就很容易被破解。通过使用三个随机数的方式,增加了自由度,一个伪随机可能被破解,但是三个伪随机就很接近于随机了,因此可以使用这种方法来保持生成秘钥的随机性和安全性。

计网 - 图67SSL 连接断开后如何恢复?

  1. 一共有两种方法来恢复断开的 SSL 连接,一种是使用 session ID,一种是 session ticket
  2. 使用 session ID 的方式,每一次的会话都有一个编号,当对话中断后,下一次重新连接时,只要客户端给出这个编号,服务器如果有这个编号的记录,那么双方就可以继续使用以前的秘钥,而不用重新生成一把。目前所有的浏览器都支持这一种方法。但是这种方法有一个缺点是,session ID 只能够存在一台服务器上,如果我们的请求通过负载平衡被转移到了其他的服务器上,那么就无法恢复对话。
  3. 另一种方式是 session ticket 的方式,session ticket 是服务器在上一次对话中发送给客户的,这个 ticket 是加密的,只有服务器能够解密,里面包含了本次会话的信息,比如对话秘钥和加密方法等。这样不管我们的请求是否转移到其他的服务器上,当服务器将 ticket 解密以后,就能够获取上次对话的信息,就不用重新生成对话秘钥了。

计网 - 图68RSA 算法的安全性保障?

  1. 对极大整数做因数分解的难度决定了 RSA 算法的可靠性。换言之,对一极大整数做因数分解愈困难,RSA 算法愈可靠。现在1024位的 RSA 密钥基本安全,2048位的密钥极其安全。

计网 - 图69DNS 为什么使用 UDP 协议作为传输层协议?

  1. DNS 使用 UDP 协议作为传输层协议的主要原因是为了避免使用 TCP 协议时造成的连接时延。因为为了得到一个域名的 IP 地址,往往会向多个域名服务器查询,如果使用 TCP 协议,那么每次请求都会存在连接时延,这样使 DNS 服务变得很慢,因为大多数的地址查询请求,都是浏览器请求页面时发出的,这样会造成网页的等待时间过长。
  2. 使用 UDP 协议作为 DNS 协议会有一个问题,由于历史原因,物理链路的最小MTU = 576,所以为了限制报文长度不超过576UDP 的报文段的长度被限制在 512 个字节以内,这样一旦 DNS 的查询或者应答报文,超过了 512 字节,那么基于 UDP DNS 协议就会被截断为 512 字节,那么有可能用户得到的 DNS 应答就是不完整的。这里 DNS 报文的长度一旦超过限制,并不会像 TCP 协议那样被拆分成多个报文段传输,因为 UDP 协议不会维护连接状态,所以我们没有办法确定那几个报文段属于同一个数据,UDP 只会将多余的数据给截取掉。为了解决这个问题,我们可以使用 TCP 协议去请求报文。
  3. DNS 还存在的一个问题是安全问题,就是我们没有办法确定我们得到的应答,一定是一个安全的应答,因为应答可以被他人伪造,所以现在有了 DNS over HTTPS 来解决这个问题。

详细资料可以参考:
《为什么 DNS 使用 UDP 而不是 TCP?》

计网 - 图70当你在浏览器中输入 Google.com 并且按下回车之后发生了什么?

  1. 1)首先会对 URL 进行解析,分析所需要使用的传输协议和请求的资源的路径。如果输入的 URL 中的协议或者主机名不合法,将会把地址栏中输入的内容传递给搜索引擎。如果没有问题,浏览器会检查 URL 中是否出现了非法字符,如果存在非法字符,则对非法字符进行转义后再进行下一过程。
  2. 2)浏览器会判断所请求的资源是否在缓存里,如果请求的资源在缓存里并且没有失效,那么就直接使用,否则向服务器发起新的请求。
  3. 3)下一步我们首先需要获取的是输入的 URL 中的域名的 IP 地址,首先会判断本地是否有该域名的 IP 地址的缓存,如果有则使用,如果没有则向本地 DNS 服务器发起请求。本地 DNS 服务器也会先检查是否存在缓存,如果没有就会先向根域名服务器发起请求,获得负责的顶级域名服务器的地址后,再向顶级域名服务器请求,然后获得负责的权威域名服务器的地址后,再向权威域名服务器发起请求,最终获得域名的 IP 地址后,本地 DNS 服务器再将这个 IP 地址返回给请求的用户。用户向本地 DNS 服务器发起请求属于递归请求,本地 DNS 服务器向各级域名服务器发起请求属于迭代请求。
  4. 4)当浏览器得到 IP 地址后,数据传输还需要知道目的主机 MAC 地址,因为应用层下发数据给传输层,TCP 协议会指定源端口号和目的端口号,然后下发给网络层。网络层会将本机地址作为源地址,获取的 IP 地址作为目的地址。然后将下发给数据链路层,数据链路层的发送需要加入通信双方的 MAC 地址,我们本机的 MAC 地址作为源 MAC 地址,目的 MAC 地址需要分情况处理,通过将 IP 地址与我们本机的子网掩码相与,我们可以判断我们是否与请求主机在同一个子网里,如果在同一个子网里,我们可以使用 APR 协议获取到目的主机的 MAC 地址,如果我们不在一个子网里,那么我们的请求应该转发给我们的网关,由它代为转发,此时同样可以通过 ARP 协议来获取网关的 MAC 地址,此时目的主机的 MAC 地址应该为网关的地址。
  5. 5)下面是 TCP 建立连接的三次握手的过程,首先客户端向服务器发送一个 SYN 连接请求报文段和一个随机序号,服务端接收到请求后向服务器端发送一个 SYN ACK报文段,确认连接请求,并且也向客户端发送一个随机序号。客户端接收服务器的确认应答后,进入连接建立的状态,同时向服务器也发送一个 ACK 确认报文段,服务器端接收到确认后,也进入连接建立状态,此时双方的连接就建立起来了。
  6. 6)如果使用的是 HTTPS 协议,在通信前还存在 TLS 的一个四次握手的过程。首先由客户端向服务器端发送使用的协议的版本号、一个随机数和可以使用的加密方法。服务器端收到后,确认加密的方法,也向客户端发送一个随机数和自己的数字证书。客户端收到后,首先检查数字证书是否有效,如果有效,则再生成一个随机数,并使用证书中的公钥对随机数加密,然后发送给服务器端,并且还会提供一个前面所有内容的 hash 值供服务器端检验。服务器端接收后,使用自己的私钥对数据解密,同时向客户端发送一个前面所有内容的 hash 值供客户端检验。这个时候双方都有了三个随机数,按照之前所约定的加密方法,使用这三个随机数生成一把秘钥,以后双方通信前,就使用这个秘钥对数据进行加密后再传输。
  7. 7)当页面请求发送到服务器端后,服务器端会返回一个 html 文件作为响应,浏览器接收到响应后,开始对 html 文件进行解析,开始页面的渲染过程。
  8. 8)浏览器首先会根据 html 文件构建 DOM 树,根据解析到的 css 文件构建 CSSOM 树,如果遇到 script 标签,则判端是否含有 defer 或者 async 属性,要不然 script 的加载和执行会造成页面的渲染的阻塞。当 DOM 树和 CSSOM 树建立好后,根据它们来构建渲染树。渲染树构建好后,会根据渲染树来进行布局。布局完成后,最后使用浏览器的 UI 接口对页面进行绘制。这个时候整个页面就显示出来了。
  9. 9)最后一步是 TCP 断开连接的四次挥手过程。

详细资料可以参考:
《当你在浏览器中输入 Google.com 并且按下回车之后发生了什么?》

计网 - 图71谈谈 CDN 服务?

  1. CDN 是一个内容分发网络,通过对源网站资源的缓存,利用本身多台位于不同地域、不同运营商的服务器,向用户提供资就近访问的功能。也就是说,用户的请求并不是直接发送给源网站,而是发送给 CDN 服务器,由 CND 服务器将请求定位到最近的含有该资源的服务器上去请求。这样有利于提高网站的访问速度,同时通过这种方式也减轻了源服务器的访问压力。

详细资料可以参考:
《CDN 是什么?使用 CDN 有什么优势?》

计网 - 图72什么是正向代理和反向代理?

  1. 我们常说的代理也就是指正向代理,正向代理的过程,它隐藏了真实的请求客户端,服务端不知道真实的客户端是谁,客户端请求的服务都被代理服务器代替来请求。
  2. 反向代理隐藏了真实的服务端,当我们请求一个网站的时候,背后可能有成千上万台服务器为我们服务,但具体是哪一台,我们不知道,也不需要知道,我们只需要知道反向代理服务器是谁就好了,反向代理服务器会帮我们把请求转发到真实的服务器那里去。反向代理器一般用来实现负载平衡。

详细资料可以参考:
《正向代理与反向代理有什么区别》
《webpack 配置 proxy 反向代理的原理是什么?》

计网 - 图73 负载平衡的两种实现方式?

  1. 一种是使用反向代理的方式,用户的请求都发送到反向代理服务上,然后由反向代理服务器来转发请求到真实的服务器上,以此来实现集群的负载平衡。
  2. 另一种是 DNS 的方式,DNS 可以用于在冗余的服务器上实现负载平衡。因为现在一般的大型网站使用多台服务器提供服务,因此一个域名可能会对应多个服务器地址。当用户向网站域名请求的时候,DNS 服务器返回这个域名所对应的服务器 IP 地址的集合,但在每个回答中,会循环这些 IP 地址的顺序,用户一般会选择排在前面的地址发送请求。以此将用户的请求均衡的分配到各个不同的服务器上,这样来实现负载均衡。这种方式有一个缺点就是,由于 DNS 服务器中存在缓存,所以有可能一个服务器出现故障后,域名解析仍然返回的是那个 IP 地址,就会造成访问的问题。

详细资料可以参考:
《负载均衡的原理》

计网 - 图74http 请求方法 options 方法有什么用?

  1. OPTIONS 请求与 HEAD 类似,一般也是用于客户端查看服务器的性能。这个方法会请求服务器返回该资源所支持的所有 HTTP 请求方法,该方法会用'*'来代替资源名称,向服务器发送 OPTIONS 请求,可以测试服务器功能是否正常。JS XMLHttpRequest 对象进行 CORS 跨域资源共享时,对于复杂请求,就是使用 OPTIONS 方法发送嗅探请求,以判断是否有对指定资源的访问权限。

相关资料可以参考:
《HTTP 请求方法》

计网 - 图75http1.1 和 http1.0 之间有哪些区别?

  1. http1.1 相对于 http1.0 有这样几个区别:
  2. 1)连接方面的区别,http1.1 默认使用持久连接,而 http1.0 默认使用非持久连接。http1.1 通过使用持久连接来使多个 http 请求复用同一个 TCP 连接,以此来避免使用非持久连接时每次需要建立连接的时延。
  3. 2)资源请求方面的区别,在 http1.0 中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,http1.1 则在请求头引入了 range 头域,它允许只请求资源的某个部分,即返回码是 206Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。
  4. 3)缓存方面的区别,在 http1.0 中主要使用 header 里的 If-Modified-Since,Expires 来做为缓存判断的标准,http1.1 则引入了更多的缓存控制策略例如 EtagIf-Unmodified-SinceIf-MatchIf-None-Match 等更多可供选择的缓存头来控制缓存策略。
  5. 4http1.1 中还新增了 host 字段,用来指定服务器的域名。http1.0 中认为每台服务器都绑定一个唯一的 IP 地址,因此,请求消息中的 URL 并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机,并且它们共享一个IP地址。因此有了 host 字段,就可以将请求发往同一台服务器上的不同网站。
  6. 5http1.1 相对于 http1.0 还新增了很多方法,如 PUTHEADOPTIONS 等。

详细资料可以参考:
《HTTP1.0、HTTP1.1 和 HTTP2.0 的区别》
《HTTP 协议入门》
《网络—-一篇文章详解请求头 Host 的概念》

计网 - 图76网站域名加 www 与不加 www 的区别?

  1. wwwWorld Wide Web)是标识这是一个需要你用浏览器来访问的网页服务,而不是需要你用telnet访问的bbs,或者ftp工具访问的文件传输服务,所以那个时候,网站主页的域名前面要用www
  2. 总的来说对于大访问量或多子域名的网站来说,不建议使用裸域。
  3. 裸域的 cookie 的作用范围太大。假如知乎也采用裸域,那么知乎所有 cookie 的作用范围就包括 http://zhihu.com 下的所有子域名。也就是说访问 http://foo.zhihu.com 和 http://bar.zhihu.com 的时候都会带上 http://zhihu.com 裸域页面设置的 cookie。从安全、隐私、可扩展性、以及管理的角度而言,这对很多大型网站来说是不可接受的。

详细资料可以参考:
《为什么域名前要加 www 前缀 www 是什么意思?》
《为什么越来越多的网站域名不加「www」前缀?》
《域名有 www 与没有 www 有什么区别?》

计网 - 图77即时通讯的实现,短轮询、长轮询、SSE 和 WebSocket 间的区别?

  1. 短轮询和长轮询的目的都是用于实现客户端和服务器端的一个即时通讯。
  2. 短轮询的基本思路就是浏览器每隔一段时间向浏览器发送 http 请求,服务器端在收到请求后,不论是否有数据更新,都直接进行响应。这种方式实现的即时通信,本质上还是浏览器发送请求,服务器接受请求的一个过程,通过让客户端不断的进行请求,使得客户端能够模拟实时地收到服务器端的数据的变化。这种方式的优点是比较简单,易于理解。缺点是这种方式由于需要不断的建立 http 连接,严重浪费了服务器端和客户端的资源。当用户增加时,服务器端的压力就会变大,这是很不合理的。
  3. 长轮询的基本思路是,首先由客户端向服务器发起请求,当服务器收到客户端发来的请求后,服务器端不会直接进行响应,而是先将这个请求挂起,然后判断服务器端数据是否有更新。如果有更新,则进行响应,如果一直没有数据,则到达一定的时间限制才返回。客户端 JavaScript 响应处理函数会在处理完服务器返回的信息后,再次发出请求,重新建立连接。长轮询和短轮询比起来,它的优点是明显减少了很多不必要的 http 请求次数,相比之下节约了资源。长轮询的缺点在于,连接挂起也会导致资源的浪费。
  4. SSE 的基本思想是,服务器使用流信息向服务器推送信息。严格地说,http 协议无法做到服务器主动推送信息。但是,有一种变通方法,就是服务器向客户端声明,接下来要发送的是流信息。也就是说,发送的不是一次性的数据包,而是一个数据流,会连续不断地发送过来。这时,客户端不会关闭连接,会一直等着服务器发过来的新的数据流,视频播放就是这样的例子。SSE 就是利用这种机制,使用流信息向浏览器推送信息。它基于 http 协议,目前除了 IE/Edge,其他浏览器都支持。它相对于前面两种方式来说,不需要建立过多的 http 请求,相比之下节约了资源。
  5. 上面三种方式本质上都是基于 http 协议的,我们还可以使用 WebSocket 协议来实现。WebSocket Html5 定义的一个新协议,与传统的 http 协议不同,该协议允许由服务器主动的向客户端推送信息。使用 WebSocket 协议的缺点是在服务器端的配置比较复杂。WebSocket 是一个全双工的协议,也就是通信双方是平等的,可以相互发送消息,而 SSE 的方式是单向通信的,只能由服务器端向客户端推送信息,如果客户端需要发送信息就是属于下一个 http 请求了。

详细资料可以参考:
《轮询、长轮询、长连接、websocket》
《Server-Sent Events 教程》
《WebSocket 教程》

计网 - 图78怎么实现多个网站之间共享登录状态

  1. 在多个网站之间共享登录状态指的就是单点登录。多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。
  2. 我认为单点登录可以这样来实现,首先将用户信息的验证中心独立出来,作为一个单独的认证中心,该认证中心的作用是判断客户端发送的账号密码的正确性,然后向客户端返回对应的用户信息,并且返回一个由服务器端秘钥加密的登录信息的 token 给客户端,该token 具有一定的有效时限。当一个应用系统跳转到另一个应用系统时,通过 url 参数的方式来传递 token,然后转移到的应用站点发送给认证中心,认证中心对 token 进行解密后验证,如果用户信息没有失效,则向客户端返回对应的用户信息,如果失效了则将
  3. 页面重定向会单点登录页面。

计网 - 图79cookie与token都放在请求头中,为什么只能劫持前者。

  1. 因为浏览器向服务器发送请求会自动带上cookie,而CRSF正式利用这一点假冒登陆者,但是CRSF攻击依靠的是cookie机制访问服务器自动携带,而不能获取到用户cookie。而token即使存在cookie中,自动携带发送到服务端,服务端验证的是请求头中的token而不是cookie,所以只要没设置token就无法验证通过,token需要客户端设置请求头发送给客户端,CRSF无法做到这一点,所以不能劫持token

计网 - 图80http2如何确保文件传输不会出错

  1. 根据前面介绍的http2帧概念流概念以及多路传输特性,我们知道虽然一个tcp连接内有多个很多帧在传输且属于不同的请求,但是帧头有Stream Identifier字段帮助我们判断当前帧属于哪个流,一个流属于一组请求-回复数据交互过程,所以再接收端按照帧头的Stream Identifier进行帧的组合即可得到原先的完整请求。

计网 - 图81什么是http协议,http工作流程

http协议:超文本传输协议(HTTP Hypertext transfer protocol)是基于应用层的协议,规定了浏览器与服务器之间相互通讯的规则。

http工作流程:

  • 浏览器发出http请求报文
  • 建立TCP连接(三次握手)
  • 传输http请求
  • 服务器响应http请求
  • 释放TCP连接(四次挥手)

计网 - 图82 简述V8引擎

V8引擎是用来专门处理JS脚本的虚拟机,是谷歌浏览器、node.js使用的js处理引擎。JS作为一门解释型语言,再程序运行时进行编译,处理成中间代码再交由解释器对中间代码处理成机器语言运行,效率比较低,V8才用了混合编译执行,解释执行两种方式以及内联缓存等方法提高性能,有了这些,JS在V8引擎运行速度媲美二进制程序。

1,V8引擎启动时初始化执行环境,比如堆栈,执行上下文,内置函数等

2,V8对源代码解析结构化,生成AST(抽象语法树)

3,生成AST同时,V8还会生成作用域,字节码,解释器可以直接执行字节码

4,解释器执行字节码发现某段代码多次执行,就会将其丢给编译器编译成二进制代码执行,提高执行速度。

计网 - 图83 简述PWA

PWA:渐进式Web应用(Progressive Web App),实际上就是使用web技术编写一个网页应用,添加App Manifest 与Service worker实现PWA的安装与离线功能。

优点:

  • 本质是个网页,没有原生APP各种启动条件,快速响应启动
  • 实现消息推送通知
  • 实现离线缓存,即使手机没有网络也可以使用一些离线功能

manifest:manifest.json文件规定添加PWA到主屏幕细节,比如图表背景颜色,大小等

html头部引入manifest.json:

service worker:service worker类似于介于网页(pwa本质就是个网页应用)与服务器之间的拦截器,拦截进出的http请求,从而控制当前网页。

特点:

  • 注册安装成功后,运行浏览器后台,不受页面刷新影响,可监听拦截作用域内页面所有http请求
  • 网站必须使用HTTPS(localhost例外)
  • 单独运行环境与执行线程
  • 不能操作页面dom,但可以通过事件驱动处理。

计网 - 图84为什么连接的时候是三次握手,关闭的时候却是四次握手?

因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,”你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

计网 - 图85大量time_wait产生原因及解决办法

原因:爬虫服务器会产生大量的time_wait状态

解决:让服务器能够快速回收和重用那些TIME_WAIT的资源。

计网 - 图86TCP协议如何来保证传输的可靠性

  • 数据包校验和:发送之前记性计算校验和,接收方收到之后也计算是不是一样的
  • 确认应答和序列号
  • 丢弃重复数据:对于重复数据丢弃
  • 超时重发:TCP发出一个报文后启动一个定时器,等待目的端确认收到这个报文。如果不能及时收到确认,将重发这个报文。
  1. 校验和
  2. 序列号与确认应答
  3. 丢弃重复数据
  4. 重发控制(超时重传)
  5. TCP将对收到的数据进行重新排序
  6. 流量控制、拥塞控制使得网络不好的时候丢包的概率大大减小

计网 - 图87三次握手中,第二次握手丢失如何处理

三次握手协议中,服务器维护一个未连接队列,该队列为每个客户端的SYN包开设一个条目,该条目表明服务器已收到SYN包,并向客户发出确认,正在等待客户的确认包。这些条目所标识的连接在服务器处于 SYN_RECV状态,当服务器收到客户的确认包时,删除该条目,服务器进入ESTABLISHED状态。

服务器发送完SYN-ACK包,如果未收到客户确认包,服务器进行首次重传,等待一段时间仍未收到客户确认包,进行第二次重传,如果重传次数超过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。

半连接存活时间是指半连接队列的条目存活的最长时间,也即服务器从收到SYN包到确认这个报文无效的最长时间,该时间值是所有重传请求包的最长等待时间总和。有时我们也称半连接存活时间为Timeout时间、SYN_RECV存活时间。

计网 - 图88SYN攻击

概念:伪造大量TCP连接请求,使得被攻击方资源耗尽;攻击客户端在短时间内伪造大量不存在的IP地址,向服务器不断地发送SYN包,服务器回复确认包,并等待客户的确认并等待一段时间之后丢弃这个未完成的连接。由于源地址是不存在的,服务器需要不断的重发直至超时,这些伪造的SYN包将长时间占用未连接队列,正常的SYN请求被丢弃。

解决办法:

  1. 缩短超时(SYN Timeout)时间
  2. SYNCOOKIE技术:每个请求连接的IP地址分配一个Cookie,如果短时间内收到某个IP重复SYN报文,认定收到了攻击,这个IP地址来的包都被丢弃。

计网 - 图89TCP与UDP的区别

  1. TCP是面向连接的,UDP是无连接的,所以udp发送的快一些
  2. TCP可靠,UDP不可靠,udp尽最大努力交付。
  3. TCP支持点对点通信、UDP支持一对一、一对多、多对一、多对多的通信模式
  4. TCP面向字节流,UDP面向报文
  5. TCP可以拥塞控制,UDP没有,所以udp可以更好控制发送时间和发送速度
  6. TCP首部(20个字节)比UDP首部(8字节)大
  7. tcp是全双工的,TCP可靠UDP不可靠,应用不同,udp应用于高速传输和实时性要求较高的通信

计网 - 图90TCP为什么会分包

TCP是以段(Segment)为单位发送数据的,建立TCP链接后,有一个最大消息长度(MSS).如果应用层数据包超过MSS,就会把应用层数据包拆分,分成两个段来发送.这个时候接收端的应用层就要拼接这两个TCP包,才能正确处理数据.

计网 - 图91TCP为什么会粘包

  • 发送方产生的粘包问题

有时候,TCP为了提高网络的利用率,会使用一个叫做Nagle的算法.该算法是指,发送端即使有要发送的数据,如果很少的话,会延迟发送.如果应用层给TCP传送数据很快的话,就会把两个应用层数据包“粘”在一起,TCP最后只发一个TCP数据包给接收端.

  • 收方产生的粘包问题**

接收方用户进程不及时接收数据,从而导致粘包现象

如何处理

  1. 特殊字符控制
  2. 在包头首都添加数据包的长度。
  3. 关闭nagle算法

tips:UDP 没有粘包问题,但是有丢包和乱序。不完整的包是不会有的,收到的都是完全正确的包。传送的数据单位协议是 UDP 报文或用户数据报,发送的时候既不合并,也不拆分。

计网 - 图92HTTP和HTTPS的区别,以及HTTPS有什么缺点

Http协议运行在TCP之上,明文传输,客户端与服务器端都无法验证对方的身份;Https是身披SSL(Secure Socket Layer)外壳的Http,运行于SSL上,SSL运行于TCP之上,是添加了加密和认证机制的HTTP。

区别:

  • HTTPS是加密传输协议,HTTP是名文传输协议,存在风险;
  • HTTP使用80端口 HTTPS使用的是443端口。
  • https通信需要SSL证书,证书一般需要向认证机构购买,http不需要
  • HTTP工作于应用层,而HTTPS 的安全传输机制工作在传输层

计网 - 图93HTTPS 的优缺点?

优点:

  1. 使用 HTTPS 协议可认证用户和服务器,确保数据发送到正确的客户机和服务器;
  2. HTTPS 协议是由 SSL + HTTP 协议构建的可进行加密传输、身份认证的网络协议,要比 HTTP 协议安全,可防止数据在传输过程中不被窃取、改变,确保数据的完整性;
  3. HTTPS 是现行架构下最安全的解决方案,虽然不是绝对安全,但它大幅增加了中间人攻击的成本。

缺点:

  1. HTTPS 协议握手阶段比较费时,会使页面的加载时间延长近 50%,增加 10% 到 20% 的耗电;
  2. HTTPS 连接缓存不如 HTTP 高效,会增加数据开销和功耗,甚至已有的安全措施也会因此而受到影响;
  3. SSL 证书需要钱,功能越强大的证书费用越高,个人网站、小网站没有必要一般不会用;
  4. SSL 证书通常需要绑定 IP,不能在同一 IP 上绑定多个域名,IPv4 资源不可能支撑这个消耗;
  5. HTTPS 协议的加密范围也比较有限,在黑客攻击、拒绝服务攻击、服务器劫持等方面几乎起不到什么作用。最关键的,SSL 证书的信用链体系并不安全,特别是在某些国家可以控制 CA 根证书的情况下,中间人攻击一样可行。

计网 - 图94 什么是糊涂窗口

糊涂窗口综合症是指当发送端应用进程产生数据很慢、或接收端应用进程处理接收缓冲区数据很慢,或二者兼而有之;就会使应用进程间传送的报文段很小,特别是有效载荷很小; 极端情况下,有效载荷可能只有1个字节;传输开销有40字节(20字节的IP头+20字节的TCP头) 这种现象。