跳转至

常见协议解析

HTTP

协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或规则,超文本传输协议(HTTP)是一种通信协议,它允许将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览器。

HTTP协议,即超文本传输协议(Hypertext transfer protocol)。是一种详细规定了浏览器和万维网(WWW = World Wide Web)服务器之间互相通信的规则,通过因特网传送万维网文档的数据传送协议。

HTTP协议是用于从WWW服务器传输超文本到本地浏览器的传送协议。它可以使浏览器更加高效,使网络传输减少。它不仅保证计算机正确快速地传输超文本文档,还确定传输文档中的哪一部分,以及哪部分内容首先显示(如文本先于图形)等。

HTTP是一个应用层协议,由请求和响应构成,是一个标准的客户端服务器模型。HTTP是一个无状态的协议。

在Internet中所有的传输都是通过TCP/IP进行的。HTTP协议作为TCP/IP模型中应用层的协议也不例外。HTTP协议通常承载于TCP协议之上,有时也承载于TLS或SSL协议层之上,这个时候,就成了我们常说的HTTPS。如下图所示:

img

HTTP默认的端口号为80,HTTPS的端口号为443。

浏览网页是HTTP的主要应用,但是这并不代表HTTP就只能应用于网页的浏览。HTTP是一种协议,只要通信的双方都遵守这个协议,HTTP就能有用武之地。比如咱们常用的QQ,迅雷这些软件,都会使用HTTP协议(还包括其他的协议)。

统一资源定位符

URL 的一般形式是:

Text Only
<URL的访问方式>://<主机>:<端口>/<路径>

img

  1. 每个Web站点都运行一个服务器进程,它不断地监听TCP的端口80, 以便发现是否有向它发来连接请求;
  2. 一旦收到请求并建立了TCP连接之后,浏览器就向服务器发出某个页面的请求, 服务器接着就返回请求的页面作响应;
  3. 最后连接被释放。这之间一系列信息的传输都遵循HTTP。

Web工作过程

**img

上图用户点击鼠标后所发生的事件:

  1. 浏览器分析超链指向页面的 URL;

  2. 浏览器向 DNS 请求解析 www.tsinghua.edu.cn 的 IP 地址;

  3. 域名系统 DNS 解析出清华大学服务器的 IP 地址;

  4. 浏览器与服务器建立 TCP 连接;

  5. 浏览器遵循HTTP协议发出取文件请求;

Text Only
GET /chn/yxsz/index.htm

6.服务器给出响应,把文件 index.htm 发给浏览器;

7.TCP 连接释放;

8.浏览器显示“清华大学院系设置”文件 index.htm 中的所有文本。

HTTP 报文

HTTP 有两类报文:

  1. 请求报文——从客户向服务器发送请求报文。

  2. 响应报文——从服务器到客户的回答。

请求报文

img

报文由三个部分组成,即**开始行、首部行和实体主体**。

在请求报文中,开始行就是请求行。

方法

“方法”是面向对象技术中使用的专门名词。所谓“方法”就是对所请求的对象进行的操作,因此这些方法实际上也就是一些命令。因此,请求报文的类型是由它所采用的方法决定的。

HTTP 请求报文的一些方法

img

URL

“URL”是所请求的资源的 URL。

版本

“版本”是 HTTP 的版本。

一个请求报文的例子

img

响应报文

img

响应报文的开始行是状态行。

状态行包括三项内容,即 HTTP 的版本,状态码,以及**解释状态码的简单短语**。

状态码都是三位数字 :

  • 1xx 表示通知信息的,如请求收到了或正在进行处理。
  • 2xx 表示成功,如接受或知道了。
  • 3xx 表示重定向,表示要完成请求还必须采取进一步的行动。
  • 4xx 表示客户的差错,如请求中有错误的语法或不能完成。
  • 5xx 表示服务器的差错,如服务器失效无法完成请求。

一个响应报文的例子:

img

使用WireShark实例分析

下面是一个用wireShark获取的http协议包:

img

可以看到这是post方法

Text Only
/pcsuiteprofile/api/updateinfo?u=38e37ccd&len=24
HTTP/1.1  \r\n
Host、Accept、Content-Type、Content-Length等等。

展开Post,具体分析,如图:

img

选中post,下边的16进制中显示的是:50 4f 53 54正好是POST四个字母对应的16进制ASCII,可以自行去对比ASCII。

DNS

DNS解析过程

当我们在浏览器输入www.baidu.com等网址时,实际上首先需要DNS将域名解析为IP,我们才能访问到对应的资源,其大概过程如下:

递归查询

如果主机所询问的本地域名服务器不知道被查询域名的 IP 地址,那么本地域名服务器就以 DNS 客户端的身份,向其他根域名服务器继续发出查询请求报文,即替主机继续查询,而不是让主机自己进行下一步查询。

