GET 与 POST

get-和-post-有什么区别GET 和 POST 有什么区别?

根据 RFC 规范,GET 的语义是从服务器获取指定的资源,这个资源可以是静态的⽂本、⻚⾯、图⽚视频

等。GET 请求的参数位置⼀般是写在 URL 中,URL 规定只能⽀持 ASCII,所以 GET 请求的参数只允许

ASCII 字符 ,⽽且浏览器会对 URL 的⻓度有限制(HTTP协议本身对 URL⻓度并没有做任何规定)。

根据 RFC 规范,POST 的语义是发送数据并对指定的资源做出处理,具体的处理⽅式视资源类型⽽不同。

POST 请求携带数据的位置⼀般是写在报⽂ body 中,body 中的数据可以是任意格式的数据,

只要客户端与服务端协商好即可,⽽且浏览器不会对 body ⼤⼩做限制。

GET POST ⽅法都是安全和幂等的吗?

先说明下安全和幂等的概念:

在 HTTP 协议⾥,所谓的「安全」是指请求⽅法不会「破坏」服务器上的资源。

所谓的「幂等」,意思是多次执⾏相同的操作,结果都是「相同」的。

如果从 RFC 规范定义的语义来看:GET ⽅法就是安全且幂等的,因为它是「只读」操作,⽆论操作多少次,服务器上的数据都是安全

的,且每次的结果都是相同的。所以,可以对 GET 请求的数据做缓存,这个缓存可以做到浏览器本身上(彻底避免浏览器发请求),也可以做到代理上(如nginx),⽽且在浏览器中 GET 请求可以保存为书签

POST 因为是「新增或提交数据」的操作,会修改服务器上的资源,所以是不安全的,且多次提交数

据就会创建多个资源,所以不是幂等的。所以,浏览器⼀般不会缓存 POST 请求,也不能把 POST请求保存为书签

但是实际过程中,开发者不⼀定会按照 RFC 规范定义的语义来实现 GET 和 POST ⽅法。⽐如:

可以⽤ GET ⽅法实现新增或删除数据的请求,这样实现的 GET ⽅法⾃然就不是安全和幂等。

可以⽤ POST ⽅法实现查询数据的请求,这样实现的 POST ⽅法⾃然就是安全和幂等。

HTTP 缓存技术

对于⼀些具有重复性的HTTP请求,⽐如每次请求得到的数据都⼀样的,我们可以把这对「请求-响应」的数据都缓存在本地,那么下次就直接读取本地的数据,不必在通过⽹络获取服务器的响应了,这样的话HTTP/1.1 的性能肯定⾁眼可⻅的提升。

所以,避免发送 HTTP 请求的⽅法就是通过缓存技术,HTTP 设计者早在之前就考虑到了这点,因此 HTTP协议的头部有不少是针对缓存的字段。

HTTP 缓存有两种实现⽅式,分别是强制缓存和协商缓存

什么是强制缓存?

强制缓存指的是只要浏览器判断缓存没有过期,则直接使⽤浏览器的本地缓存,决定是否使⽤缓存的主动性在于浏览器这边。

如下图中,返回的是 200 状态码,但在 size 项中标识的是 from disk cache,就是使⽤了强制缓存。

img

强缓存是利⽤下⾯这两个 HTTP 响应头部(Response Header)字段实现的,它们都⽤来表示资源在客户端缓存的有效期:

  • Cache-Control , 是⼀个相对时间;
  • Expires ,是⼀个绝对时间;

在响应头中 Expires 字段的意思是,当前返回数据的缓存到期时间戳。当浏览器在进行请求的时候,会那浏览器本地的时候和这个时间做对比,判断资源是否过期。

但是上述存在一个问题就是,如果我手动改变了电脑的时间,那么就会出现问题,这也是 HTTP1.0 中存在的问题。

Expires 指缓存过期的时间,超过了这个时间点就代表资源过期。有一个问题是由于使用具体时间,如果时间表示出错或者没有转换到正确的时区都可能造成缓存生命周期出错,并且 Expires 是 HTTP/1.0 的标准,现在更倾向于用 HTTP/1.1 中定义的 Cache-Control,两个同时存在时也是 Cache-Control 的优先级更高。
为了解决这个问题,在 HTTP1.1 中增加了 Cache-Control 这个字段。

