计算机网络知识之TCP/IP协议簇
OSI参考模型
OSI的来源
OSI七层模型的划分
各层功能定义
数据链路层又分为2个子层:逻辑链路控制子层(LLC)和媒体访问控制子层(MAC)。
MAC子层处理CSMA/CD算法、数据出错校验、成帧等;LLC子层定义了一些字段使上次协议能共享数据链路层。 在实际使用中,LLC子层并非必需的。
这个没找到合适的例子
<7> 物理层
TCP/IP五层模型
IP协议
什么是IP协议
IP协议是TCP/IP协议族的动力,它为上层协议提供无状态、无连接、不可靠的服务。
无状态是指IP通信双方不同步传输数据的状态信息,因此所有IP数据报的发送、传输和接收都是相互独立、没有上下文关系的。这种服务最大的缺点就是无法处理乱序和重复的IP数据报。面向连接的协议,比如TCP协议,能够自己处理乱序的、重复的报文段,它递交给上层协议的内容绝对是有序的、正确的。无状态服务的优点也很明显:简单、高效。我们无需为保持通信的状态而分配一些内核资源,也无需每次传输数据时都携带状态信息。
无连接是指IP通信双方都不长久地维持对方的任何信息。这样上层协议每次发送数据的时候,都必须明确指定对方的IP地址。
不可靠是指IP协议不能保证IP数据报准确地到达接收端,它只是承诺尽最大努力。很多情况都可以导致IP数据报发送失败。比如,某个中转路由器发现IP数据报在网络上存活地时间太长,那么它将丢弃该报文,并返回一个ICMP错误消息给发送端。因此,使用IP服务地上层协议需要自己实现数据确认、超时重传等机制以达到可靠传输的目的。
IP头部
wireshark抓包实例:
各字段说明:
- 4位版本号指定IP协议的版本。对于IPv4来说,其值是4.其他IPv4的扩展版本(如SIP协议和PIP协议),则具有不同的版本号。
- 4位头部长度标识该IP头部有多少个32bit字(4字节)。因为4位最大能表示15,所以IP头部最长是60字节。
- 8位服务类型包括一个3位的优先权字段,4位的TOS字段和1位的保留字段(必须置0)。4位的TOS字段分别表示:最小延时,最大吞吐量,最高可靠性和最小费用。其中最多有一个能置位1,应用程序应该根据实际需要来设置它。比如像ssh和telnet这样的登陆程序需要的是最小延时服务,而文件传输程序ftp则需要最大吞吐量的服务。
- 16位总长度是指整个IP数据报的长度,以字节为单位,因此IP数据报的最大长度为65535字节。但由于MTU的限制,长度超过MTU的数据报都将被分片传输,所以实际传输的IP数据报的长度都远远没有达到最大值。
- 16位标识唯一地标识主机发送地每一个数据报。其初始值由系统随机生成,没发送一个数据报,其值就加1.该值在数据报分片时被复制到每个分片中,因此同一个数据报地所有分片都具有相同地标识。
- 3位标志字段地第一位保留。第二位表示"禁止分片"。如果设置了这个位,IP模块将不对数据报进行分片。在这种情况下,如果IP数据报长度超过MTU的话,IP模块将丢弃该数据报并返回一个ICMP差错报文。第三位表示“更多分片”。除了数据报的最后一个分片外,其他分片都要把它置1。
- 13位分片偏移是分片相对原始IP数据报开始处(仅指数据部分)的偏移。实际的偏移值是该值左移3位(乘8)后得到的。由于这个原因,除了最后一个IP分片外,每个IP分片的数据部分的长度必须是8的整数倍(这样才能保证后面的IP分片拥有一个合适的偏移量)。
- 8位生存时间(TTL)是数据报到达目的地之前允许经过的路由器跳数。TTL值被发送端设置(常见值位64)。数据报在转发过程中每经过一个路由,该值就被路由器减1。当TTL值减为0时,路由器将丢弃数据报,并向源端发送一个ICMP差错报文。TTL值可以防止数据报陷入路由循环。
- 8位协议用来区分上层协议,/etc/protocols文件定义了所有上层协议对应的protocol字段的数值。其中ICMP是1,TCP是6,UDP是17。
- 16位头部校验和由发送端填充,接收端对其使用CRC算法以检验IP数据报头部在传输过程中是否损坏。
- 32位的源端IP地址和目的端IP地址用来标识数据报的发送端和接收端。一般情况下,这两个地址在整个数据报的传递过程中保持不变,而不论它中间经过多少个中转路由器。
- IPv4最后一个选项字段是可变长的可选信息。这部分最多包含40个字节,因为IP头部最长是60字节(其中还包含前面讨论的20字节的固定部分)。可用的IP选项包括:
1.记录路由,告诉数据报途径的所有路由器都将自己的IP地址填入IP头部的选项部分,这样就可以跟踪数据报的传递路径。
2.时间戳,告诉每个路由器都将数据报被转发的时间填入IP头部的选项部分,这样就可以测量途径路由之间数据报传输时间。
3.松散源路由选择,指定一个路由器IP地址列表,数据报发送过程必须经过其中所有的路由器。
4.严格源路由选择,和松散源路由选择类似,不过数据报只能经过被指定的路由器。
通过wireshark分析ARP协议
什么是地址解析协议
地址解析协议,即ARP(Address Resolution Protocol),是根据IP地址获取物理地址的一个TCP/IP协议。主机发送信息时将包含目标IP地址的ARP请求广播到局域网络上的所有主机,并接收返回消息,以此确定目标的物理地址;收到返回消息后将该IP地址和物理地址存入本机ARP缓存中并保留一定时间,下次请求时直接查询ARP缓存以节约资源。
实现过程
同网段:
在同一局域网内,如果主机A要想通过B的IP地址确定其MAC地址并和B进行数据交互,需要按照ARP协议的”广播请求和单播应答”来确定主机B的MAC地址。
假如A表示我本机地址192.168.1.8,B表示192.168.1.2,实现过程为:
1) A先查看自己的ARP高速缓存表中是否有B主机的MAC地址记录。
用arp -a查看发现确实有:
为了便于测试,我先删除:arp -ad 192.168.1.2 (要管理员权限)
2) 如果A的ARP高速缓存表中有B的MAC地址记录,则直接通过这个MAC地址进行数据的传输。
3) 如果A主机的ARP高速缓存中没有B主机的记录,则会向局域网的所有主机广播一个ARP请求报文,寻找B主机的MAC地址。
现在A的arp缓存没有B的记录,ping 一下B:ping 192.168.1.2;
打开wireshark网络分析器,过滤arp协议:
系统向本网段发出广播,谁有192.168.1.2的mac地址呀?有的话告诉我192.168.1.8。
具体的arp请求报文详情:
字段说明:
Hardware type----网卡类型,以太网(Ethernet)是1。我们常见的网络都是以太网,但这并不意味着只有以太网。
Protocol type----查询中提供的网络地址的类型,IPv4是0x0800。
Harware lenght----网卡地址长度,以太网网卡是6字节。
Protocol lengt----查询中提供的网络地址的的长度,IPv4是4字节。
Opcode----Operation查询包值为1,响应包值为2。
Sender MAC address----发送者的Mac地址。
Sender IP address----发送者的IP地址。
Target MAC address----接收者的Mac地址,指向性查询包是MAC地址表中记录的mac,广播性查询包是00:00:00:00:00:00。(注意区分ARP头和Eth头,指向性查询包Eth头的dst mac是MAC地址表中记录的mac,而广播性查询包是ff:ff:ff:ff:ff:ff)。
Target IP address----要查询mac地址的ip。
4) 当B主机收到A主机广播的ARP请求后,就会直接给A主机回复一个ARP数据包。
5) 当A主机收到B主机发送过来的请求后,将B的MAC地址写入高速缓存中,然后通过该MAC地址,A主机向B主机进行数据的传输。
跨网段:
A与B不在一个网段,A查询自己的路由表,知道如果想和B通信则必须通过gateway 来中转,所以会在与gateway 直连的接口(假定 Ethernet接口)上请求gateway 的MAC地址。 A主机先通过广播一个ARP请求,找到本网络中的一个路由器的MAC地址,然后将数据包直接给路由器。当路由收到数据包后,如果B主机在同网络中的话,这时通过ARP找到B主机,然后把数据包给B主机。如果B主机不和A主机发送数据的路由器在同一网络内的话,则路由器会通过ARP协议找到下一跳的路由器,然后把数据包发送到该路由上,以此类推。
路由协议
路由控制
互联网是由路由器连接的网络组合而成。为了让数据包正确达到目标主机,路由器必须正确的转发,这种向正确的方向转发数据所进行的处理叫做路由控制或路由。
路由器根据路由控制表转发数据包,它根据所接收到数据包中目标主机的IP地址与路由控制表的比较得出下一个应该接收的路由器。因此这个过程中一定要准确,不然有可能数据包无法到达主机。
静态路由与动态路由
静态路由是指事先设置好路由器和主机中并将路由信息固定的一种方法。动态路由是指让路由协议在运行过程中自动的设置路由控制信息的一种方法。各有利弊。
静态路由设置通常是手工操作,因此会给管理者带来很大的负担。一旦某一个发生故障,基本无法自动绕过发生故障的点,只有在手工设置后才能恢复正常。新增加网络要在所有路由器上设置。
使用动态路由情况下,管理员必须设置好路由协议,设定过程复杂度与采用的具体路由协议有关。RIP(路由信息协议)情况下无需太多设置。OSPF(开放式最短路径优先)进行详细路由控制时,设置工作会非常繁琐。新增网络只需要在一个路由器上进行动态路由设置即可。
路由实例:
关于路由协议详细部分暂不讨论。
TCP协议
TCP协议属于传输层,提供可靠地字节流服务。所谓的字节流服务(Byte Stream Service)是指,为了方便传输,将大块数据分割成以报文段(segment)为单位的数据包进行管理。而可靠的传输服务是指,能够把数据准确可靠地传给对方。一言以蔽之,TCP 协议为了更容易传送大数据才把数据分割,而且 TCP 协议能够确认数据最终是否送达到对方。
TCP报文格式
字段说明
16位源端口号:16位的源端口中包含初始化通信的端口。源端口和源IP地址的作用是标识报文的返回地址。
16位目的端口号:16位的目的端口域定义传输的目的。这个端口指明报文接收计算机上的应用程序地址接口。
32位序号:32位的序列号由接收端计算机使用,重组分段的报文成最初形式。当SYN出现,序列码实际上是初始序列码(Initial Sequence Number,ISN),而第一个数据字节是ISN+1。这个序列号(序列码)可用来补偿传输中的不一致。
32位确认序号:32位的序列号由接收端计算机使用,重组分段的报文成最初形式。如果设置了ACK控制位,这个值表示一个准备接收的包的序列码。头部长度(首部长度):由于TCP首部包含一个长度可变的选项和填充部分,所以需要这么一个值来指定这个TCP报文段到底有多长。或者可以这么理解:就是表示TCP报文段中数据部分在整个TCP报文段中的位置。该字段的单位是32位字,即:4个字节。TCP的滑动窗口大小实际上就是socket的接收缓冲区大小的字节数。
保留(6位):6位值域,这些位必须是0。为了将来定义新的用途而保留
URG:指示报文中有紧急数据,应尽快传送(相当于高优先级的数据)。
PSH:为1表示是带有push标志的数据,指示接收方在接收到该报文段以后,应尽快将这个报文段交给应用程序,而不是在缓冲区排队。
RST:TCP连接中出现严重差错(如主机崩溃),必须释放连接,在重新建立连接。
FIN:发送端已完成数据传输,请求释放连接。
SYN:处于TCP连接建立过程。 (Synchronize Sequence Numbers)
ACK:确认序号标志,为1时表示确认号有效,为0表示报文中不含确认信息,忽略确认号字段。
滑动窗口大小:这个字段是接收端用来告知发送端自己还有多少缓冲区可以接受数据。于是发送端可以根据这个接收端的处理能力来发送数据,而不会导致接收端处理不过来。(以此控制发送端发送数据的速率,从而达到流量控制。)窗口大小是一个16bit字段,因而窗口大小最大为65535字节。
16位校验和:16位TCP头。源机器基于数据内容计算一个数值,收信息机要与源机器数值 结果完全一样,从而证明数据的有效性。检验和覆盖了整个的TCP报文段:这是一个强制性的字段,一定是由发送端计算和存储,并由接收端进行验证的。
16位紧急指针:指向后面是优先数据的字节,在URG标志设置了时才有效。如果URG标志没有被设置,紧急域作为填充。加快处理标示为紧急的数据段。
选项和填充部分:TCP报文的字段实现了TCP的功能,标识进程、对字节流拆分组装、差错控制、流量控制、建立和释放连接等。其最大长度可根据TCP首部长度进行推算。TCP首部长度用4位表示,那么选项部分最长为:(2^4-1)*(32/8)-20=40字节。
TCP三次握手
三次握手这个说法我就觉得有问题,正常两个人见面握一次手就行了,谁会连续握三次手?three-way handshake翻译为三步握手更合适。
举个栗子,金正恩和特朗普见面:
1、金正恩像特朗普伸出手,表示自己没有武器,(SYN)
2、特朗普看到后点头微笑(ACK),也伸出自己的手,表示自己也没有武器(SYN)
3、金正恩看到特朗普的诚意后也很感动,最终两只大手握在了一起(ACK)
三个步骤实现了本次握手。
开个玩笑。。。
具体实现过程
所谓三次握手(Three-Way Handshake)即建立TCP连接,就是指建立一个TCP连接时,需要客户端和服务端总共发送3个包以确认连接的建立。在socket编程中,这一过程由客户端执行connect来触发,整个流程如下图所示:
最开始的时候客户端和服务器都是处于CLOSED状态。主动打开连接的为客户端,被动打开连接的是服务器。
1. TCP服务器进程先创建传输控制块TCB,时刻准备接受客户进程的连接请求,此时服务器就进入了LISTEN(监听)状态;
2. TCP客户进程也是先创建传输控制块TCB,然后向服务器发出连接请求报文,这时报文首部中的同部位SYN=1,同时选择一个初始序列号 seq=x ,此时,TCP客户端进程进入了 SYN-SENT(同步已发送状态)状态。TCP规定,SYN报文段(SYN=1的报文段)不能携带数据,但需要消耗掉一个序号。
3. TCP服务器收到请求报文后,如果同意连接,则发出确认报文。确认报文中应该 ACK=1,SYN=1,确认号是ack=x+1,同时也要为自己初始化一个序列号 seq=y,此时,TCP服务器进程进入了SYN-RCVD(同步收到)状态。这个报文也不能携带数据,但是同样要消耗一个序号。
4. TCP客户进程收到确认后,还要向服务器给出确认。确认报文的ACK=1,ack=y+1,自己的序列号seq=x+1,此时,TCP连接建立,客户端进入ESTABLISHED(已建立连接)状态。TCP规定,ACK报文段可以携带数据,但是如果不携带数据则不消耗序号。也就是说,如果第三次握手的报文没有携带数据,那么后面一次发送数据的报文的seq仍然是x+1,ack仍是y+1.
5. 当服务器收到客户端的确认后也进入ESTABLISHED状态,此后双方就可以开始通信了。
wireshark实例分析TCP三次握手过程
打开wireshark,追踪某个tcp流,如下:
前五个请求中有两个是超时重传的,忽略。第一个请求就是发起连接请求的SYN包。后面的SYN,ACK就是服务端发过来的确认包。
客户端再给一个ACK,连接建立。
为何需要三次握手?
通俗一点,a、b双方要通信,首先得保证双方的接收和发送功能没问题!其实很简单, 1.a->b, 这个时候没有任何状态, 2. b->a, b给a发东西, 说明收到了a的东西, 证明了a的发送能力是没问题的,同时证明了b的接收能力也是没有问题的。 如果到这里就结束了, 那么a的接收能力和b的发送能力就没办法保证了。如果再加上3. a->b , 证明了a收到了b的发送, 那么b的发送能力也是好的, a的接收能力也是好的。这样a和b的接收发送的能力都是好的, 就没必要再次证明了。三次握手可以搞定。
谢希仁版《计算机网络》中说为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。”
三次握手的原则设计还可以防止旧复用链接的初始化所导致的问题,为了解决此问题,我们设计了reset
这个特别的控制信号来处理。如果接收中的 TCP 在一个未同步状态如 SYN-SENT, SYN-RECEIVED
,它会返回 reset
给对方。如果 TCP 是同步状态中如(ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT, CLOSING, LAST-ACK, TIME-WAIT)
,他会终止此连接并通知用户。
看起来有点绕,我们举个例看看:
TCP A TCP B
1. CLOSED LISTEN
2. SYN-SENT --> <SEQ=100><CTL=SYN> ...
3. (duplicate) ... <SEQ=90><CTL=SYN> --> SYN-RECEIVED
4. SYN-SENT <-- <SEQ=300><ACK=91><CTL=SYN,ACK> <-- SYN-RECEIVED
5. SYN-SENT --> <SEQ=91><CTL=RST> --> LISTEN
6. ... <SEQ=100><CTL=SYN> --> SYN-RECEIVED
7. SYN-SENT <-- <SEQ=400><ACK=101><CTL=SYN,ACK> <-- SYN-RECEIVED
8. ESTABLISHED --> <SEQ=101><ACK=401><CTL=ACK> --> ESTABLISHED
Recovery from Old Duplicate SYN
这是 复用连接时,旧在途包发往新连接中的例子。
- 3中,一个旧的重复的
SYN
到达B
。 - 4中,
B
分别不出是否旧的,照样子正常回包。 - 5中,
A
检测到B
返回的ACK
不正确,所以返回RST(reset)
- 6中,
B
接收到RST(reset)
信号,于是变成LISTEN
状态。 - 7中,新连接正常的
SYN
终于到达了,三次握手正常进行。
这种是简化的情况,但是可以看出 TCP 是如何处理复用旧链接的包到达的。
个人认为,TCP连接的三次握手的核心是交换通信双方数据原点的序列号ISN(Initial Sequence Number)。有了这个ISN,就知道哪些seq数据段是非法的,接收到所有的合法的数据段后就可以排序重组。
对于三次握手中的丢包问题:
1、A发给B的SYN中途丢包,则A会周期性超时重传,直到收到B的确认;
2、B发给A的SYN+ACK中途丢包,则B会周期性超时重传,直到收到A的确认;
3、A发给B的ACK包中途丢包,此时A单方面认为TCP是Established状态,而B显然认为TCP为Active状态:
- 假如此时双方都没有数据发送,则回到第二种情况,B超时重传;
- 假如此时A有数据发送,B收到A的数据包,因为该包含有ACK,自然会切换为Established状态,并接受A的数据。
TCP如何保证可靠传输?
- 应用数据被分割成TCP认为最合适发送的数据块。
- TCP给发送的每一个包进行编号,接收方对数据包进行排序,把有序数据传送给应用层。
- 校验和:TCP将保持它首部和数据的检验和。这是一个端到端的校验和,目的是检测数据在传输过程中的任何变化。如果收到端的检验和有差错,TCP将丢弃这个报文段和不确认接收此报文段。
- TCP的接收端会丢弃重复的数据。
- 流量控制:TCP连接的每一方都有固定大小的缓冲空间,TCP的接收端只允许发送端发送接收端缓冲区能接纳的数据。当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。TCP使用的流量控制协议是可变大小的滑动窗口协议。(TCP利用滑动窗口实现流量控制)
- 拥塞控制:当网络拥塞时,减少数据的发送。
- ARQ(自动重传请求)协议:也是为了实现可靠传输的,它的基本原理就是 每发完一个分组就停止发送,等待对方确认,在收到确认后再发下一个分组。
- 超时重传:当TCP发出一个报文段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重新发送这个报文段。
ARQ协议
自动重传请求(Automatic Repeat-reQuest,ARQ)是OSI模型中数据链路层和传输层的错误纠正协议之一。它通过使用确认和超时这两个机制,在不可靠服务的基础上实现可靠的信息传输。ARQ包括停止等待ARQ协议和连续ARQ协议。
停止等待ARQ协议:
基本原理:每发完一个分组就停止发送,等待对方确认(回复ACK)。如果过了一段时间(超时时间后),还是没有收到ACK确认,说明没有发送成功,需要重新发送,直到收到确认后再发下一个分组。
在停止等待协议中,若接收方收到重复分组,就丢弃该分组,但同时还要发送确认。
优点:简单
缺点:信道利用率低,等待时间长
连续ARQ协议:
连续ARQ协议可提高信道利用率。发送方维持一个发送窗口,凡位于发送窗口内的分组可以连续发送出去,而不需要等待对方确认,对按序到达的最后一个分组发送确认,表明到这个分组为止的所有分组都已经正确收到了。比如发送6个分组,若第一个分组没到达,而其他都到了,则此时仍然不会收到接收方的任何确认信息。
优点:信道利用率高,容易实现,即使确认丢失,也不必重传。
缺点:不能向发送方反映出接收方已经正确收到的所有分组的信息。比如:发送方发送了6个分组,中间第个条丢失(3号),这时接收方只能对前两个发送确认,发送方无法知道后四个分组的下落,只能把后四个都再传一遍。这也叫Go-Back-N(回退N),表示需要退回来重传已经发送过的N个消息。
关于SYN攻击
在三次握手过程中,Server发送SYN-ACK之后,收到Client的ACK之前的TCP连接称为半连接(half-open connect),此时Server处于SYN_RCVD状态,当收到ACK后,Server转入ESTABLISHED状态。SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server回复确认包,并等待Client的确认,由于源地址是不存在的,因此,Server需要不断重发直至超时,这些伪造的SYN包将占用未连接队列,导致正常的SYN请求因为队列满员而被丢弃,从而引起网络堵塞甚至系统瘫痪。SYN攻击是一种典型的DOS攻击(Denial of Service),检测SYN攻击的方式非常简单,即当Server上有大量半连接状态且源IP地址是随机的,则可以断定遭到SYN攻击了,使用如下命令可以让之现行:#netstat -nap | grep SYN_RECV
关于TCP反射攻击
黑客伪造目的服务器IP向公网的TCP服务器发起连接请求(SYN),以使得被攻击服务器收到大量SYN/ACK报文,最终造成拒绝服务。
详情请看此文:
https://www.freebuf.com/articles/database/202401.html
http://blog.nsfocus.net/tcp-syn/
TCP四次挥手
所谓四次挥手(Four-Way Wavehand)即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。在socket编程中,这一过程由客户端或服务端任一方执行close来触发,整个流程如下图所示:
数据传输完毕后,双方都可释放连接。最开始的时候,客户端和服务器都是处于ESTABLISHED状态,然后客户端主动关闭,服务器被动关闭。
1. 客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。
2. 服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
3. 客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
4. 服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
5. 客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。
wireshark实例:
很显然,第二次挥手和第三次挥手的确认号和序列号是一样的,这表示两次挥手之间服务端没有向客户端传任何数据,所以两次挥手是可以合并在一起的,即三次挥手。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
疑问??????
请求lemfix.com的主页,整个过程的结束部分如下,服务端返回主页结束后主动关闭了多个与客户端连接的端口,但是关闭时只发了个【FIN,ACK】请求,然后客户端回复了个ACK就完事了,这不成了两次挥手了吗?不明白!!!!!
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
TIME_WAIT:主动要求关闭的机器表示收到了对方的FIN报文,并发送出了ACK报文,进入TIME_WAIT状态,等2MSL后即可进入到CLOSED状态。如果FIN_WAIT_1状态下,同时收到待FIN标识和ACK标识的报文时,可以直接进入TIME_WAIT状态,而无需经过FIN_WAIT_2状态。
CLOSE_WAIT:被动关闭的机器收到对方请求关闭连接的FIN报文,在第一次ACK应答后,马上进入CLOSE_WAIT状态。这种状态其实标识在等待关闭,并且通知应用发送剩余数据,处理现场信息,关闭相关资源。
为什么建立连接是三次握手,而关闭连接却是四次挥手呢?
这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送。
为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
原因有二:
一、保证TCP协议的全双工连接能够可靠关闭
二、保证这次连接的重复数据段从网络中消失
先说第一点,如果Client直接CLOSED了,那么由于IP协议的不可靠性或者是其它网络原因,导致Server没有收到Client最后回复的ACK。那么Server就会在超时之后继续发送FIN,此时由于Client已经CLOSED了,就找不到与重发的FIN对应的连接,最后Server就会收到RST而不是ACK,Server就会以为是连接错误把问题报告给高层。这样的情况虽然不会造成数据丢失,但是却导致TCP协议不符合可靠连接的要求。所以,Client不是直接进入CLOSED,而是要保持TIME_WAIT,当再次收到FIN的时候,能够保证对方收到ACK,最后正确的关闭连接。
再说第二点,如果Client直接CLOSED,然后又再向Server发起一个新连接,我们不能保证这个新连接与刚关闭的连接的端口号是不同的。也就是说有可能新连接和老连接的端口号是相同的。一般来说不会发生什么问题,但是还是有特殊情况出现:假设新连接和已经关闭的老连接端口号是一样的,如果前一次连接的某些数据仍然滞留在网络中,这些延迟数据在建立新连接之后才到达Server,由于新连接和老连接的端口号是一样的,又因为TCP协议判断不同连接的依据是socket pair,于是,TCP协议就认为那个延迟的数据是属于新连接的,这样就和真正的新连接的数据包发生混淆了。所以TCP连接还要在TIME_WAIT状态等待2倍MSL,这样可以保证本次连接的所有数据都从网络中消失。
关于滑动窗口
TCP滑动窗口技术通过动态改变窗口大小来调节两台主机间数据传输。每个TCP/IP主机支持全双工数据传输,因此TCP有两个滑动窗口:一个用于接收数据,另一个用于发送数据。TCP使用肯定确认技术,其确认号指的是下一个所期待的字节。 假定发送方设备以每一次三个数据包的方式发送数据,也就是说,窗口大小为3。发送方发送序列号为1、2、3的三个数据包,接收方设备成功接收数据包,用序列号4确认。发送方设备收到确认,继续以窗口大小3发送数据。当接收方设备要求降低或者增大网络流量时,可以对窗口大小进行减小或者增加,本例降低窗口大小为2,每一次发送两个数据包。当接收方设备要求窗口大小为0,表明接收方已经接收了全部数据,或者接收方应用程序没有时间读取数据,要求暂停发送。发送方接收到携带窗口号为0的确认,停止这一方向的数据传输。当链路变好了或者变差了这个窗口还会发生变话,并不是第一次协商好了以后就永远不变了。
滑动窗口协议,是TCP使用的一种流量控制方法。该协议允许发送方在停止并等待确认前可以连续发送多个分组。由于发送方不必每发一个分组就停下来等待确认,因此该协议可以加速数据的传输。 只有在接收窗口向前滑动时(与此同时也发送了确认),发送窗口才有可能向前滑动。收发两端的窗口按照以上规律不断地向前滑动,因此这种协议又称为滑动窗口协议。
拥塞控制
cwnd:发送端窗口( congestion window )
rwnd:接收端窗口(receiver window)
发送端主动控制cwnd,有慢启动(从cwnd初始为1开始启动,指数启动),拥塞避免(到达ssthresh后,为了避免拥塞开始尝试线性增长),快重传(接收方每收到一个报文段都要回复一个当前最大连续位置的确认,发送方只要一连收到三个重复确认就知道接收方丢包了,快速重传丢包的报文,并TCP马上把拥塞窗口 cwnd 减小到1),快恢复(直接从ssthresh线性增长)。
如果网络上的延时突然增加,那么TCP对这个事作出的应对只有重传数据,但是重传会导致网络的负担更重,于是会导致更大的延迟以及更多的丢包,于是这个情况就会进入恶性循环被不断地放大。试想一下,如果一个网络内有成千上万的TCP连接都这么行事,那么马上就会形成“网络风暴”,TCP这个协议就会拖垮整个网络。所以TCP不能忽略网络上发生的事情,而无脑地一个劲地重发数据,对网络造成更大的伤害。对此TCP的设计理念是:TCP不是一个自私的协议,当拥塞发生的时候,要做自我牺牲。就像交通阻塞一样,每个车都应该把路让出来,而不要再去抢路了。
差错控制
TCP使用差错控制来提供可靠性。差错控制包括以下的一些机制:检测和重传受到损伤的报文段、重传丢失的报文段、保存失序到达的报文段直至缺失的报文到期,以及检测和丢弃重复的报文段。TCP通过三个简单的工具来完成其差错控制:检验和、确认以及超时。
UDP协议
简介
UDP数据报
UDP数据报分为首部和用户数据部分,整个UDP数据报作为IP数据报的数据部分封装在IP数据报中,UDP数据报文结构如图所示:
字段说明:
UDP首部有8个字节,由4个字段构成,每个字段都是两个字节:
1、源目端口号
UDP协议使用端口号为不同的应用保留其各自的数据传输通道。UDP和TCP协议正是采用这一机制实现对同一时刻内多项应用同时发送和接收数据的支持。数据发送一方(可以是客户端或服务器端)将UDP数据包通过源端口发送出去,而数据接收一方则通过目标端口接收数据。有的网络应用只能使用预先为其预留或注册的静态端口;而另外一些网络应用则可以使用未被注册的动态端口。因为UDP报头使用两个字节存放端口号,所以端口号的有效范围是从0到65535。一般来说,大于49151的端口号都代表动态端口。UDP端口号指定有两种方式:由管理机构指定端口和动态绑定的方式。
2、长度
数据报的长度是指包括报头和数据部分在内的总字节数。因为报头的长度是固定的,所以该域主要被用来计算可变长度的数据部分(又称为数据负载)。数据报的最大长度根据操作环境的不同而各异。从理论上说,包含报头在内的数据报的最大长度为65535字节。不过,一些实际应用往往会限制数据报的大小,有时会降低到8192字节。
3、校验和
wireshark实例
这里dns使用的是udp协议,四个字段一览无余。
UDP的优势
UDP提供不可靠服务,具有TCP所没有的优势:
1. UDP无连接,时间上不存在建立连接需要的时延。空间上,TCP需要在端系统中维护连接状态,需要一定的开销。此连接装入包括接收和发送缓存,拥塞控制参数和序号与确认号的参数。UCP不维护连接状态,也不跟踪这些参数,开销小。空间和时间上都具有优势。
举个例子:
2. DNS如果运行在TCP之上而不是UDP,那么DNS的速度将会慢很多。
HTTP使用TCP而不是UDP,是因为对于基于文本数据的Web网页来说,可靠性很重要。
同一种专用应用服务器在支持UDP时,一定能支持更多的活动客户机。
3. 分组首部开销小,TCP首部20字节,UDP首部8字节。
4. UDP没有拥塞控制,应用层能够更好的控制要发送的数据和发送时间,网络中的拥塞控制也不会影响主机的发送速率。某些实时应用要求以稳定的速度发送,能容 忍一些数据的丢失,但是不能允许有较大的时延(比如实时视频,直播等)
5. UDP提供尽最大努力的交付,不保证可靠交付。所有维护传输可靠性的工作需要用户在应用层来完成。没有TCP的确认机制、重传机制。如果因为网络原因没有传送到对端,UDP也不会给应用层返回错误信息
6. UDP是面向报文的,对应用层交下来的报文,添加首部后直接乡下交付为IP层,既不合并,也不拆分,保留这些报文的边界。对IP层交上来UDP用户数据报,在去除首部后就原封不动地交付给上层应用进程,报文不可分割,是UDP数据报处理的最小单位。
正是因为这样,UDP显得不够灵活,不能控制读写数据的次数和数量。比如我们要发送100个字节的报文,我们调用一次sendto函数就会发送100字节,对端也需要用recvfrom函数一次性接收100字节,不能使用循环每次获取10个字节,获取十次这样的做法。
7. UDP常用一次性传输比较少量数据的网络应用,如DNS,SNMP等,因为对于这些应用,若是采用TCP,为连接的创建,维护和拆除带来不小的开销。UDP也常用于多媒体应用(如IP电话,实时视频会议,流媒体等)数据的可靠传输对他们而言并不重要,TCP的拥塞控制会使他们有较大的延迟,也是不可容忍的
HTTP协议
HTTP简介
HTTP(HyperText Transfer Protocol,超文本传输协议)
HTTP是一个应用层协议,虽然在2015年已推出HTTP/2版本,并被主要的web浏览器和web服务器支持。但目前使用最广泛的还是HTTP/1.1版本。
它的主要特点可概括如下:
- 支持客户/服务器模式。
- 简单快速:客户向服务器请求服务时,只需传送请求方法和路径。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
- 灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。
- 无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
- 无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。为了解决这个问题, Web程序引入了Cookie机制来维护状态。
HTTP请求报文结构
HTTP请求实例
GET /uploads/user/avatar/1164/b0cea8.jpg!md HTTP/1.1 --------------请求行
Host: lemfix.com
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36
Accept: image/webp,image/apng,image/*,*/*;q=0.8
Referer: http://lemfix.com/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,la;q=0.7
Cookie: _ga=GA1.2.1588732938.1575559305; _gid=GA1.2.737178753.1576136374; user_id=eyJfcmFpbHMiOnsibWVzc2FnZSI6ImJuVnNiQT09IiwiZXhwIjpudWxsLCJwdXIiOiJjb29raWUudXNlcl9pZCJ9fQ%3D%3D--be7000dd69b3502d78ff20455470adaf2ceb5eac;
以上实例分为两部分,请求行和请求头部。
请求行:请求方法+URL+HTTP版本信息
HTTP请求方法
HTTP请求之GET和POST的区别
(1)提交形式:
GET提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连,如EditPosts.aspx?name=test1&id=123456。POST方法是把提交的数据放在HTTP包的Body中。
(2)传输数据的大小:
HTTP协议本身没有对传输的数据大小进行限制,HTTP协议规范也没有对URL长度进行限制。 而在实际开发中存在的限制主要有:
GET:特定浏览器和服务器对URL长度有限制,例如IE对URL长度的限制是2083字节。对于其他浏览器,如Netscape,FireFox等,理论上没有长度限制,其限制取决于操作系统的支持。因此对于GET提交时,传输数据就会受到URL长度的限制。
POST:由于不是通过URL传值,理论上数据不受限制。但实际各个WEB服务器会规定对post提交数据大小进行限制,Apache,IIS6都有各自的配置。
(3)安全性:
POST的安全性要比GET的安全性高,具有真正的Security的含义。通过GET提交数据,用户名和密码将明文出现在URL上,因为登录页面有可能被浏览器缓存,其他用户浏览历史记录就可以拿到账号和密码。
HTTP请求头字段详细说明
HTTP响应报文格式
响应报文结构与请求报文结构唯一的区别在于第一行中用状态信息代替了请求信息。状态行(status line)通过提供一个状态码来说明所请求的资源情况。
结构图示:
HTTP响应实例
HTTP/1.1 200 OK 状态行
Server: nginx/1.16.1
Date: Fri, 13 Dec 2019 01:57:57 GMT
Content-Type: image/jpeg
Content-Length: 4100
Connection: keep-alive
Last-Modified: Thu, 18 Apr 2019 07:16:03 GMT 响应头
ETag: W/"5cb82433-aa4dd"
Expires: Fri, 20 Dec 2019 01:57:57 GMT
Cache-Control: max-age=604800
Cache-Control: public
X-Pownered: nginx_image_filter
X-Cache-Status: MISS
空行
......JFIF.....`.`.....;CREATOR: gd-jpeg v1.0 (using IJG JPEG v80), quality = 95 响应体
...C..................................... ... ......
HTTP响应头字段说明
HTTP响应状态码大全
1xx: http状态返回代码 1xx(临时响应)
100 (继续) 请求者应当继续提出请求。 服务器返回此代码表示已收到请求的第一部分,正在等待其余部分。
101 (切换协议) 请求者已要求服务器切换协议,服务器已确认并准备切换。
2xx: 成功,操作被成功接收并处理
200 (成功) 服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。
201 (已创建) 请求成功并且服务器创建了新的资源。
202 (已接受) 服务器已接受请求,但尚未处理。
203 (非授权信息) 服务器已成功处理了请求,但返回的信息可能来自另一来源。
204 (无内容) 服务器成功处理了请求,但没有返回任何内容。
205 (重置内容) 服务器成功处理了请求,但没有返回任何内容。
206 (部分内容) 服务器成功处理了部分 GET 请求。
3xx: 重定向,需要进一步的操作以完成请求
300 (多种选择) 针对请求,服务器可执行多种操作。 服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择。
301 (永久移动) 请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。
302 (临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
303 (查看其他位置) 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。
305 (使用代理) 请求者只能使用代理访问请求的网页。 如果服务器返回此响应,还表示请求者应使用代理。
307 (临时重定向) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
401 (未授权) 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。
403 (禁止) 服务器拒绝请求。
404 (未找到) 服务器找不到请求的网页。
405 (方法禁用) 禁用请求中指定的方法。
406 (不接受) 无法使用请求的内容特性响应请求的网页。
407 (需要代理授权) 此状态代码与 401(未授权)类似,但指定请求者应当授权使用代理。
408 (请求超时) 服务器等候请求时发生超时。
409 (冲突) 服务器在完成请求时发生冲突。 服务器必须在响应中包含有关冲突的信息。
410 (已删除) 如果请求的资源已永久删除,服务器就会返回此响应。
411 (需要有效长度) 服务器不接受不含有效内容长度标头字段的请求。
412 (未满足前提条件) 服务器未满足请求者在请求中设置的其中一个前提条件。
413 (请求实体过大) 服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。
414 (请求的 URI 过长) 请求的 URI(通常为网址)过长,服务器无法处理。
415 (不支持的媒体类型) 请求的格式不受请求页面的支持。
416 (请求范围不符合要求) 如果页面无法提供请求的范围,则服务器会返回此状态代码。
417 (未满足期望值) 服务器未满足"期望"请求标头字段的要求。
501 (尚未实施) 服务器不具备完成请求的功能。 例如,服务器无法识别请求方法时可能会返回此代码。
502 (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。
503 (服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。
504 (网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求。
505 (HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。
Session和Cookie
说到HTTP,就不得不提Session和Cookie。但严格来说,Session和Cookie并不是http协议的一部分。由于HTTP协议设计原则是无状态的,但是近年来出现了种种需求,其中cookie的作用就是为了解决HTTP协议无状态的缺陷所作出的努力。后来出现的session机制则是又一种在客户端与服务器之间保持状态的解决方案。具体来说cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案。同时我们也看到,由于采用服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制可能需要借助于cookie机制来达到保存标识的目的,但实际上它还有其他选择。Session是可以存储针对于某一个用户的浏览器以及通过其当前窗口打开的任何窗口具有针对性的用户信息存储机制。
通常大家认为,只要关闭浏览器,session就消失,其实这是错误的理解。对session来说也是一样的,除非程序通知服务器删除一个session,否则服务器会一直保留。由于关闭浏览器不会导致session被删除,迫使服务器为seesion设置了一个失效时间,当距离客户端上一次使用session的时间超过这个失效时间时,服务器就可以认为客户端已经停止了活动,才会把session删除以节省存储空间。
(1)第一次访问某个web站点资源时,客户端提交没有带SessionID的请求(请求报文头没有Cookie头域信息)。而web服务器会检查是否有SessionID过来,没有则创建SessionID,并根据web程序自身定义在请求哪个资源时添加属于当前会话的信息(也可为空),这个信息列表以SessionID作为标识。然后将SessionID返回给客户端(通过响应报文头的Set-Cookie头域)。
(2)客户端再次访问同个web站点时,提交带有SessionID的请求(通过Cookie头域存储SessionID)。由服务端判断session是否失效,如果未失效,可查询属于当前会话的信息列表。如果失效,则创建新的session(产生新的SessionID),而原先的session(包含session带的信息列表)则丢失,无法访问。
HTTPS协议
到现在为止,我们已了解到 HTTP 具有相当优秀和方便的一面,然而 HTTP 并非只有好的一面,事物皆具两面性,它也是有不足之处的。
HTTP的三大缺点
1、通信使用明文(不加密),内容可能会被窃听:
由于 HTTP 本身不具备加密的功能,所以也无法做到对通信整体(使用 HTTP 协议通信的请求和响应的内容)进行加密。即,HTTP 报文使用明文(指未经过加密的报文)方式发送。
所谓互联网,是由能连通到全世界的网络组成的。无论世界哪个角落的服务器在和客户端通信时,在此通信线路上的某些网络设备 、光缆、计算机等都不可能是个人的私有物,所以不排除某个环节中会遭到恶意窥视行为。
即使已经过加密处制理的通信,也会被窥视到通信内容,这点和未加密的通信是相同的。只是说如果通信经过加密,就有可能让人无法破解报文信息的含义,但加密处理后的报文信息本身还是会被看到的。
2、不验证通信方的身份, 因此有可能遭遇伪装:
HTTP 协议中的请求和响应不会对通信方进行确认。也就是说存在“服务器是否就是发送请求中 URI 真正指定的主机,返回的响应是否真的返回到实际提出请求的客户端”等类似问题。
在 HTTP 协议通信时,由于不存在确认通信方的处理步骤,任何人都可以发起请求。另外,服务器只要接收到请求,不管对方是谁都会返回一个响应(但也仅限于发送端的 IP 地址和端口号没有被 Web 服务器设定限制访问的前提下)。
HTTP 协议的实现本身非常简单,不论是谁发送过来的请求都会返回响应,因此不确认通信方,会存在以下各种隐患:
1、无法确定请求发送至目标的 Web 服务器是否是按真实意图返回响应的那台服务器。有可能是已伪装的 Web 服务器。
2、无法确定响应返回到的客户端是否是按真实意图接收响应的那个客户端。有可能是已伪装的客户端。
3、无法确定正在通信的对方是否具备访问权限。因为某些Web 服务器上保存着重要的信息, 只想发给特定用户通信的权限。
4、即使是无意义的请求也会照单全收。无法阻止海量请求下的DoS 攻击( Denial of Service, 拒绝服务攻击) 。
3、无法证明报文的完整性, 所以有可能已遭篡改:
所谓完整性是指信息的准确度。若无法证明其完整性,通常也就意味着无法判断信息是否准确。
由于 HTTP 协议无法证明通信的报文完整性,因此,在请求或响应送出之后直到对方接收之前的这段时间内,即使请求或响应的内容遭到篡改,也没有办法获悉。换句话说,没有任何办法确认,发出的请求 响应和接收到的请求 响应是前后相同的。
另外,客户端持有证书即可完成个人身份的确认,也可用于对 Web 网站的认证环节。
HTTPS简介
HTTP+ 通信加密 + 证书认证 + 完整性保护 = HTTPS
HTTP 加上加密处理和认证以及完整性保护后即是 HTTPS。
如果在 HTTP 协议通信过程中使用未经加密的明文,比如在 Web 页面中输入信用卡号,如果这条通信线路遭到窃听,那么信用卡号就暴露了。
另外,对于 HTTP 来说,服务器也好,客户端也好,都是没有办法确认通信方的。因为很有可能并不是和原本预想的通信方在实际通信。并且还需要考虑到接收到的报文在通信途中已经遭到篡改这一可能性。
通常,HTTP 直接和 TCP 通信。当使用 SSL 时,则演变成先和 SSL 通信,再由 SSL和 TCP 通信了。简言之,所谓 HTTPS,其实就是身披 SSL 协议这层外壳的HTTP。
加密方式
共享密钥加密:
加密和解密同用一个密钥的方式称为共享密钥加密(Common key cryptosystem),也被叫做对称密钥加密。
公开秘钥加密:
公开密钥加密使用一对非对称的密钥。一把叫做私有密钥(private key),另一把叫做公开密钥(public key)。顾名思义,私有密钥不能让其他任何人知道,而公开密钥则可以随意发布,任何人都可以获得。公开密钥和私有密钥是配对的一套密钥。
使用公开密钥加密方式,发送密文的一方使用对方的公开密钥进行加密处理,对方收到被加密的信息后,再使用自己的私有密钥进行解密。利用这种方式,不需要发送用来解密的私有密钥,也不必担心密钥被攻击者窃听而盗走。
另外,要想根据密文和公开密钥,恢复到信息原文是异常困难的,因为解密过程就是在对离散对数进行求值,这并非轻而易举就能办到。退一步讲,如果能对一个非常大的整数做到快速地因式分解,那么密码破解还是存在希望的。但就目前的技术来看是不太现实的。
HTTPS混合加密机制
为了解决上述问题,可以使用由数字证书认证机构(CA,Certificate Authority)和其相关机关颁发的公开密钥证书。
数字证书认证机构处于客户端与服务器双方都可信赖的第三方机构的立场上。威瑞信(VeriSign)就是其中一家非常有名的数字证书认证机构。
首先,服务器的运营人员向数字证书认证机构提出公开密钥的申请。数字证书认证机构在判明提出申请者的身份之后,会对已申请的公开密钥做数字签名,然后分配这个已签名的公开密钥,并将该公开密钥放入公钥证书后绑定在一起。
服务器会将这份由数字证书认证机构颁发的公钥证书发送给客户端,以进行公开密钥加密方式通信。公钥证书也可叫做数字证书或直接称为证书。接到证书的客户端可使用数字证书认证机构的公开密钥,对那张证书上的数字签名进行验证,一旦验证通过,客户端便可明确两件事:一,认证服务器的公开密钥的是真实有效的数字证书认证机构。二,服务器的公开密钥是值得信赖的。
此处数字证书认证机构的公开密钥必须安全地转交给客户端。使用通信方式时,如何安全转交是一件很困难的事,因此,多数浏览器开发商发布版本时,会事先在内部植入常用认证机构的公开密钥。
HTTPS 通信步骤
步骤 1: 客户端通过发送 Client Hello 报文开始 SSL 通信。报文中包含客户端支持的 SSL 的指定版本、加密组件(Cipher Suite)列表(所使用的加密算法及密钥长度等)。
步骤 2: 服务器可进行 SSL 通信时,会以 Server Hello 报文作为应答。和客户端一样,在报文中包含 SSL 版本以及加密组件。服务器的加密组件内容是从接收到的客户端加密组件内筛选出来的。
步骤 3: 之后服务器发送 Certificate 报文。报文中包含公开密钥证书。
步骤 4: 最后服务器发送 Server Hello Done 报文通知客户端,最初阶段的SSL握手协商部分结束。
步骤 5: SSL 第一次握手结束之后,客户端以 Client Key Exchange 报文作为回应。报文中包含通信加密中使用的一种被称为 Pre-master secret 的随机密码串。该报文已用步骤 3 中的公开密钥进行加密。
步骤 6: 接着客户端继续发送 Change Cipher Spec 报文。该报文会提示服务器,在此报文之后的通信会采用 Pre-master secret 密钥加密。
步骤 7: 客户端发送 Finished 报文。该报文包含连接至今全部报文的整体校验值。这次握手协商是否能够成功,要以服务器是否能够正确解密该报文作为判定标准。
步骤 8: 服务器同样发送 Change Cipher Spec 报文。
步骤 9: 服务器同样发送 Finished 报文。
步骤 10: 服务器和客户端的 Finished 报文交换完毕之后,SSL 连接就算建立完成。当然,通信会受到 SSL 的保护。从此处开始进行应用层协议的通信,即发送 HTTP请求。
步骤 11: 应用层协议通信,即发送 HTTP 响应。
步骤 12: 最后由客户端断开连接。断开连接时,发送 close_notify 报文。上图做了一些省略,这步之后再发送 TCP FIN 报文来关闭与 TCP 的通信。
wireshark实例分析握手过程
client hello:
server hello:
HTTPS制约因素
HTTPS通信效率
为什么不一直使用 HTTPS
既然 HTTPS 那么安全可靠,那为何所有的 Web 网站不一直使用 HTTPS?
其中一个原因是,因为与纯文本通信相比,加密通信会消耗更多的 CPU 及内存资源。如果每次通信都加密,会消耗相当多的资源,平摊到一台计算机上时,能够处理的请求数量必定也会随之减少。
因此,如果是非敏感信息则使用 HTTP 通信,只有在包含个人信息等敏感数据时,才利用 HTTPS 加密通信。
特别是每当那些访问量较多的 Web 网站在进行加密处理时,它们所承担着的负载不容小觑。在进行加密处理时,并非对所有内容都进行加密处理,而是仅在那些需要信息隐藏时才会加密,以节约资源。除此之外,想要节约购买证书的开销也是原因之一。