1、主机首先向其本地域名服务器进行递归查询。

2、本地域名服务器收到递归查询的委托后,也采用递归查询的方式向某个根域名服务器查询。

3、根域名服务器收到递归查询的委托后,也采用递归查询的方式向某个顶级域名服务器查询。

4、顶级域名服务器收到递归查询的委托后,也采用递归查询的方式向某个权限域名服务器查询。

迭代查询

当根域名服务器收到本地域名服务器发出的迭代查询请求报文时,要么给出所要查询的IP 地址,要么告诉本地服务器下一步应该找哪个域名服务器进行查询,然后让本地服务器进行后续的查询。

1、主机首先向其本地域名服务器进行递归查询。

2、本地域名服务器采用迭代查询,它先向某个根域名服务器查询。

3、根域名服务器告诉本地域名服务器,下一次应查询的顶级域名服务器的IP地址。

4、本地域名服务器向顶级域名服务器进行迭代查询。

5、顶级域名服务器告诉本地域名服务器,下一次应查询的权限域名服务器的IP地址。

6、本地域名服务器向权限域名服务器进行迭代查询。

7、权限域名服务器告诉本地域名服务器所查询的域名的IP地址。

8、本地域名服务器最后把查询的结果告诉主机。

DNS报文

DNS 一般采用 UDP 作为传输层协议( TCP 亦可),端口号是 53 。请求报文和应答报文均作为数据,搭载在 UDP 数据报中进行传输:

DNS 报文分为 请求 和 应答 两种,结构是类似的,大致分为五部分:

  • 头部( header ),描述报文类型,以及其下 4 个小节的情况;
  • 问题节( question ),保存查询问题;
  • 答案节( answer ),保存问题答案,也就是查询结果;
  • 授权信息节( authority ),保存授权信息;
  • 附加信息节( additional ),保存附加信息;

也有不少文献将 DNS 请求称为 DNS 查询( query ),两者是一个意思。

其中,头部是固定的,共 12 字节;其他节不固定,记录数可多可少,数目保存在头部中。头部分为 6 个字段:

  • 标识( identifier ),一个 16 位的 ID ,在应答中原样返回,以此匹配请求和应答;
  • 标志( flags ),一些标志位,共 16 位;
  • 问题记录数( question count ),一个 16 位整数,表示问题节中的记录个数;
  • 答案记录数( answer count ),一个 16 位整数,表示答案节中的记录个数;
  • 授权信息记录数( authority record count ),一个 16 位整数,表示授权信息节中的记录个数;
  • 附加信息记录数( additional record count ),一个 16 位整数,表示附加信息节中的记录个数;

最后,我们来解释一下标志字段中的各个标志位:

  • QR 位标记报文是一个查询请求,还是查询应答;
    • 0 表示查询请求;
    • 1 表示查询应答;
  • 操作码( opcode )占 4 位,表示操作类型:
    • 0 代表标准查询;
    • 1 代表反向查询;
    • 2 代表服务器状态请求;
  • AA 位表示 权威回答( authoritative answer ),意味着当前查询结果是由域名的权威服务器给出的;
  • TC 位表示 截短( truncated ),使用 UDP 时,如果应答超过 512 字节,只返回前 512 个字节;
  • RD 位表示 期望递归 ( recursion desired ),在请求中设置,并在应答中返回;
    • 该位为 1 时,服务器必须处理这个请求:如果服务器没有授权回答,它必须替客户端请求其他 DNS 服务器,这也是所谓的 递归查询 ;
    • 该位为 0 时,如果服务器没有授权回答,它就返回一个能够处理该查询的服务器列表给客户端,由客户端自己进行 迭代查询 ;
  • RA 位表示可递归( recursion available ),如果服务器支持递归查询,就会在应答中设置该位,以告知客户端;
  • 保留位,这 3 位目前未用,留作未来扩展;
  • 响应码( response code )占 4 位,表示请求结果,常见的值包括:
    • 0 表示没有差错;
    • 3 表示名字差错,该差错由权威服务器返回,表示待查询的域名不存在;

问题记录

客户端查询域名时,需要向服务端发送请求报文;待查询域名作为问题记录,保存在问题节中。

img

问题节支持保存多条问题记录,记录条数则保存在 DNS 头部中的问题记录数字段。这意味着,DNS 协议单个请求能够同时查询多个域名,虽然通常只查询一个。

一个问题记录由 3 个字段组成:

  • 待查询域名( Name ),这个字段长度不固定,由具体域名决定;
  • 查询类型( Type ),域名除了关联 IP 地址,还可以关联其他信息,常见类型包括(下节详细介绍):
    • 1 表示 A 记录,即 IP 地址;
    • 28 表示 AAAA 记录,即 IPv6 地址;
    • etc
  • 类 ( Class )通常为 1 ,表示 TCP/IP 互联网地址;