服务器和客户端说,这个资源缓存只可以存在 7200 秒,在这个时间段之内,你就可以在缓存获取资源。

如果 HTTP 响应头部同时有 Cache-Control 和 Expires 字段的话,Cache-Control 的优先级⾼于 Expires

Cache-control 选项更多⼀些,设置更加精细,所以建议使⽤ Cache-Control 来实现强缓存。具体的实现

流程如下:

当浏览器第⼀次请求访问服务器资源时,服务器会在返回这个资源的同时,在 Response 头部加上Cache-Control,Cache-Control 中设置了过期时间⼤⼩;

浏览器再次请求访问服务器中的该资源时,会先通过请求资源的时间与 Cache-Control 中设置的过

期时间⼤⼩,来计算出该资源是否过期,如果没有,则使⽤该缓存,否则重新请求服务器;

服务器再次收到请求后,会再次更新 Response 头部的 Cache-Control。

什么是协商缓存?

当我们在浏览器使⽤开发者⼯具的时候,你可能会看到过某些请求的响应码是 304 ,这个是告诉浏览器

可以使⽤本地缓存的资源,通常这种通过服务端告知客户端是否可以使⽤缓存的⽅式被称为协商缓存。

img

上图就是⼀个协商缓存的过程,所以协商缓存就是与服务端协商之后,通过协商结果来判断是否使⽤本地缓存

协商缓存可以基于两种头部来实现。

第⼀种:请求头部中的 If-Modified-Since 字段与响应头部中的 Last-Modified 字段实现,这两个字段

的意思是:

  • 响应头部中的 Last-Modified :标示这个响应资源的最后修改时间;
  • 请求头部中的 If-Modified-Since :当资源过期了,发现响应头中具有 Last-Modified 声明,则再次发起请求的时候带上 Last-Modified 的时间,服务器收到请求后发现有 If-Modified-Since 则与被请求资源的最后修改时间进⾏对⽐(Last-Modified),如果最后修改时间较新(⼤),说明资源⼜被改过,则返回最新资源,HTTP 200 OK;如果最后修改时间较旧(⼩),说明资源⽆新修改,响应HTTP 304 ⾛缓存。

第⼆种:请求头部中的 If-None-Match 字段与响应头部中的 ETag 字段,这两个字段的意思是:

  • 响应头部中 Etag :唯⼀标识响应资源;
  • 请求头部中的 If-None-Match :当资源过期时,浏览器发现响应头⾥有 Etag,则再次向服务器发起请求时,会将请求头 If-None-Match 值设置为 Etag 的值。服务器收到请求后进⾏⽐对,如果资源没有变化返回 304,如果资源变化了返回 200。

第⼀种实现⽅式是基于时间实现的,第⼆种实现⽅式是基于⼀个唯⼀标识实现的,相对来说后者可以更加

准确地判断⽂件内容是否被修改,避免由于时间篡改导致的不可靠问题。

如果在第⼀次请求资源的时候,服务端返回的 HTTP 响应头部同时有 Etag 和 Last-Modified 字段,那么客

户端再下⼀次请求的时候,如果带上了 ETag 和 Last-Modified 字段信息给服务端,这时 Etag 的优先级更

,也就是服务端先会判断 Etag 是否变化了,如果 Etag 有变化就不⽤在判断 Last-Modified 了,如果

Etag 没有变化,然后再看 Last-Modified。

为什么 ETag 的优先级更⾼?这是因为 ETag 主要能解决 Last-Modified ⼏个⽐较难以解决的问题:

1、在没有修改⽂件内容情况下⽂件的最后修改时间可能也会改变,这会导致客户端认为这⽂件被改动

了,从⽽重新请求;

2、可能有些文件是在秒级以内修改的,If-Modified-Since 能检查到的粒度是秒级的,使用 Etag就能够

保证这种需求下客户端在 1 秒内能刷新多次;

3、有些服务器不能精确获取文件的最后修改时间。

注意, 协商缓存这两个字段都需要配合强制缓存中 Cache-Control 字段来使用,只有在未能命中强制缓存

