万字图解 | 深入揭秘HTTP工作原理

news2024/11/20 16:35:26

大家好,我是「云舒编程」,今天我们来聊聊计算机网络面试之-(应用层HTTP)工作原理。

文章首发于微信公众号:云舒编程
关注公众号获取:
1、大厂项目分享
2、各种技术原理分享
3、部门内推

前言

想必不少同学在面试过程中,会遇到「在浏览器中输入www.baidu.com后,到网页显示,其间发生了什么」类似的面试题。
本专栏将从该背景出发,详细介绍数据包从HTTP层->TCP层->IP层->网卡->互联网->目的地服务器 这中间涉及的知识。
本系列文章将采用自底向上的形式讲解每层的工作原理和数据在该层的处理方式。

系列文章

图解 | 深入揭秘数据链路层、物理层工作原理
图解 | 深入揭秘IP层工作原理
图解 | 深入揭秘TCP工作原理
图解 | 深入揭秘HTTP工作原理
图解 | 深入揭秘Linux 接收网络数据包
图解 | 深入揭秘IO多路复用原理

通过上一篇文章图解 | 深入揭秘TCP工作原理的介绍,我们知道了传输层的基本工作原理。
本篇将会详解对应用层进行介绍。

通过本文你可学到:

  1. 什么是超文本传输协议
  2. HTTP协议格式构成
  3. HTTP协议的发展历程
    1. 缓存技术
    2. 长连接
    3. https
    4. 多路复用
    5. 数据压缩
    6. QUIC协议
    7. cookie与session
  4. WebSocket

什么是超文本传输协议

HTTP 全称是HyperText Transfer Protocol,也叫超文本传输协议。
HTTP 于 1991 年提出的,主要用于学术交流,当时的目的也很简单,就是用来在网络之间传递 HTML文本的内容,所以被称为超文本传输协议。
一个简单的HTTP请求流程如下:

  • HTTP 都是基于 TCP 协议的,所以客户端先要根据 IP 地址、端口和服务器建立 TCP 连接,而建立连接的过程就是 TCP 协议三次握手的过程。
  • 建立好连接之后,会发送一个 GET/POST 请求,如GET /index.html用来获取 index.html。
  • 服务器接收请求信息之后,读取对应的 HTML 文件,并将数据以 ASCII 字符流返回给客户端。
  • HTML 文档传输完成后,断开连接。


在互联网早期的时候,HTTP传输的数据只是简单的字符文字,但是现在HTTP协议经过长时间的发展已经支持了图片、视频、音频等传输,所以【文本】的涵义已经不仅仅是指文字字符了。

HTTP协议格式构成

HTTP协议由以下四部分构成:

HTTP request请求体:


第一部分对应请求行,请求行又由三部分组成:


第二部分对应请求头:请求头由多个k:v结构组成
第三部分是空白行:
第四部分是请求体:
请求体可以接受form表单、json、xml、字符串等类型的参数,具体取决于Content-Type的设置。

HTTP response响应体:


第一部分对应响应行,响应行又由三部分组成:

Version:表示报文使用的HTTP协议版本;
Status Code:一个三位数,用代码的形式表示处理的结果,比如200是成功,500是服务器错误;
Reason:作为数字状态码补充,是更详细的解释文字,帮助人理解原因。
第二部分对应响应头:请求头由多个k:v结构组成
第三部分是空白行:
第四部分是响应体:
响应体可以接受form表单、json、xml、字符串等类型的结果,具体取决于Content-Type的设置。

HTTP优化设计史

在前文【什么是超文本传输协议】我们有提到HTTP最开始设计时,只是为了传输简单的字符文本,随着互联网的发展,HTTP也经过了几次优化设计,满足人们在数据类型传输、安全、性能等多方面的需求。
接下来我们会逐步讲解,HTTP的几次重大优化设计:

HTTP/0.9

HTTP/0.9 是最开始的HTTP协议,就如前面说的,只支持简单的字符文本传输,安全,多样的数据、性能都没有做考虑。
并且他的请求/响应也不是我们前面提到的【HTTP协议格式构成】部分标准组成。而是如下:

GET /mypage.html
<html>
  这是一个非常简单的 HTML 页面
</html>

只支持简单的GET 请求,响应结果也只包含文档本身。

HTTP/1.0

1994 年底出现了拨号上网服务以及网景推出新浏览器后,人们开始对HTTP提出了更多的需求。

需求一、丰富HTTP协议格式

定义了前文提到的【HTTP协议格式构成】,后续的HTTP请求都必须按照标准格式请求/响应。
带来如下好处:

  • 引入了更多的请求Method,例如POST命令和HEAD命令,丰富了浏览器与服务器的互动手段;
  • 引入了状态码,使浏览器能了解请求执行成功或失败,并相应调整行为(如更新或使用本地缓存);
  • 引入了 HTTP 头部字段的概念,允许传输更多的元数据,使协议变得非常灵活,更具扩展性;

需求二、多文件传输(除了HTML,还要支持JS、CSS、图片、音视频等)

得益于HTTP标准协议格式的提出,HTTP/1.0 可以通过请求头和响应头来进行协商,在发起请求时候会通过 HTTP 请求头告诉服务器它期待服务器返回:
1、什么类型的文件;
2、采取什么形式的压缩;
3、提供什么语言的文件以及文件的具体编码。最终发送出来的请求头内容如下:

accept: text/html //期望服务器返回 html 类型的文件
accept-encoding: gzip, deflate, br //期望服务器可以采用 gzip、deflate 或者 br 其中的一种压缩方式
accept-Charset: ISO-8859-1,utf-8 //期望返回的文件编码是 UTF-8 或者 ISO-8859-1
accept-language: zh-CN,zh //期望页面的优先语言是中文

服务器接收到浏览器发送过来的请求头信息之后,会根据请求头的信息来准备响应数据。不过有时候会有一些意外情况发生,比如浏览器请求的压缩类型是 gzip,但是服务器不支持 gzip,只支持 br 压缩,那么它会通过响应头中的 content-encoding 字段告诉浏览器最终的压缩类型,也就是说最终浏览器需要根据响应头的信息来处理数据。下面是一段响应头的数据信息:

content-encoding: br //服务器采用了 br 的压缩方法
content-type: text/html; charset=UTF-8 //服务器返回的是 html 文件,并且该文件的编码类型是 UTF-8。

HTTP/1.1

优化一:缓存

对于重复性的请求,HTTP会缓存结果,这样当一样的请求发起时直接从本地获取缓存,不需要请求服务端,节省了资源也提高了性能。
HTTP的缓存是通过在HTTP请求头/响应头增加字段实现的,具体又分为两种:
1、强制缓存
强缓存指的是只要浏览器判断缓存没有过期,则直接使用浏览器的本地缓存,主动权在浏览器这边。
类似这样的请求就是使用了强制缓存。

强制缓存由由响应请求设置的,通过:

  • Cache-Control:设置相对时间,优先级最高;
  • Expires:设置绝对时间;

两个头部字段控制。
流程如下:

  1. 浏览器请求服务器中时,会先判断是否存在cache,以及相应的Cache-Control 是否过期。如果没有,则使用该缓存,否则重新请求服务器;
  2. 重新请求服务器后,会再次更新 Response 头部的 Cache-Control。

2、协商缓存
协商缓存就是强制缓存过期后,浏览器继续请求服务器使用缓存的机制,主要分为以下两种情况:

  1. 协商缓存生效,返回304,代表资源未更新,旧的缓存可以继续使用;
  2. 协商缓存失效,返回200和新的请求结果。

协商缓存主要有两种实现方式:

  • Last-Modified/If-Modified-Since
  • Etag/If-None-Match

其中Etag/If-None-Match优先级比Last-Modified/If-Modified-Since高。

Last-Modified/If-Modified-Since

Last-Modified是资源文件在服务器最后被修改的时间。
客户端请求服务端时会设置如下请求头:

If-Modified-Since:Last-Modified
//Last-Modified是客户端第一次请求服务端时,服务端返回的

服务器收到该请求,发现请求头含有If-Modified-Since字段,则会根据If-Modified-Since的字段值与该资源在服务器的最后被修改时间做对比,

  • 若服务器的资源最后修改时间大于If-Modified-Since的字段值,则重新返回资源,状态码为200;
  • 否则返回304,代表资源无更新,可以继续使用缓存文件。
Etag/If-None-Match

Etag是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成)。
客户端请求服务端时会设置如下请求头:

If-None-Match:Etag
//Etag是客户端第一次请求服务端时,服务端返回的

服务端收到该请求后,发现该请求含有If-None-Match,则会根据If-None-Match的字段值与该资源在服务器的Etag值做对比,

  • 一致则返回304,代表资源无更新,继续使用缓存文件;
  • 否则重新返回资源,状态码为200.

Etag/If-None-Match优先级比Last-Modified/If-Modified-Since高的原因就是Last-Modified/If-Modified-Since依赖于时间,但是客户端和服务端的时间不一定一致,并且在分布式场景中,服务端各个机器的时间也不一定一致。

优化二:连接复用

HTTP/1.0 每进行一次 HTTP 通信,都需要经历建立 TCP 连接、传输 HTTP 数据和断开 TCP 连接三个阶段。互联网发展到如今,一个页面的渲染会发起十几个HTTP请求,如果每个请求都经历三次握手四次挥手,那会增加很多无关的开销。
为了解决这个问题,HTTP/1.1 中增加了持久连接的方法,它的特点是在一个 TCP 连接上可以传输多个 HTTP 请求,只要浏览器或者服务器没有明确断开连接,那么该 TCP 连接会一直保持。

从上图可以看出,HTTP 的持久连接可以有效减少 TCP 建立连接和断开连接的次数,减少了资源的浪费。

  • 持久连接在 HTTP/1.1 中是默认开启的,不需要专门设置。
  • 如果你不想要采用持久连接,可以在 HTTP 请求头中加上Connection: close。
  • 目前浏览器中对于同一个域名,默认允许同时建立 6 个 TCP 持久连接。
Q:如果同一个域名的HTTP请求超过6个会怎么处理?
A: 如果在同一个域名下有超过6个HTTP请求,例如同时有10个请求发生,那么其中4个请求会进入排队等待状态,直至进行中的请求完成。当然,如果当前请求数量少于6,会直接进入下一步,建立TCP连接。