最后,我们回过头来考察域名字段,它的长度是不固定的。域名按 . 切分成若干部分,再依次保存。每个部分由一个前导计数字节开头,记录当前部分的字符数。

以域名 fasionchan.com. 为例,以 . 切分成 3 个部分,fasionchan 、com 以及空字符串 。请注意,空字符串 代表根域。因此,待查询域名字段依次为:

  • 一个前导字节保存整数 10 ,然后 10 个字节保存 fasionchan 部分(二级域);
  • 一个前导字节保存整数 3 ,然后 3 个字节保存 com 部分(一级域);
  • 一个前导字节保存整数 0 ,然后 0 个字节保存 ``部分(根域);

由此可见,每一级域名的长度理论上可以支持多达 255 个字符。

查询类型 名称代码 描述
1 A IPv4地址
2 NS 名称服务器
5 CNAME 规范名称
15 MX 电子邮件交互
16 TXT 文本信息
28 AAAA IPv6地址

查询类型这里先不展开,下一小节会详细介绍。

资源记录

服务端处理查询请求后,需要向客户端发送应答报文;域名查询结果作为资源记录,保存在答案以及其后两节中。

img

答案节、授权信息节和附加信息节均由一条或多条资源记录组成,记录数目保存在头部中的对应字段,不再赘述。

资源记录结构和问题记录非常相似,它总共有 6 个字段,前 3 个和问题记录完全一样:

  • 被查询域名( Name ),与问题记录相同;
  • 查询类型( Type ),与问题记录相同;
  • 类 ( Class ),与问题记录相同;
  • 有效期( TTL ),域名记录一般不会频繁改动,所以在有效期内可以将结果缓存起来,降低请求频率;
  • 数据长度( Resource Data Length ),即查询结果的长度;
  • 数据( Resource Data ),即查询结果;

如果查询类型是 A 记录,那查询结果就是一个 IP 地址,保存于资源记录中的数据字段;而数据长度字段值为 4 ,因为 IP 地址的长度为 32 位,折合 4 字节。

报文实例

我们以 test.fasionchan.com 这个域名为例,来讲解 DNS 查询请求报文和应答报文。

执行 dig 命令即可查询该域名:

Text Only
dig test.fasionchan.com

我们对查询 test.fasionchan.com 的一次通信过程进行抓包,结果保存在 Github 上,以供参考。童鞋们可以将抓包结果下载到本地,并用 WireShark 打开,并结合讲解进行分析。

请求报文

img

抓包结果请求报文只有头部、问题节和附加节,图解假设没有附加节。

先看头部,问题记录数为 1 ,其他记录数都是 0 。这意味着,请求报文只有问题节,而且问题节中只有一条问题记录,只查询一个域名。头部中的标志位分别如下:

  • QR=0 ,表示该报文是一个请求报文;
  • 操作码为 0 ,表示这个 DNS 请求是一个标准请求;
  • TC=0 ,表示请求报文没有被截短;
  • RD=1 ,表示客户端希望服务器可以执行递归查询;

问题记录我们已经很熟悉了,不再赘述:

  • Type=1 ,表示客户端希望查询 A 记录,即与域名关联的 IP 地址;
  • Class=1 ,代表 TCP/IP 互联网;

image-20260228224830419

应答报文

img

抓包结果应答报文只有头部、问题节和答案节。其中,问题节中的问题记录与请求报文一样,图中就不展开了。

先看头部,问题记录数为 1 ,答案记录数也是 1 ,其他记录数都是 0 。这意味着,应答报文只有问题节和答案节,而且它们各自只有一条记录。头部中的标志位分别如下:

  • QR=1 ,表示该报文是一个应答报文;
  • 操作码为 0 ,表示这个 DNS 请求是一个标准请求;
  • AA=0 ,表示结果不是由域名的权威服务器返回的,因为查询对象是本地的 DNS 缓存服务器(如果是向权威服务器发起查询,它返回的应答报文 AA=1 );
  • TC=0 ,表示应答报文没有被截短;
  • RD=1 ,与请求报文保持一致,略;
  • RA=1 ,表示服务端支持递归查询;
  • 响应码为 0 ,表示查询成功,没有出错;

答案节中的资源记录就是查询结果,前 3 个字段与问题记录一样,不再赘述。

TTL 字段是一个整数,表示有效期,单位是秒。例子中的查询结果,有效期是752秒,即 12 分 32 秒。也就是说,查询结果从现在开始算,12分32秒内均有效,无须重新请求。

查询结果是一个 IP 地址,长度为 4 个字节,保存在资源数据字段中。

image-20260228224938072

TCP

TCP 是 传输控制协议( Transmission Control Protocol )的简称,它是一种 面向连接的流式协议 ,可为应用程序提供 可靠的字节流传输服务 。

TCP应答机制

建立连接(三次握手)