的时候,才能发起带有协商缓存字段的请求。

下图是强制缓存和协商缓存的工作流程:

img

当使用 ETag 字段实现的协商缓存的过程:

当浏览器第一次请求访问服务器资源时,服务器会在返回这个资源的同时,在 Response 头部加上

ETag 唯一标识,这个唯一标识的值是根据当前请求的资源生成的;

当浏览器再次请求访问服务器中的该资源时,首先会先检查强制缓存是否过期:

​ 如果没有过期,则直接使用本地缓存;

​ 如果缓存过期了,会在 Request 头部加上 If-None-Match 字段,该字段的值就是 ETag 唯一标

​ 识;

服务器再次收到请求后, 会根据请求中的 If-None-Match 值与当前请求的资源生成的唯一标识进行

比较 :

​ 如果值相等,则返回 304 Not Modified,不会返回资源 ;

​ 如果不相等,则返回 200 状态码和返回资源,并在 Response 头部加上新的 ETag 唯一标识;

如果浏览器收到 304 的请求响应状态码,则会从本地缓存中加载资源,否则更新资源。

HTTP各个版本

HTTP1.0

HTTP/1.0是无状态、无连接的应用层协议。

无连接
  无连接:每次请求都要建立连接,需要使用 keep-alive 参数建立长连接、HTTP1.1默认长连接keep-alive
  无法复用连接,每次发送请求都要进行TCP连接,TCP的连接释放都比较费事,会导致网络利用率低

队头阻塞
  队头阻塞(head of line blocking),由于HTTP1.0规定下一个请求必须在前一个请求响应到达之前才能发送,假设前一个请求响应一直不到达,那么下一个请求就不发送,后面的请求就阻塞了。

HTTP1.1

HTTP 1.1支持长连接Persistent Connection,并且默认使用,在同一个TCP的连接中可以传送多个HTTP请求和响应,多个请求和响应可以重叠,多个请求和响应可以同时进行,更加多的请求头和响应头

HTTP 1.1的持续连接,也需要增加新的请求头来帮助实现,例如,Connection请求头的值为Keep-Alive时,客户端通知服务器返回本次请求结果后保持连接;Connection请求头的值为Close时,客户端通知服务器返回本次请求结果后关闭连接。

管道网络传输

HTTP/1.1 采用了长连接的方式,这使得管道网络传输成为了可能。

即可在同一个 TCP 连接里面,客户端可以发起多个请求,只要第一个请求发出去了,不必等其回来,就可以发第二个请求出去,可以减少整体的响应时间。

举例来说,客户端需要请求两个资源。以前的做法是,在同一个TCP连接里面,先发送 A 请求,然后等待服务器做出回应,收到后再发出 B 请求,管道机制则是允许浏览器同时发出 A 请求和 B 请求。

但是服务器还是按照顺序,先回应 A 请求,完成后再回应 B 请求,要是 前面的回应特别慢,后面就会有许多请求排队等着。

所以,HTTP/1.1 管道解决了请求的队头阻塞,但是没有解决响应的队头阻塞

注意!!!

实际上 HTTP/1.1 管道化技术不是默认开启,而且浏览器基本都没有支持。

HTTP2.0(不详细)

HTTP2.0和HTTP1.X相比的新特性

  • 新的二进制格式,HTTP1.x的解析是基于文本
  • 多路复用,即连接共享,即每一个request都是是用作连接共享机制的,一个request对应一个id,这样一个连接上可以有多个request,每个连接的request可以随机的混杂在一起,接收方可以根据request的 id将request再归属到各自不同的服务端请求里面
  • header压缩,HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小
  • 服务端推送

HTTP/2 还在一定程度上改善了传统的请求 - 应答工作模式,服务不再是被动地响应,也可以主动向客户端发送消息。

举例来说,在浏览器刚请求 HTML 的时候,就提前把可能会用到的 JS、CSS 文件等静态资源主动发给客户端,减少延时的等待,也就是服务器推送。

数据流

HTTP/2 的数据包不是按顺序发送的,同一个连接里面连续的数据包,可能属于不同的回应。