在浏览器中可以通过Connection ID判断HTTP请求是否复用了同一个TCP连接。

优化三:管线化技术

HTTP长连接默认是串行的,也就是后面的请求得等前面的请求响应了才能继续请求,这就会导致如果一个请求响应慢,就会拖累后面的请求,也就是著名的队头阻塞。HTTP/1.1 中试图通过管线化技术来解决队头阻塞的问题。
HTTP/1.1 中的管线化:将多个 HTTP 请求整批提交给服务器的技术,虽然可以整批发送请求,不过服务器依然需要根据请求顺序来回复浏览器的请求。
但是管线化技术依旧存在诸多限制,导致其未流行起来:

  • 响应必须按照请求发过来的顺序,进行发送,如果顺序错乱,客户端就没办法匹配。
  • 不能使用诸如post这样对数据有副作用的请求方式。
  • 客户端必须做好连接会在任意时刻关闭的准备,还要准备好重发所有未完成的管道化请求。
  • 会产生head of line blocking。即前一个请求遇到了阻塞,就算后面请求已经处理完毕也需要等待前一个请求完成,才能发送所有响应,浪费时间。

优化四:响应分块

在设计 HTTP/1.0 时,必须要知道响应数据的大小,浏览器才可以根据设置的数据大小来接收数据。不过随着技术的发展,很多数据都是动态生成的,因此在传输数据之前并不知道最终的数据大小,这就导致了浏览器不知道何时会接收完所有的文件数据。
HTTP/1.1 通过引入Chunk transfer 机制来解决这个问题,服务器会将数据分割成若干个任意大小的数据块,每个数据块发送时会附上上个数据块的长度,最后使用一个零长度的块作为发送数据完成的标志。

优化五:虚拟主机的支持

在 HTTP/1.0 中,每个域名绑定了一个唯一的 IP 地址,因此一个服务器只能支持一个域名。但是随着虚拟主机技术的发展,需要实现在一台物理主机上绑定多个虚拟主机,每个虚拟主机都有自己的单独的域名,这些单独的域名都公用同一个 IP 地址。
因此,HTTP/1.1 的请求头中增加了Host 字段,用来表示当前的域名地址,这样服务器就可以根据不同的 Host 值做不同的处理。

HTTP2

HTTP/1.1 的问题:

  • TCP慢启动

    前面TCP介绍时,我们有介绍过TCP慢启动,当TCP连接刚建立时,数据的发送是缓慢的,当网络没有拥塞时才会逐渐加快速度。
    这样就会导致页面加载资源的性能会变慢。

  • 队头阻塞

    HTTP长连接默认是串行的,也就是后面的请求得等前面的请求响应了才能继续请求,这就会导致如果一个请求响应慢,就会拖累后面的请求,也就是著名的队头阻塞。

HTTP2的优化:

多路复用

HTTP/2 的设计思路是:一个域名只使用一个 TCP 长连接来传输数据,并且数据传输是并行的,请求之间不存在等待的情况,服务器也可以随时返回响应,不需要保证顺序。

多路复用实现原理

HTTP2增加了一个HTTP分帧层,将上层的HTTP请求进行拆分。

HTTP/2 的请求和接收过程如下:

  1. 浏览器准备好标准HTTP请求体。
  2. 第一步的数据经过分帧层处理,被转换为一个个带有请求 ID 编号的帧;
  3. 这些帧被发送给服务器(可以乱序);
  4. 服务器接收到所有帧之后,会将所有相同 ID 的帧合并为一条完整的请求信息。
  5. 然后服务器处理该条请求,同样的响应结果也被发送到分帧层进行处理。
  6. 浏览器接收到响应帧之后,会根据 ID 编号将帧的数据提交给对应的请求。

对比HTTP1.1,数据格式变为:
在这里插入图片描述

HTTP2 数据帧格式

image.png

名称长度描述
Length3 字节帧的长度
Type1 字节帧的类型
Flags1 字节帧的标识
R1 字节保留位,不需要设置
Stream Identifier31 位每个流的唯一ID
Frame Payload不固定存放数据

Type字段的取值:

帧类型类型编码用途
DATA0x0传递HTTP包体
HEADERS0x1传递HTTP头部
PRIORITY0x2指定Stream流的优先级
RST_STREAM0x3终止Stream流
SETTINGS0x4修改连接或者Stream流的配置
PUSH_PROMISE0x5服务端推送资源时描述请求的帧
PING0x6心跳检测,兼具计算RTT往返时间的功能
GOAWAY0x7优雅的终止连接或者通知错误
WINDOW_UPDATE0x8实现流量控制
CONTINUATION0x9传递较大HTTP头部时的持续帧
HTTP2数据传输

HTTP数据传输主要依赖两个概念:Stream和Frame。
一条TCP连接上有多个Stream,一个Stream上有多个Frame。
一个HTTP请求与响应对应一个Stream,请求报文和响应报文会被分割成为多个Frame。

  • 不同 Stream 的帧是可以并发乱序发送的,因为每个帧的头部会携带 Stream ID 信息,所以接收端可以通过 Stream ID 有序组装成 HTTP 消息。
  • 同一Stream 内部的帧必须是严格有序的,这样客户端/服务端才能根据达到顺序还原报文。(由于tcp可以保证报文的有序,所以只要保证同一stream的报文是有序提交到tcp层的,就可以保证接收方收到时也是有序的)