为保证可靠性,TCP 需要先建立连接才能开始传输数据。

  1. 连接主动发起方(一般是客户端),向被动连接方(一般是服务端)发出 SYN ;
  2. 被动连接方收到 SYN 后,向主动发起方回复 SYN+ACK ;
  3. 主动发起方收到 SYN 后,向被动连接方回复 ACK ;

接收确认

TCP 将数据组织成连续的字节流,每个字节均可由一个唯一的序号来标识:

img

为了简化讨论,上图假设序号从 0 开始:字节流第一个字节为 0 ;第二个字节为 1 ;以此类推。

实际上,出于安全性和健壮性考虑,TCP 序号并非从 0 开始,而是有目的地“随机”选择。在三次握手阶段,SYN 包会将本端挑选的起始序号告诉对端。

img

TCP 在发送数据时,会将数据的 起始序号 和 长度 告诉对端。接收方收到数据后,将发送 ACK 对数据进行确认。ACK 中包含确认序号,它的值为最后一个已接收字节的序号加一,也就是接收方期望收到的新数据的起始序号。

如下图,假设主机①向主机②发送一段数据。它告诉主机②,数据的起始字节序号为 1000 ,总共 100 字节,最后一个字节的序号为 1099 :

img

主机②收到数据后,发送 ACK 对数据进行确认,确认序号为 1100 。这相当于告诉主机①:序号 1100 以前的数据均已收到,可以发序号 1100 的数据给我了。

这样一来,只要主机①收到 ACK ,它就可以确定:数据已经成功送达了。

超时重传

如果发送方迟迟没有收到接收方的确认,说明数据很有可能在传输的过程中丢掉了。这时,发送方只能 重传 数据。

实际上,发送方在发送数据的同时,将启动一个定时器。如果在规定的时间内没有收到 ACK ,它就开始重传数据。

流量控制

不同主机处理能力各有差异,发送方和接收方处理速度协调不好就会有大问题。举个例子,如果接收方处理速度较慢,发送方还拼命地发送数据,就只能白白浪费网络资源了。

好在 TCP 实现了流量控制机制,使得发送方可以根据接收方的处理速度,自动调节发送速度。那么,TCP 是如何做到这点的呢?

根据 TCP 协议规定,接收方需要维护一个 接收窗口 ,我们可以将它看作内存中的一个缓冲区。在连接建立和数据传输的过程中,接收方会将自己的接收窗口大小通告给发送方。发送方必须保证,发送的数据不超过接收窗口。如果接收窗口被占满,发送方就暂停发送新数据。

img

重置连接

RST 标志用于表示一个连接出现了异常或无效的状态,需要立即终止。

当某一方发送 RST 时,连接会立即终止,无需等待 ACK。

连接关闭(四次挥手)

TCP 连接建立后,我们得到了两个独立的字节传输流。他们传输方向相反,一起构成了全双工的传输信道。

img

当某个方向的数据传输完毕,发送方可以发送 FIN 指令,告诉接收方该方向传输流已经关闭。先关闭传输流的一方称为主动关闭方,另一方则成为被动关闭方。

假设主机①数据发送完毕,它向主机②发出 FIN ,成为主动关闭方;主机②则成为被动关闭方,它回复 ACK 后,从主机①到主机②的数据流关闭。

img

这时,连接处于 半关闭状态 ,反方向的数据流仍然有效。也就是说,这时主机②还可以向主机①发送数据。

当主机②也发完数据,它同样发出 FIN 指令,告诉主机①数据流关闭;主机①收到 FIN 并回复 ACK 后,连接就完全关闭了。这就是 TCP 连接关闭的主要步骤,也被形象地称为“四次挥手”。

TCP报文

由于 TCP 协议位于传输层,它的传输单元一般叫做 TCP段( segment ),也可译为 TCP分组 。当然了,也有不少文献将它笼统地称为 TCP报文 。

  1. 源端口

第一个字段是 源端口( source port ),它的长度为 16 位,表示报文 发送方 的端口号。

  1. 目的端口

第二个字段是 目的端口( destination port ),它的长度为 16 位,表示报文 接收方 的端口号。

  1. 序号

序号( sequence number )字段,长度为 32 位,表示数据首字节的序号。在三次握手阶段,SYN 指令也是通过该字段,将本端选定的 起始序号 告诉接收方。

  1. 确认号

确认号 ( acknowledgement number )字段,长度为 32 位。它表示已确认收到的数据序号,它的值为:已收到数据最后一个字节的序号加一,即接收方期望进一步接收的数据序号。

  1. 头部长度

头部长度 ( header length )字段,长度为 4 位,表示 TCP 报文头部的长度,也可称为 数据偏移 ( data offset )。跟 IP 协议一样,TCP 头部长度字段也不是以字节为单位,而是以 32 位字(4字节)为单位。