因此,必须要对数据包做标记,指出它属于哪个回应。

每个请求或回应的所有数据包,称为一个数据流(Stream)。

每个数据流都标记着一个独一无二的编号,其中规定客户端发出的数据流编号为奇数, 服务器发出的数据流编号为偶数

客户端还可以指定数据流的优先级。优先级高的请求,服务器就先响应该请求。

HTTP2.0的多路复用和HTTP1.X中的长连接复用有什么区别

  • HTTP/1.1的Pipeling为若干个请求排队串行化单线程处理,后面的请求等待前面请求的返回才能获得执行机会,一旦有某请求超时等,后续请求只能被阻塞,毫无办法;
  • HTTP2.0多个请求可同时在一个连接上并行执行,某个请求任务耗时严重,不会影响到其它连接的正常执行

HTTP3.0(不详细)

使用UDP协议

HTTP/2 主要的问题在于:多个 HTTP 请求在复用一个 TCP 连接,下层的 TCP 协议是不知道有多少个 HTTP 请求的。

所以一旦发生了丢包现象,就会触发 TCP 的重传机制,这样在一个 TCP 连接中的所有的 HTTP 请求都必须等待这个丢了的包被重传回来

  • HTTP/1.1 中的管道传输中如果有一个请求阻塞了,那么队列后请求也统统被阻塞住了
  • HTTP/2 多请求复用一个TCP连接,一旦发生丢包,就会阻塞住所有的 HTTP 请求。

这都是基于 TCP 传输层的问题,所以 HTTP/3 把 HTTP 下层的 TCP 协议改成了 UDP!

总结

HTTP/1.1 相比 HTTP/1.0 提高了什么性能?
  • 使用⻓连接的方式改善了 HTTP/1.0 短连接造成的性能开销。

  • 支持管道(pipeline)网络传输,只要第一个请求发出去了,不必等其回来,就可以发第二个请求出

    去,可以减少整体的响应时间。

但 HTTP/1.1 还是有性能瓶颈:

  • 请求 / 响应头部(Header)未经压缩就发送,首部信息越多延迟越大。只能压缩 Body 的部分;

  • 发送冗⻓的首部。每次互相发送相同的首部造成的浪费较多;

  • 服务器是按请求的顺序响应的,如果服务器响应慢,会招致客户端一直请求不到数据,也就是队头阻

    塞;

  • 没有请求优先级控制;

  • 请求只能从客户端开始,服务器只能被动响应。

HTTP/2 做了什么优化?

HTTP/2 协议是基于 HTTPS 的,所以 HTTP/2 的安全性也是有保障的。

HTT/1 ~ HTTP/2

那 HTTP/2 相比 HTTP/1.1 性能上的改进:

  • 头部压缩

  • 二进制格式

  • 并发传输

  • 服务器主动推送资源

1. 头部压缩

HTTP/2 会 压缩头 (Header)如果你同时发出多个请求,他们的头是一样的或是相似的,那么,协议会帮
消除重复的部分

这就是所谓的 HPACK 算法:在客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生

成一个索引号,以后就不发送同样字段了,只发送索引号,这样就 提高速度 了。

2. 二进制格式

HTTP/2 不再像 HTTP/1.1 里的纯文本形式的报文,而是全面采用了 二进制格式 ,头信息和数据体都是二进

制,并且统称为帧(frame): 头信息帧(Headers Frame)和数据帧(Data Frame)

HTTP/1 与 HTTP/2

这样虽然对人不友好,但是对计算机非常友好,因为计算机只懂二进制,那么收到报文后,无需再将明文

的报文转成二进制,而是直接解析二进制报文,这 增加了数据传输的效率 。

比如状态码 200 ,在 HTTP/1.1 是用 ‘2’’0’’0’ 三个字符来表示(二进制:00110010 00110000

00110000 ),共用了 3 个字节,如下图

img

在 HTTP/2 对于状态码 200 的二进制编码是 10001000 ,只用了 1 字节就能表示,相比于 HTTP/1.1 节省

了 2 个字节,如下图:

img

Header: :status: 200 OK 的编码内容为:1000 1000,那么表达的含义是什么呢?