例如下图所示:

其中:

  • 客户端向服务端请求的资源,属于客户端建立的Stream,Stream ID必须是奇数;
  • 服务端主动向客户端推送的资源,属于服务端建立的 Stream,Stream ID 必须是偶数;
  • 同一个连接中的 Stream ID 是不能复用的,只能顺序递增,所以当 Stream ID 耗尽时,需要发一个控制帧 GOAWAY,用来关闭 TCP 连接。

HTTP3

HTTP2存在问题:

TCP 的队头阻塞


前面有提到,HTTP2同一个域名的请求是跑在一个TCP上的,不同的HTTP请求采用StreamID进行区分。这样可以实现并发。
但是HTTP请求报文被分割成为Frame后,最终还是以TCP报文形式发出的。根据前面每天5分钟玩转计算机网络-(传输层tcp)工作原理 我们知道TCP会保证报文可靠和顺序重组。
按照图中所示,假设在传输过程中5号报文丢失了,即使其余报文已经全部到达了,TCP依旧不会把3,2,6报文提交给HTTP层,就会导致请求1和请求3被请求2阻塞了。
随着丢包率的增加,HTTP/2 的传输效率也会越来越差。有测试数据表明,当系统达到了 2% 的丢包率时,HTTP/1.1 的传输效率反而比 HTTP/2 表现得更好。这是因为HTTP/1.1对于同一个域名会开启6个TCP连接,即使一个请求阻塞,其余的TCP连接还可以继续使用。

TCP 建立连接的延时

由于TCP建立连接必须经历三次握手,并且有慢启动控制,导致初始请求无法弹射起步。

HTTP3优化:

由于以上问题都是TCP的特性导致的,从HTTP设计已经无法再产生本质的改变,于是HTTP3就把目光放到了UDP。
UDP相比TCP有如下优点:

  • 无需三次握手,可以直接发送数据;
  • 简单,不存在慢启动、拥塞控制、流量控制;
  • 报头较小,UDP的包头相对较小,仅包含源端口号和目标端口号等少量信息,这使得UDP在传输数据时的包头开销较小。

UDP的缺点也很明显:

  • 不可靠:UDP不保证数据传输的可靠性,也不保证数据的完整性;
  • 无拥塞控制:UDP有数据就发送,不管网络负载和服务器负载,可能导致网络拥挤和服务器过载;

UDP的有点部分可以解决HTTP2遇到的困境,但是简单的将TCP替换为UDP肯定也是不行的,毕竟没有人会想自己的请求没有任何保障,能不能达到服务端全靠缘分。
于是Google提出基于UDP设计新的可靠层,去弥补UDP的缺点,这个QUIC,于是整体架构变为:

QUIC特点:

  • 可靠传输
    • 由于UDP 不提供可靠性的传输,所以QUIC 在 UDP 的基础之上增加了一层来保证数据可靠性传输。它提供了数据包重传、拥塞控制以及其他一些 TCP 中存在的特性。
  • 安全保证
    • QUIC 使用TLS1.3进行安全加密,相较于早期版本 TLS1.2 有更多的优点,其中最重要的一点是减少了握手所花费的 RTT 个数。
  • 多路复用功能
    • QUIC 实现了在同一TCP连接上可以有多个独立的逻辑数据流(如下图)。实现了数据流的单独传输,就解决了 TCP 中队头阻塞的问题

HTTP/3 帧结构


相比于HTTP2,HTTP3使用了更加简单的帧结构。

HTTP的安全机制

HTTP最初设计时数据是明文在网络上传输的,也就是任何人只要拦截了网络,就可以不费吹灰之力获取到HTTP请求/响应内容,从而非法获取信息。
为了解决这个问题,提出了HTTPS 概念,通过加密的形式去保护请求/响应内容,这样即使报文被劫持,也无法获取其中的内容。

SSL/TLS

HTTP通过引入SSL/TLS层去加解密数据包,如图:

非对称加密:非对称加密

TLS 1.2运行过程

SSL/TLS协议的基本思路是采用 非对称加密+对称加密的综合模式。

第一步:客户端向服务端索要公钥(非对称加密)

第二步:基于非对称加密,生成一个随机秘钥

第三步:基于随机秘钥(对称加密)加密后续通话的报文

上面是一个粗略的执行过程,具体的执行细节类似TCP三次握手:

HTTPS握手(TLS-ECDHE)


实际抓包HTTPS握手过程:

1、ClientHello:TCP连接建立后,Client会发出ClientHello请求,开始进行TLS握手。

2、ServerHello:服务端收到ClientHello请求后,会响应一个ServerHello请求。

可以看到服务端选择的是【TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384】,这是一系列加密算法的组合写法,含义如下:

  • 密钥协商算法使用 ECDHE;
  • 签名算法使用 RSA;
  • 握手后的通信使用 AES 对称算法,密钥长度 256 位,分组模式是 GCM;
  • 摘要算法使用 SHA384;

​3、Server Certificate:服务器把自己的证书发给客户端