字( word )是计算机领域中的一个概念,表示由一系列比特组成的数据单位。字的长度可长可短,常见的有 8 位字、16 位字以及 32 位字等等。

这个字段长度为 4 位,最大值为 。因此,TCP 头部最大长度只能达到 字节。

  1. 保留

保留 ( reversed )字段,长度为 3 位,保留未用。

  1. 标志位

标志位( flags ),长度为 9 位,用于保存一些标志位。前面提到的 SYN ACK FIN 等指令,就是以标志位的形式保存在该字段中。这样的标志位,总共有 9 个:

  • NS ,ECN显式拥塞通知,属于 TCP 扩展,略;
  • CWR ,同样属于 TCP 扩展,略;
  • ECE ,同样属于 TCP 扩展,略;
  • URG ,紧急数据指令,表示紧急指针有效,报文段包含高优先级数据;
  • ACK ,确认指令,表示确认号有效,对已接收数据进行确认;
  • PSH ,立即推送指令,指示接收方立即将数据提交给应用层,不用等缓冲区装满;
  • RST ,重置指令,表示出现严重错误,常用于拒绝非法报文段以及拒绝连接请求;
  • SYN ,序号同步指令,在 TCP 三次握手建立连接时,将本端选定序号告诉对端;
  • FIN ,连接关闭指令,用于告诉对端,本端数据已发送完毕,连接关闭;

  • 窗口大小

窗口大小( window size )字段长度为 16 位,表示当前报文发送者接收窗口的大小,单位一般是 字节 。接收窗口表示接收方还能接收的数据大小,用于实现 TCP 流量控制 机制,后续章节再展开介绍。

  1. 校验和

校验和( checksum )字段长度为 16 位,保存报文段的校验和,用于纠错。跟 UDP 协议一样,TCP 整个报文段都会参与校验和计算。除此之外,TCP 还会在报文段前面拼接一个 IP 伪头部,同时参与校验和计算:

img

数据长度

您可能会有这样的疑问:TCP 报文段由头部和数据两部分组成,但头部并没有记录数据的长度。那么,TCP 协议是如何确定数据长度的呢?

答案其实非常简单,——可以根据 IP 包的长度来计算!

我们知道,传输层报文段需要借助网络层的传输能力,作为数据搭载在网络层包中,发往目标主机。如下图,为了将 TCP 报文段发往目标主机,协议栈将它作为数据封装成 IP 包,并发送出去:

img

换句话说,IP 包的数据部分就是一个 TCP 报文段;只要 IP 包的数据长度确定,TCP 报文的长度也就确定了。

回忆 IP 协议相关内容,我们知道 IP 包头部中有 头部长度 和 总长度 两个字段,总长度减去头部长度即是IP包数据部分的长度。因此,TCP 报文段数据部分的长度可以这样计算:

Text Only
IP包长度 - IP包头部长度 - TCP头部长度

Wireshark示例

第一次握手(客户端-服务端)

image-20260301165849369

第二次握手(服务端-客户端)

image-20260301170031216

第三次握手(客户端-服务端)

image-20260301170123896

发送数据

image-20260301170306292

第一次挥手

第二次挥手

第三次挥手

第四次挥手

TLS/SSL

SSL(Secure Sockets Layer)和 TLS(Transport Layer Security)都是为网络通信提供安全和数据完整性的加密协议。

SSL 是由网景公司在1990年代早期开发。TLS是其后续版本,由互联网工程任务组(IETF)开发。虽然两者在技术上有所不同,但它们的目标和功能基本相同,因此通常一起讨论,并且术语 “SSL/TLS” 常常被用来表示两者。

SSL/TLS 协议主要有两个目的:一是确保数据在传输过程中的隐私,二是确保数据在传输过程中的完整性。这是通过在数据传输开始时进行一次“握手”来实现的,以便服务器和客户端可以就如何加密数据进行协商,并可选地验证对方的身份。

在握手过程中,服务器和客户端会协商一个密钥,然后使用这个密钥对传输的数据进行加密和解密。这样,即使数据在传输过程中被拦截,也无法读取其内容,除非拦截者知道密钥。

此外,SSL/TLS 还可以使用数字证书来验证服务器(或在某些情况下,客户端)的身份。这是通过将服务器的公钥和一些身份信息打包到一个由受信任的第三方(称为证书颁发机构)签名的证书中来实现的。客户端可以验证证书的签名,以确保它是与服务器通信,而不是与冒充服务器的攻击者通信。

总的来说,SSL/TLS是一种重要的安全协议,用于保护网络通信不被窃听或篡改。

image-20251117111100190

TLS v1.2握手过程

TLS 握手原理是双方互换信息,协商出共享的 会话密钥。

Text Only
客户端随机数 + 服务端随机数 + 预主密钥 = 主密钥 ==> 会话密钥

image-20251117144144869

第一次握手