img

  1. 最前面的 1 标识该 Header 是静态表中已经存在的 KV。
  2. 在静态表里,“:status: 200 ok” 静态表编码是 8 ,二进制即是 1000 。

因此,整体加起来就是 1000 1000。

  1. 并发传输

我们都知道 HTTP/1.1 的实现是基于请求-响应模型的。同一个连接中,HTTP 完成一个事务(请求与响

应),才能处理下一个事务,也就是说在发出请求等待响应的过程中,是没办法做其他事情的,如果响应

迟迟不来,那么后续的请求是无法发送的,也造成了 队头阻塞 的问题。

而 HTTP/2 就很牛逼了,引出了 Stream 概念,多个 Stream 复用在一条 TCP 连接。

img

从上图可以看到, 1 个 TCP 连接包含多个 Stream,Stream 里可以包含 1 个或多个 Message,Message
对应 HTTP/1 中的请求或响应,由 HTTP 头部和包体构成。Message 里包含一条或者多个 Frame,Frame
是 HTTP/2 最小单位,以二进制压缩格式存放 HTTP/1 中的内容(头部和包体)。

针对不同的 HTTP 请求用独一无二的 Stream ID 来区分,接收端可以通过 Stream ID 有序组装成 HTTP

消息,不同 Stream 的帧是可以乱序发送的,因此可以并发不同的 Stream ,也就是 HTTP/2 可以并行交
错地发送请求和响应。

比如下图,服务端 并行交错地 发送了两个响应: Stream 1 和 Stream 3,这两个 Stream 都是跑在一个
TCP 连接上,客户端收到后,会根据相同的 Stream ID 有序组装成 HTTP 消息。

img

4 、服务器推送

HTTP/2 还在一定程度上改善了传统的「请求 - 应答」工作模式,服务端不再是被动地响应,可以 主动 向客

户端发送消息。

客户端和服务器 双方都可以建立 Stream , Stream ID 也是有区别的,客户端建立的 Stream 必须是奇数
号,而服务器建立的 Stream 必须是偶数号。

比如下图,Stream 1 是客户端向服务端请求的资源,属于客户端建立的 Stream,所以该 Stream 的 ID 是
奇数(数字 1 );Stream 2 和 4 都是服务端主动向客户端推送的资源,属于服务端建立的 Stream,所以
这两个 Stream 的 ID 是偶数(数字 2 和 4 )。

img

再比如,客户端通过 HTTP/1.1 请求从服务器那获取到了 HTML 文件,而 HTML 可能还需要依赖 CSS 来

渲染⻚面,这时客户端还要再发起获取 CSS 文件的请求,需要两次消息往返,如下图左边部分:

img

如上图右边部分,在 HTTP/2 中,客户端在访问 HTML 时,服务器可以直接主动推送 CSS 文件,减少了

消息传递的次数。

HTTP/2 有什么缺陷?

HTTP/2 通过 Stream 的并发能力,解决了 HTTP/1 队头阻塞的问题,看似很完美了,但是 HTTP/2 还是存
在“队头阻塞”的问题,只不过问题不是在 HTTP 这一层面,而是在 TCP 这一层。

HTTP/2 是基于 TCP 协议来传输数据的,TCP 是字节流协议,TCP 层必须保证收到的字节数据是完整且

连续的,这样内核才会将缓冲区里的数据返回给 HTTP 应用,那么当「前 1 个字节数据」没有到达时,后

收到的字节数据只能存放在内核缓冲区里,只有等到这 1 个字节数据到达时,HTTP/2 应用层才能从内核

中拿到数据,这就是 HTTP/2 队头阻塞问题。

img

举个例子,如下图:

img

图中发送方发送了很多个 packet,每个 packet 都有自己的序号,你可以认为是 TCP 的序列号,其中
packet 3 在网络中丢失了,即使 packet 4-6 被接收方收到后,由于内核中的 TCP 数据不是连续的,于是
接收方的应用层就无法从内核中读取到,只有等到 packet 3 重传后,接收方的应用层才可以从内核中读取
到数据,这就是 HTTP/2 的队头阻塞问题,是在 TCP 层面发生的。