4、Server Key Exchange:由于服务器选择了 ECDHE 算法,所以它会发送 Server Key Exchange 。

这一步服务器做了很多事情:

  • 生成随机数作为服务端的椭圆曲线的私钥,保留在本地,不发送给客户端;
  • 根据椭圆曲线规则和私钥生成公钥;
  • 用 RSA签名算法给椭圆曲线公钥生成签名,保证其未被篡改;
  • 以上信息发送给客户端;

随后发送ServeHelloDone代表服务端消息发送结束。

5、Client Key Exchange:由于选择了ECDHE 算法,所以客户端会发送 Client Key Exchange

  • 客户端收到服务端的响应后,会验证服务端的证书是否可靠;
  • 生成随机数作为客户端的椭圆曲线的私钥,保留在本地,不发送给服务端;
  • 根据椭圆曲线规则和私钥生成公钥;
  • 以上信息发送给服务端;

6、计算Pre-Master :
到目前为止客户端和服务器分别拿到了如下参数:
客户端:

  - ClientRandom(客户端随机数)
  - ServerRandom(服务端随机数)
  - Server 椭圆曲线公钥

服务端:

  - ClientRandom(客户端随机数)
  - ServerRandom(服务端随机数)
  - Client 椭圆曲线公钥

客户端和服务端分别使用自己的椭圆曲线私钥和对方的椭圆曲线公钥根据 ECDHE 算法一阵算,算出一个新的随机数:Pre-Master(ECDHE可以保证客户端和服务端算出来的Pre-Master值是一样的)
然后客户端和服务端在分别根据ClientRandom、ServerRandom、Pre-Master生成最终的对称加密秘钥:Master Secret。
后续的报文就通过之前协商的对称加密算法和Master Secret对报文进行加密。

TLS RSA加密

其实最开始的TLS握手过程没有那么复杂,以前使用的是RSA传统的加密手段,但是由于无法保证前向安全所以逐渐淘汰了
握手过程如下:

  1. ClientHello:TLS版本、客户端随机数、一系列加密算法;
  2. ServerHello:TLS版本、服务端随机数、确定选择的加密算法;
  3. Server Certificate:服务器把自己的证书发给客户端;
  4. 客户端验证服务器证书并且提取出公钥,然后生成一个新的随机数,并且使用服务端的公钥加密该随机数,然后将加密后的随机数传递给服务端;
  5. 服务端收到新随机数后,使用私钥解密;
  6. 客户端和服务端就分别有了三个随机数:ClientRandom、ServerRandom、Pre-Master,在根据三个随机数生成Master Secret。
  7. 后续的报文就通过之前协商的对称加密算法和Master Secret对报文进行加密。
TLS_ECDHE优势

可以看出TLS_RSA 跟TLS_ECDHE的主要区别在于Pre-Master的生成和交换过程:
TLS_RSA的Pre_Master是客户端随机生成,然后服务器公钥加密,私钥解密。那么只要服务器的私钥泄漏了,那么所以的历史报文就有可能被破解。
TLS_ECDHE的Pre_Master是临时生成一对公钥私钥,然后根据ECDHE计算出来的,即使被破解了也只影响本次通话,不会影响历史报文。

TLS 1.3运行过程

TLS 1.2极大的解决了HTTP的安全问题,不过随着互联网的发展,TLS 1.2慢慢显露出来弊端,主要集中在性能和安全上。

性能问题

TLS 1.2握手过程中,需要耗费两次往返消息(2-RTT)才能完成加密前置准备。这可能导致几十毫秒甚至上百毫秒的延迟,这对注重性能的程序是影响比较大的。
TLS 1.3 优化:

相比于TLS 1.2,1.3只需要一次往返消息(1-RTT)就可以完成加密准备:
1、ClientHello:TCP连接建立后,Client会发出ClientHello请求,开始进行TLS握手。
相比于1.2,1.3主要多了以下几个参数。

这里的客户端主要传递几个意图:

  1. TLS 1.2,1.3我都支持,可以由你决定使用哪个;
  2. 为了方便我把椭圆曲线参数和对应的公钥都给你,用不用随你;
  3. 我支持这些类型的椭圆曲线,你要用的话只能用这个几个;

2、ServerHello:服务端收到ClientHello请求后,会响应一个ServerHello请求。

这里的服务端主要传递几个意图:

  1. 我们确定用TLS1.3吧;
  2. 我选择了椭圆曲线x25519,对应的参数和公钥也给你了;

通过这样的形式客户端和服务端只需要两条消息就分别拿到了如下数据:
客户端:

  • ClientRandom(客户端随机数)
  • ServerRandom(服务端随机数)
  • Server 椭圆曲线公钥

服务端:

  • ClientRandom(客户端随机数)
  • ServerRandom(服务端随机数)
  • Client 椭圆曲线公钥

接下来就可以计算出Pre-Master和Master Secret。而TLS.1.2需要交换5条消息才能做到。

安全问题

从TLS 1.2运行过程我们知道它支持很多加密算法,但是正是这些加密算法爆出了历史上很多安全漏洞:

  • RSA 密钥传输:不提供前向保密性
  • CBC 模式密码:BEAST 和 Lucky 13 攻击
  • RC4 流密码:在 HTTPS 中使用不安全
  • 任意 Diffie-Hellman 组:CVE-2016-0701
  • 导出密码:FREAK 和 LogJam 攻击