客户端首先会发一个「Client Hello」消息,消息里面有客户端使用的 TLS 版本号、支持的密码套件列表、支持的椭圆曲线、支持的签名算法,以及生成的**随机数(Client Random)**。

image-20251117144735783

image-20251117144821194

第二次握手

服务端收到客户端的「打招呼」,同样也要回礼,会返回「Server Hello」消息,消息面有服务器确认的 TLS 版本号,也给出了一个**随机数(Server Random)**,然后从客户端的密码套件列表选择了一个合适的密码套件。

image-20251117145125653

不过,这次选择的密码套件就和 RSA 不一样了,我们来分析一下这次的密码套件的意思。

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

接着,服务端为了证明自己的身份,发送「Certificate」消息,会把证书也发给客户端。

image-20251117145532898

这一步就和 RSA 握手过程有很大到区别了,因为服务端选择了 ECDHE 密钥协商算法,所以会在发送完证书后,发送「Server Key Exchange」消息。

image-20251117145709978

这个过程服务器做了三件事:

  • 选择了**名为 named_curve 的椭圆曲线**,选好了椭圆曲线相当于椭圆曲线基点 G 也定好了,这些都会公开给客户端;
  • 生成随机数作为服务端椭圆曲线的私钥,保留到本地;
  • 根据基点 G 和私钥计算出**服务端的椭圆曲线公钥**,这个会公开给客户端。

也就是传输ECDH算法的公开参数

为了保证这个椭圆曲线的公钥不被第三方篡改,服务端会用 RSA 签名算法给服务端的椭圆曲线公钥做个签名。

随后,就是「Server Hello Done」消息,服务端跟客户端表明:“这些就是我提供的信息,打招呼完毕”。

image-20251117145830844

至此,TLS 两次握手就已经完成了,目前客户端和服务端通过明文共享了这几个信息:Client Random、Server Random 、使用的椭圆曲线、椭圆曲线基点 G、服务端椭圆曲线的公钥,这几个信息很重要,是后续生成会话密钥的材料。

第三次握手

客户端收到了服务端的证书后,自然要校验证书是否合法,如果证书合法,那么服务端到身份就是没问题的。校验证书到过程,会走证书链逐级验证,确认证书的真实性,再用证书的公钥验证签名,这样就能确认服务端的身份了,确认无误后,就可以继续往下走。

客户端会生成一个随机数作为客户端椭圆曲线的私钥,然后再根据服务端前面给的信息,生成**客户端的椭圆曲线公钥**,然后用「Client Key Exchange」消息发给服务端。

image-20251117150539005

至此,双方都有对方的椭圆曲线公钥、自己的椭圆曲线私钥、椭圆曲线基点 G。于是,双方都就计算出点(x,y),其中 x 坐标值双方都是一样的,前面说 ECDHE 算法时候,说 x 是会话密钥,但实际应用中,x 还不是最终的会话密钥。

还记得 TLS 握手阶段,客户端和服务端都会生成了一个随机数传递给对方吗?

最终的会话密钥,就是用「客户端随机数 + 服务端随机数 + x(ECDHE 算法算出的共享密钥) 」三个材料生成的。

之所以这么麻烦,是因为 TLS 设计者不信任客户端或服务器「伪随机数」的可靠性,为了保证真正的完全随机,把三个不可靠的随机数混合起来,那么「随机」的程度就非常高了

算好会话密钥后,客户端会发一个「Change Cipher Spec」消息,告诉服务端后续改用对称算法加密通信。

image-20251117150809536

接着,客户端会发「Encrypted Handshake Message」消息,把之前发送的数据做一个摘要,再用对称密钥加密一下,让服务端做个验证,验证下本次生成的对称密钥是否可以正常使用。

image-20251117151005814

第四次握手

最后,服务端也会有一个同样的操作,发「Change Cipher Spec」和「Encrypted Handshake Message」消息,如果双方都验证加密和解密没问题,那么握手正式完成。于是,就可以正常收发加密的 HTTP 请求和响应了。

image-20251117151035288

总结

下载