所以,一旦发生了丢包现象,就会触发 TCP 的重传机制,这样在一个 TCP 连接中的 所有的 HTTP 请求都

必须等待这个丢了的包被重传回来 。

HTTP/3 做了哪些优化?

前面我们知道了 HTTP/1.1 和 HTTP/2 都有队头阻塞的问题:

  • HTTP/1.1 中的管道( pipeline)虽然解决了请求的队头阻塞,但是 没有解决响应的队头阻塞 ,因为服

    务端需要按顺序响应收到的请求,如果服务端处理某个请求消耗的时间比较⻓,那么只能等响应完这

    个请求后, 才能处理下一个请求,这属于 HTTP 层队头阻塞。

  • HTTP/2 虽然通过多个请求复用一个 TCP 连接解决了 HTTP 的队头阻塞 ,但是 一旦发生丢包,就会

    阻塞住所有的 HTTP 请求 ,这属于 TCP 层队头阻塞。

HTTP/2 队头阻塞的问题是因为 TCP,所以 HTTP/3 把 HTTP 下层的 TCP 协议改成了 UDP!

HTTP/1 ~ HTTP/3

UDP 发送是不管顺序,也不管丢包的,所以不会出现像 HTTP/2 队头阻塞的问题。大家都知道 UDP 是不

可靠传输的,但基于 UDP 的 QUIC 协议 可以实现类似 TCP 的可靠性传输。

QUIC 有以下 3 个特点。

  • 无队头阻塞

  • 更快的连接建立

  • 连接迁移

1 、无队头阻塞

QUIC 协议也有类似 HTTP/2 Stream 与多路复用的概念,也是可以在同一条连接上并发传输多个 Stream,
Stream 可以认为就是一条 HTTP 请求。

QUIC 有自己的一套机制可以保证传输的可靠性的。 当某个流发生丢包时,只会阻塞这个流,其他流不会

受到影响,因此不存在队头阻塞问题 。这与 HTTP/2 不同,HTTP/2 只要某个流中的数据包丢失了,其他流

也会因此受影响。

所以,QUIC 连接上的多个 Stream 之间并没有依赖,都是独立的,某个流发生丢包了,只会影响该流,其
他流不受影响。

img

2 、更快的连接建立

对于 HTTP/1 和 HTTP/2 协议,TCP 和 TLS 是分层的,分别属于内核实现的传输层、openssl 库实现的表
示层,因此它们难以合并在一起,需要分批次来握手,先 TCP 握手,再 TLS 握手。

HTTP/3 在传输数据前虽然需要 QUIC 协议握手,但是这个握手过程只需要 1 RTT,握手的目的是为确认双

方的「连接 ID」,连接迁移就是基于连接 ID 实现的。

但是 HTTP/3 的 QUIC 协议并不是与 TLS 分层,而是 QUIC 内部包含了 TLS,它在自己的帧会携带 TLS

里的“记录”,再加上 QUIC 使用的是 TLS/1.3,因此仅需 1 个 RTT 就可以「同时」完成建立连接与密钥协

商,如下图:

TCP HTTPS(TLS/1.3) 和 QUIC HTTPS

甚至,在第二次连接的时候,应用数据包可以和 QUIC 握手信息(连接信息 + TLS 信息)一起发送,达到

0-RTT 的效果。

如下图右边部分,HTTP/3 当会话恢复时,有效负载数据与第一个数据包一起发送,可以做到 0-RTT(下

图的右下⻆):

img

3 、连接迁移

基于 TCP 传输协议的 HTTP 协议,由于是通过四元组(源 IP、源端口、目的 IP、目的端口)确定一条

TCP 连接。

TCP 四元组

那么 当移动设备的网络从 4G 切换到 WIFI 时,意味着 IP 地址变化了,那么就必须要断开连接,然后重新

建立连接 。而建立连接的过程包含 TCP 三次握手和 TLS 四次握手的时延,以及 TCP 慢启动的减速过程,

给用户的感觉就是网络突然卡顿了一下,因此连接的迁移成本是很高的。

而 QUIC 协议没有用四元组的方式来“绑定”连接,而是通过 连接 ID 来标记通信的两个端点,客户端和服务