TLS 1.3 优化:
在TLS 1.3中对支持的加密算法进行精简,只保留了如下几种:

  • TLS_AES_128_GCM_SHA256
  • TLS_AES_256_GCM_SHA384
  • TLS_CHACHA20_POLY1305_SHA256
  • TLS_AES_128_CCM_SHA256
  • TLS_AES_128_CCM_8_SHA256

HTTP cookie与session

HTTP最初设计时是无状态的,也就是请求之间没有关键性。这样的好处是方便扩展成集群,但是缺点也很明显:对于论坛,电商购物这类网站是需要知道用户是谁的场景,无状态HTTP就无法支持。
为了解决这个问题,HTTP就设计了Cookie,让HTTP有记忆能力。

Cookie

数据格式

我们前面说过HTTP头部是可以设置很多KV的数据的。Cookie正是利用了这一点。
在HTTP头部中以key=“cookie”,value=自定义kv(不同的kv使用;分割)的形式存在。如图:

工作原理

当你第一次通过浏览器访问服务端时,服务端处理完业务逻辑后,为了标记你是谁就会生成一些kv的数据,然后在响应头里设置“Set-Cookie”=kv,如果存在多组kv那么就会有多个“Set-Cookie”=kv。如图:
然后客户端收到响应后就把“Set-Cookie”里的值全部取出来,并且用;分割组成一条记录然后存储在内存或者本地磁盘。等下次请求的时候就会通过在请求头里设置“Cookie”=kv再把数据带回去。
通过这样的形式,就完成了记忆能力。

Cookie属性

为了增强Cookie的能力,围绕Cookie可以设置一系列属性。

  1. 生命周期(超过一定时间就会失效)
Expires:用的是绝对时间点,例如上图的:expires=Sat, 10-Aug-2024 09:19:18 GMT (202481009:19:18之后过期)
Max-Age:优先级更高,用的是相对时间,单位是秒,浏览器用收到报文的时间点再加上 Max-Age,就可以得到失效的绝对时间。
  1. 作用域(限制cookie只能发送给特定的服务器)
Domain:指定了 Cookie 所属的域名
Path:指定了 Cookie 所属的路径。

浏览器在发送 Cookie 前会从 URI 中提取出 host 和 path 部分,对比 Cookie 的属性。如果不满足条件,就不会在请求头里发送 Cookie。

  1. 安全
HttpOnly:该设置会限制Cookie 只能通过浏览器 HTTP 协议传输,禁止其他方式访问。例如document.cookie 等一切相关的 API都将无法操作Cookie,可以避免脚本攻击。
SameSite:
    SameSite=Strict可以严格限定 Cookie 不能随着跳转链接跨站发送;
    SameSite=Lax允许 GET/HEAD 等安全方法,但禁止 POST 跨站发送;
    通过上面两种形式可以防范“跨站请求伪造”(XSRF)攻击。
Secure:表示这个 Cookie 仅能用 HTTPS 协议加密传输,明文的 HTTP 协议会禁止发送。但 Cookie 本身不是加密的,浏览器里还是以明文的形式存在。

缺点

  1. 安全性问题

    虽然可以通过上文提到的属性加强安全,但是增加了复杂度。并且由于还是明文存储在本地依旧有泄露风险。

  2. 大小受到限制

    大多数浏览器对 Cookie 的大小有 4096 字节的限制

  3. 带宽消耗

    每次HTTP请求都会携带Cookie,如果Cookie存放的信息太多,就会造成流量带宽消耗。

  4. 客户端禁用Cookie

客户端如果禁用了Cookie的,那么围绕Cookie设计的功能都将无法正常使用。

Session

为了解决Cookie的缺点,于是推出了Session。

数据格式

Session依旧使用散列表的形式存储数据,例如Java中的HashMap。可以存储多个kv数据。

工作原理

与Cookie不同,Session的kv数据是存储在服务端的,而Cookie的数据则是存储在客户端。
服务端会为每一个Session生成一个唯一id(sessionid),然后把该id通过Cookie的形式返回给客户端,如图:

等下次再发起请求时,客户端就会通过Cookie字段将该SessionId带上,服务端就可以根据该sessionId找到对应的kv数据,从而完成记忆能力。

如果客户端禁用了Cookie能力,依旧可以通过重写url的形式将sessionid带上(?sessionid=xxx)

WebSocket

HTTP协议是一种请求 - 应答的通信模式,同时还是一种“被动”通信模式,也就是说服务器只能“被动”响应客户端的请求,无法主动向客户端发送数据。
但是在互联网中,存在很多需要服务端主动向客户端推送数据的场景:即时消息、网络游戏以及飞书文档的协同编辑等。在没有WebSocket之前,只能通过客户端【轮询】的形式去不停地问”服务端是否有数据给我“,在请求量比较少的情况下这么做是没有问题的,但是在高并发的情况下非常容易导致服务端过载。
为了解决该问题,于是设计了WebSocket,即允许客户端主动向服务端推送数据,也允许服务端主动向客户端推送数据。

报文结构

RFC文档中对WebSocket报文的格式定义如下所示:

1、FIN :消息结束的标志位,表示数据发送完毕。一个消息可以拆成多个帧,接收方看到 FIN 后,就可以把前面的帧拼起来,组成完整的消息。
2、RSV1、2、3 :三位是保留位,目前没有任何意义,但必须是 0。
3、Opcode :表示帧类型:
1:表示帧内容是纯文本
2:表示帧内容是二进制数据
8:是关闭连接
4、MASK :表示帧内容是否使用异或操作(xor)做简单的加密。目前的 WebSocket 标准规定,客户端发送数据必须使用掩码,而服务器发送则必须不使用掩码。
5、Payload len :表示帧内容的长度。
6、Masking-key :掩码密钥,由上面的标志位 MASK 决定的,如果使用掩码就是 4 个字节的随机数,否则就不存在。
7、Payload Data(continued):真正存放数据的地方。

工作原理

WebSocket并没有从零开始设计,反而是站在HTTP协议的基础上进行设计。WebSocket也需要进行握手后,才能正式收发数据。

客户端:

WebSocket 的握手是一个标准的 HTTP GET 请求,但要带上两个协议升级的专用头字段:

Connection: Upgrade(表示要求协议升级)
Upgrade: websocket(表示要升级成 WebSocket 协议)

同时还增加了两个额外的认证用头字段:

Sec-WebSocket-Key:一个 Base64 编码的 16 字节随机数,作为简单的认证密钥;
Sec-WebSocket-Version:协议的版本号,当前必须是 13。

最终报文如下:

服务端:

服务器收到 HTTP 请求报文,根据上面的四个字段,意识到这是一个WebSocket 升级请求,于是采用WebSocket的方式进行处理。
1、构造一个特殊的 101 Switching Protocols 响应报文;
2、生成Sec-WebSocket-Accept:取出请求头里 Sec-WebSocket-Key 对应的值,加上专用的 UUID 258EAFA5-E914-47DA-95CA-C5AB0DC85B11,然后计算对应的SHA-1摘要。
客户端收到响应报文,就可以用同样的算法,比对值是否相等,如果相等,则握手成功。
最终报文如下:

完整握手交互抓包


websocket报文帧

推荐阅读

1、原来阿里字节员工简历长这样

2、一条SQL差点引发离职

3、MySQL并发插入导致死锁


如果你也觉得我的分享有价值,记得点赞或者收藏哦!你的鼓励与支持,会让我更有动力写出更好的文章哦!
更多精彩内容,请关注公众号「云舒编程」

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1416958.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

华清远见作业第三十四天——C++(第三天)

思维导图&#xff1a; 题目&#xff1a; 设计一个Per类&#xff0c;类中包含私有成员:姓名、年龄、指针成员身高、体重&#xff0c;再设计一个Stu类&#xff0c;类中包含私有成员:成绩、Per类对象p1&#xff0c;设计这两个类的构造函数、析构函数和拷贝构造函数。 代码&#…

LabVIEW动态数据交换实现数据通信

LabVIEW动态数据交换实现数据通信 介绍了LabVIEW软件在驱动一般多功能接口卡中的应用。LabVIEW作为一种图形化编程平台&#xff0c;被广泛应用于自动测量系统、工业过程自动化等领域。利用LabVIEW驱动实验室中常用的多功能接口卡&#xff0c;以实现数据采集和分析。 系统主要…

通讯录项目(终)

Start And Stick 上一期我们将通讯录的项目的基本功能已经实现&#xff0c;这一篇文章我们将对通讯录进行完善。 目录 Start And Stick 上期回顾&#xff1a; 上期必要代码&#xff1a; 数据打印&#xff1a; 代码讲解&#xff1a; 头部插入数据&#xff1a; 代码讲解&…

黑马程序员-瑞吉外卖-day5

修改实体类 package com.itheima.reggie.entity;import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.annotation.TableField; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode;i…

常见の算法5

位图 一个int类型32字节&#xff0c;可以表示0-31这32个数出没出现过&#xff0c;出现过1没出现0&#xff0c;再扩大一点搞个数组&#xff0c;就可以表示0-1023出没出现过&#xff0c;一个long类型可储存64位 如何把10位组成的数&#xff0c;第四位由1改成零 package class05…

【深度学习:开源BERT】 用于自然语言处理的最先进的预训练

【深度学习&#xff1a;开源BERT】 用于自然语言处理的最先进的预训练 是什么让 BERT 与众不同&#xff1f;双向性的优势使用云 TPU 进行训练BERT 结果让 BERT 为您所用 自然语言处理 &#xff08;NLP&#xff09; 面临的最大挑战之一是训练数据的短缺。由于 NLP 是一个具有许多…

绿联私有云DX4600升级DX4600 Pro试用体验 | 全方位解读“卷王”NAS的进化史

哈喽小伙伴们好&#xff0c;我是Stark-C~ 想必很多关注数码圈的朋友都知道绿联这个品牌吧&#xff1f;作为一个深耕数码科技领域数十载的国民大品牌&#xff0c;绿联现在可谓是在数码行业全面开花&#xff0c;并且取得的成就大家也是有目共睹。它家的产品基本都是以高性价比著…