序号 方向 握手 过程 描述
1 C -> S 第一次 Client Hello 客户端发送它支持的 TLS 版本,加密套件列表,客户端随机数给服务端
2 S -> C 第二次 Server Hello 服务端发送它选择的 TLS 版本,加密套件,服务端随机数给客户端
3 S -> C 第二次 Certificate 服务端发送 CA 证书(公钥 + 证书持有者等信息)给客户端
4 S -> C 第二次 Server Key Exchange 1. 服务端生成椭圆曲线私钥 ==> 生成椭圆曲线公钥 ==> 服务端的 RSA 私钥实现椭圆曲线公钥签名 2. 服务端发送:椭圆曲线算法信息,(服务端的)椭圆曲线公钥,(服务端的)椭圆曲线公钥签名给客户端
5 S -> C 第二次 Server Hello Done 服务端发送确认给客户端,已完成 Hello 阶段流程
6 C -> S 第三次 Client Key Exchange 客户端生成椭圆曲线公钥,并将其发送给服务端
7 C -> S 第三次 Change Cipher Spec 客户端通知服务端,确认握手过程中的加密算法和密钥已经生效,表示之后的消息都将使用新的密钥
8 C -> S 第三次 Encrypted Handshake Message 客户端将之前的握手数据(发送和接收)做一个摘要,再用会话密钥(对称密钥)加密摘要数据,将密文发送给服务端
9 S -> C 第四次 New Session Ticket 服务器发送该消息给客户端,包含一个新的会话票据,用于快速恢复会话,避免重复握手
10 S -> C 第四次 Change Cipher Spec 服务端接收到客户端生成的 椭圆曲线公钥,也协商出共享的 会话秘钥,并通知客户端表示之后的消息都将使用新的密钥
11 S -> C 第四次 Encrypted Handshake Message 服务端将之前的握手数据(发送和接收)做一个摘要,再用会话密钥(对称密钥)加密摘要数据,将密文发送给客户端,确认握手过程的完成

TLS v1.3握手过程

TLS v1.3的握手过程相较于TLS v1.2来说变化不大,主要是减少了往返过程从而提高了性能,并且还删除了之前TLS v1.2存在的不安全算法,以下是TLS v1.3握手流程图

Text Only
sequenceDiagram
    Client->>Server: ClientHello (key_share)
    Server->>Client: ServerHello (key_share) + EncryptedExtensions + Certificate + CertificateVerify + Finished
    Client->>Server: Finished
特性/场景 TLS 1.2 TLS 1.3
握手耗时 2-RTT 1-RTT(或 0-RTT)
密钥交换算法 支持 RSA(非前向安全) 仅 ECDHE/DHE(强制前向安全)
握手消息合并 多步骤(如 ServerKeyExchange) 合并至 ServerHello 后
0-RTT 支持 不支持 支持(基于 PSK)
不安全算法 允许 SHA-1、RC4 等 完全移除
会话恢复机制 Session ID 或 Session Ticket 优先使用 PSK 和 Session Ticket
首次连接延迟 高(2-RTT) 低(1-RTT)
重连延迟(会话恢复) 中(1-RTT) 极低(0-RTT)
抗量子计算攻击 弱 更强(支持 X25519 等算法)

Note

由于TLS v1.3是2018年发表的,所以部分旧设备还未适配TLS v1.3,所以TLS v1.2仍是HTTPS中使用最广泛的协议

参考文章

TLS 1.2 与 TLS 1.3 握手流程深度解析:安全与性能的演进 | Symbol Crash

TLS1.3握手流程以及参数详解 – 绿盟科技技术博客

ICMP

互联网控制消息协议 ( Internet Control Message Protocol )简称 ICMP ,是 IP 的辅助协议,同样位于网络层,负责网际通信中 控制信息 和 差错信息 的传送。

ICMP 有赖 IP 提供的网际通信能力,它的报文作为数据承载在 IP 包中进行传输:

img

注意到,IP 包头部中的 protocol 字段,用于标识数据部分所属的协议,可以当做数据类型来理解。如果 protocol 字段的值为 1 ,说明 IP 包的数据部分是一个 ICMP 报文。

那么,ICMP 报文的格式又长啥样呢?

img

ICMP 报文同样分为 头部 和 数据 两部分,其中头部字段如下:

  • 类型 ( type ),顾名思义用来标识 ICMP 报文的类型,例如 目的不可达 ( destination unreachable )差错报文;
  • 代码 ( code ),进一步划分 ICMP 报文的类型,标识错误的原因,例如目的不可达可以进一步分成网络不可达、主机不可达以及端口不可达等等;
  • 校验和 ( checksum ),用于差错校验,由 ICMP 头部计算得出;

常见的 ICMP 报文类型列举如下表:

类型 描述 状态 查询 差错
0 回显响应 ✔️
1 保留 未分配
2 保留 未分配
3 目的不可达 ✔️
4 源端关闭 弃用 ✔️
5 重定向 ✔️
6 备用主机地址 弃用
7 保留 未分配
8 回显请求 ✔️
9 路由通告 ✔️
10 路由请求 ✔️
11 超时错误 ✔️
12 参数错误(IP头部错误) ✔️
13 时间戳请求 ✔️
14 时间戳应答 ✔️
…

image-20260228225629351

image-20260228225642866

Note

值得一提的是,windows平台下ICMP默认的payload data为61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 61 62 63 64 65 66 67 68 69,也就是abcdefghijklmnopqrstuvwabcdefghi

Websocket