器可以各自选择一组 ID 来标记自己,因此即使移动设备的网络变化后,导致 IP 地址变化了,只要仍保有

上下文信息(比如连接 ID、TLS 密钥等),就可以“无缝”地复用原连接,消除重连的成本,没有丝毫卡顿

感,达到了 连接迁移 的功能。

所以, QUIC 是一个在 UDP 之上的 TCP + TLS + HTTP/2 的多路复用的协议。

QUIC 是新协议,对于很多网络设备,根本不知道什么是 QUIC,只会当做 UDP,这样会出现新的问题,

因为有的网络设备是会丢掉 UDP 包的,而 QUIC 是基于 UDP 实现的,那么如果网络设备无法识别这个是

QUIC 包,那么就会当作 UDP包,然后被丢弃。

HTTPS

HTTP与HTTPS的区别

  • HTTP 是超文本传输协议,信息是明文传输,存在安全⻛险的问题。HTTPS 则解决 HTTP 不安全的缺

陷,在 TCP 和 HTTP 网络层之间加入了 SSL/TLS 安全协议,使得报文能够加密传输。

  • HTTP 连接建立相对简单, TCP 三次握手之后便可进行 HTTP 的报文传输。而 HTTPS 在 TCP 三次

握手之后,还需进行 SSL/TLS 的握手过程,才可进入加密报文传输。

  • 两者的默认端口不一样,HTTP 默认端口号是 80 ,HTTPS 默认端口号是 443 。

  • HTTPS 协议需要向 CA(证书权威机构)申请数字证书,来保证服务器的身份是可信的。

HTTPS 解决了 HTTP 的哪些问题?

HTTP 由于是明文传输,所以安全上存在以下三个⻛险:

  • 窃听⻛险 ,比如通信链路上可以获取通信内容,用户号容易没。

  • 篡改⻛险 ,比如强制植入垃圾广告,视觉污染,用户眼容易瞎。

  • 冒充⻛险 ,比如冒充淘宝网站,用户钱容易没。

HTTP S 在 HTTP 与 TCP 层之间加入了 SSL/TLS 协议,可以很好的解决了上述的⻛险:

  • 信息加密 :交互信息无法被窃取,但你的号会因为「自身忘记」账号而没。

  • 校验机制 :无法篡改通信内容,篡改了就不能正常显示,但百度「竞价排名」依然可以搜索垃圾广告。

  • 身份证书 :证明淘宝是真的淘宝网,但你的钱还是会因为「剁手」而没。

HTTPS 是如何解决上面的三个风险的?

  • 混合加密 的方式实现信息的 机密性 ,解决了窃听的⻛险。

  • 摘要算法 的方式来实现 完整性 ,它能够为数据生成独一无二的「指纹」,指纹用于校验数据的完整性,解决了篡改的⻛险。

  • 将服务器公钥放入到 数字证书 中,解决了冒充的⻛险

1. 混合加密

通过混合加密的方式可以保证信息的机密性,解决了窃听的风险。

HTTPS 采用的是对称加密非对称加密结合的「混合加密」方式:

  • 在通信建立前采用 非对称加密 的方式交换「会话秘钥」,后续就不再使用非对称加密。

  • 在通信过程中全部使用 对称加密 的「会话秘钥」的方式加密明文数据。

采用「混合加密」的方式的原因:

  • 对称加密 只使用一个密钥,运算速度快,密钥必须保密,无法做到安全的密钥交换。

  • 非对称加密 使用两个密钥:公钥和私钥,公钥可以任意分发而私钥保密,解决了密钥交换问题但速度慢。

2. 摘要算法 + 数字签名

为了保证传输的内容不被篡改,我们需要对内容计算出一个「指纹」,然后同内容一起传输给对方。

对方收到后,先是对内容也计算出一个「指纹」,然后跟发送方发送的「指纹」做一个比较,如果「指

纹」相同,说明内容没有被篡改,否则就可以判断出内容被篡改了。

那么,在计算机里会 用摘要算法(哈希函数)来计算出内容的哈希值 ,也就是内容的「指纹」,这个 哈希

值是唯一的,且无法通过哈希值推导出内容