详解SpringCloud微服务技术栈:ElasticSearch实践1——RestClient操作索引库与文档

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位大四、研0学生&#xff0c;正在努力准备大四暑假的实习 &#x1f30c;上期文章&#xff1a;详解SpringCloud微服务技术栈&#xff1a;ElasticSearch原理精讲、安装、实践 &#x1f4da;订阅专栏&#xff1a;微服务技术全家…

C++ 数论相关题目 表达整数的奇怪方式(中国剩余定理)

给定 2n 个整数 a1,a2,…,an 和 m1,m2,…,mn &#xff0c;求一个最小的非负整数 x &#xff0c;满足 ∀i∈[1,n],x≡mi(mod ai) 。 输入格式 第 1 行包含整数 n 。 第 2…n1 行&#xff1a;每 i1 行包含两个整数 ai 和 mi &#xff0c;数之间用空格隔开。 输出格式 输出最小…

使用 create-react-app 创建 react 应用

一、创建项目并启动 第一步&#xff1a;全局安装&#xff1a;npm install -g create-react-app 第二步&#xff1a;切换到想创建项目的目录&#xff0c;使用命令create-react-app hello-react 第三步&#xff1a;进入项目目录&#xff0c;cd hello-react 第四步&#xff1a;启…

内部类 --java学习笔记

内部类 是类中的五大成分之一&#xff08;成员变量、方法、构造器、内部类、代码块&#xff09;&#xff0c;如果一个类定义在另一个类的内部&#xff0c;那么这个类就是内部类当一个类的内部包含了一个整体的事务&#xff0c;且这个事务没必要单独设计时&#xff0c;就可以把…

Java面试题:JMM与锁的理论

王有志&#xff0c;一个分享硬核Java技术的互金摸鱼侠 加入Java人的提桶跑路群&#xff1a;共同富裕的Java人 今天是《面霸的自我修养》的第二弹&#xff0c;内容是Java并发编程中关于Java内存模型&#xff08;Java Memory Model&#xff09;和锁的基础理论相关的问题。这两块内…

网工必备工具:不懂它,何谈高手之位?

点开之前&#xff0c;你脑子里闪出来的工具是什么&#xff1f;ping&#xff1f;又或是arp、tracert、route……&#xff1f; 今天要给你分享的是非常经典的Linux网络抓包工具Tcpdump。 它允许用户拦截和显示发送或收到过网络连接到该计算机的TCP/IP和其他数据包。 Tcpdump 适用…

【语录】岁月

中年 写中年&#xff0c;应该是年少励志三千里 踌躇百步无寸功&#xff0c;转眼高堂已白发 儿女蹒跚学堂中&#xff0c;不如意事常八九&#xff0c;可与人言无二三 可是诸位&#xff0c;不用悲伤&#xff0c;稻盛和夫说&#xff0c; 人生并不是一场物质的盛宴&#xff0c;而是…

12.Golang中类的表示与封装

目录 概述类的表示代码结果 类的封装代码结果 结束 概述 Golang中类的表示与封装 类的表示 代码 注释掉的代码&#xff0c;并不能拿来当赋值或获取值来使用。 package mainimport "fmt"// 类大写则代表&#xff0c;可以被其它包使用 type Hero struct {// 属性方法大…

30岁以就业为目标学前端,快歇着吧;反之50岁都不晚。

Hi&#xff0c;我是贝格前端工场&#xff0c;首先声明声明我们不搞前端培训&#xff0c;有很多老铁在留言中问我关于前端学习的问题&#xff0c;最普遍的一个问题就是30岁以后学前端晚了吗&#xff1f;今天借着此篇文章回答一下。 一、30岁学前端的三种人 首先抛开年龄不说&am…

【计算数组连续值的移动距离】及【计算遥控器按键总次数】

计算数组连续值的移动距离及计算遥控器按键总次数 计算数组连续值的移动距离计算遥控器按键总次数 计算数组连续值的移动距离 /*** 计算数组连续值的移动距离* 给定一个乱序的整数数组&#xff0c;数组中值为1~n&#xff0c;请计算出所有数字移动到比其大1的数字位置的距离和。…

【vue2】路由之 Vue Router

文章目录 一、安装二、基础使用1、简单的示例2、动态路由2.1 定义动态路径参数2.2 获取动态路径的参数2.3 捕获所有路由 3、嵌套路由4、编程式的导航4.1 router.push4.2 router.replace4.3 router.go(n) 5、命名路由6、重定向 三、进阶1、导航守卫1.1 全局前置守卫1.2 全局后置…

1Panel CloudFlare证书申请失败的解决方案

在升级1Panel后&#xff0c;使用 CloudFlare DNS验证时&#xff0c;会提示 [*.biliwind.com] [*.biliwind.com] acme: error presenting token: cloudflare: failed to find zone biliwind.com.: ListZonesContext command failed: Invalid request headers (6003) 为解决此问…

如何在Arxiv上预发表自己的手稿

1. 使用latex编辑好自己的手稿。可以使用latex软件或者overleaf。尽量避免警告&#xff0c;否则会在上传到arxiv时出现意外的错误。 2. https://arxiv.org/登陆并注册arxiv账号 3. 点击 开始新的提交&#xff08;START NEW SUBMISSION&#xff09; 4. 主要的问题是参考文献的导…