Web 应用采用 HTTP 协议进行通信:客户端向服务器发送 HTTP 请求,服务器对请求进行处理后,向客户端回复 HTTP 响应。换句话讲,HTTP 协议只能客户端主动发起请求,服务器被动进行响应。

不少应用场景要求服务主动向客户端进行推送,这时 HTTP 协议就有点捉襟见肘了。举个例子,为实现 Web 聊天室功能,当新消息到达时,服务器必须向客户端推送通知。只用 HTTP 协议来实现,我们必须在客户端做轮询。

轮询有个致命的缺陷——性能比较差:如果轮询频率很高,服务器要消耗很多资源;但如果控制轮询频率,应用消息通知的实时性又大打折扣。

很显然,服务器主动向客户端推送数据,也是一个非常常见的应用场景,最好能从网络协议层面进行支持。为此,计算机网络先驱们设计了 WebSocket 协议。

WebSocket 协议,顾名思义为 Web 应用引入了 套接字( socket )通信能力。Websocket 是一种应用层协议,以 TCP 为底层传输协议,为通信双方提供了一个 全双工 的信道。

为了兼容 Web 主流应用协议 HTTP ,WeSocket 复用 80 和 443 端口,并使用 HTTP 请求来建立连接(配合 Upgrade 头部)。因此,WebSocket 可以兼容现有的 HTTP代理 和中间件,例如 Nginx 。

URL

和 HTTP 协议一样,WebSocket 服务器地址也用 URL 表示,只是协议部分为 ws 或 wss 。例如:

Text Only
# ws代表WebSocket协议,端口为80
ws://api.fasionchan.com/chat

# wss代表WebSocket安全协议,与https类似,端口为443
wss://api.fasionchan.com/chat

连接建立

客户端先通过 TCP 协议连到服务器,然后通过 TCP 连接向服务器发送 HTTP 请求。请注意,HTTP 请求头中要带 Upgrade 头部,告诉服务器将连接升级到 WebSocket 协议:

Text Only
GET /chat HTTP/1.1
Host: localhost:8080
User-Agent: Go-http-client/1.1
Connection: Upgrade
Sec-WebSocket-Key: bLPIf/xpAnrtCKuifPKTUg==
Sec-WebSocket-Version: 13
Upgrade: websocket

服务器接到请求后,检查 Upgrade 头部,发现客户端想将连接协议升级到 WebSocket 。如果应用服务器支持 WebSocket ,它便回复 101 状态码,表示同意切换协议:

Text Only
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: lShvB7NL9TbGxezz+KUd5ee6jhA=

img

HTTP 请求和响应交互完毕后,通信双方就可以在 TCP 连接上互相发送 WebSocket 报文了。

数据帧

连接建好后,通信双方就可以用 WebSocket 协议来发送数据了。WebSocket 将数据组织成一系列帧( frame )来传输,一条应用层消息可以封装成一个或多个数据帧。数据帧报文结构如下所示:

img

  • 标志位 ,占 4 位,每个标识占一位;
    • FIN 标识表示这是一条消息的最后一帧;
    • RSV1 、RSV2 和 RSV3 预留给协议拓展用,本文不讨论;
  • 操作代码 ( opcode ),占 4 位,表示帧的类型,其中 0~7 表示非控制( non-control )帧,8~15 表示控制( control )帧(非控制帧用于承载应用数据,控制帧用于连接控制);
    • 0 这是前面数据帧的续帧(一个消息封装成多个帧时);
    • 1 表示这是一个文本帧;
    • 2 表示这是一个二进制( binary )帧;
    • 3~7 保留,未来可以分配给新的非控制( non-control )帧;
    • 8 表示这是一个连接关闭( close )帧;
    • 9 表示这是一个 ping 帧;
    • 10 表示这是一个 pong 帧;
    • 11~15 保留,未来可以分配给新的控制( control )帧;
  • MASK 位,表示 承载数据( payload data )是否做掩码处理,1 表示掩码处理,0 表示不做掩码处理(客户端发的帧必须做掩码处理,主要出于避免网络中间件混淆和安全上的考虑);
  • 数据长度( payload len ),占 7 位,用来表示数据负载的长度(以字节为单位);
    • 该字段小于 126 时,该字段直接表示数据长度,其后的扩展字段为空( 0 字节),可表示 0~125 字节的数据;
    • 当该字段等于 126 时,数据长度由其后的扩展字段表示,这是扩展字段为 2 字节,可表示长度为 126~65535 字节的数据;
    • 当该字段等于 127 时,数据长度由其后的扩展字段表示,这时扩展字段为 8 字节,可表示长度为 到 字节的数据;
  • 扩展数据长度( extended payload len ),占用 0 、2 或 8 字节,由前一个字段决定;
  • 掩码Key( masking key ),数据帧开启掩码处理时( MASK=1 )才有,占用 4 个字节,用于掩码计算;
  • 承载数据( payload data ),即数据帧承载的应用层数据;