通过哈希算法可以确保内容不会被篡改, 但是并不能保证「内容 + 哈希值」不会被中间人替换,因为这里

缺少对客户端收到的消息是否来源于服务端的证明

举个例子,你想向老师请假,一般来说是要求由家⻓写一份请假理由并签名,老师才能允许你请假。

但是你有模仿你爸爸字迹的能力,你用你爸爸的字迹写了一份请假理由然后签上你爸爸的名字,老师一看

到这个请假条,查看字迹和签名,就误以为是你爸爸写的,就会允许你请假。

那作为老师,要如何避免这种情况发生呢?现实生活中的,可以通过电话或视频来确认是否是由父母发出

的请假,但是计算机里可没有这种操作。

那为了避免这种情况,计算机里会用 非对称加密算法 来解决,共有两个密钥:

  • 一个是公钥,这个是可以公开给所有人的;

  • 一个是私钥,这个必须由本人管理,不可泄露。

这两个密钥可以 双向加解密 的,比如可以用公钥加密内容,然后用私钥解密,也可以用私钥加密内容,公

钥解密内容。

流程的不同,意味着目的也不相同:

  • 公钥加密,私钥解密 。这个目的是为了 保证内容传输的安全 ,因为被公钥加密的内容,其他人是无法

解密的,只有持有私钥的人,才能解密出实际的内容;

  • 私钥加密,公钥解密 。这个目的是为了 保证消息不会被冒充 ,因为私钥是不可泄露的,如果公钥能正

常解密出私钥加密的内容,就能证明这个消息是来源于持有私钥身份的人发送的。

一般我们不会用非对称加密来加密实际的传输内容,因为非对称加密的计算比较耗费性能的。

所以非对称加密的用途主要在于 通过「私钥加密,公钥解密」的方式,来确认消息的身份 ,我们常说的

字签名算法 ,就是用的是这种方式,不过私钥加密内容不是内容本身,而是 对内容的哈希值加密

img

私钥是由服务端保管,然后服务端会向客户端颁发对应的公钥。如果客户端收到的信息,能被公钥解密,

就说明该消息是由服务器发送的。

引入了数字签名算法后,你就无法模仿你爸爸的字迹来请假了,你爸爸手上持有着私钥,你老师持有着公

钥。

这样只有用你爸爸手上的私钥才对请假条进行「签名」,老师通过公钥看能不能解出这个「签名」,如果

能解出并且确认内容的完整性,就能证明是由你爸爸发起的请假条,这样老师才允许你请假,否则老师就

不认。

工作原理

HTTPS 协议会对传输的数据进行加密,而加密过程是使用了非对称加密实现

HTTPS的整体过程分为证书验证和数据传输阶段,具体的交互过程如下:

img

  • Client发起一个HTTPS的请求
  • Server把事先配置好的公钥证书返回给客户端。
  • Client验证公钥证书:比如是否在有效期内,证书的用途是不是匹配Client请求的站点,是不是在CRL吊销列表里面,它的上一级证书是否有效,这是一个递归的过程,直到验证到根证书(操作系统内置的Root证书或者Client内置的Root证书),如果验证通过则继续,不通过则显示警告信息。
  • Client使用伪随机数生成器生成加密所使用的对称密钥,然后用证书的公钥加密这个对称密钥,发给Server。
  • Server使用自己的私钥解密这个消息,得到对称密钥。至此,Client和Server双方都持有了相同的对称密钥。
  • Server使用对称密钥加密明文内容A,发送给Client。
  • Client使用对称密钥解密响应的密文,得到明文内容A。
  • Client再次发起HTTPS的请求,使用对称密钥加密请求的明文内容B,然后Server使用对称密钥解密密文,得到明文内容B。

数字证书

客户端先向服务器端索要公钥,然后用公钥加密信息,服务器收到密文后,用自己的私钥解密。

这就存在些问题,如何保证公钥不被篡改和信任度?

所以这里就需要借助第三方权威机构 CA (数字证书认证机构),将服务器公钥放在数字证书(由数字证书认证机构颁发)中,只要证书是可信的,公钥就是可信的。

通过数字证书的方式保证服务器公钥的身份,解决冒充的风险。

img