问大家,为什么要有TCP/Ip网络模型?
对于同一台设备上的进程通信,有很多种方式,比如有管道、消息队列、共享内存、信号等方式,对于不同设备上的进程通信,就需要有网络通信,而设备是多样性的,所以要兼容多种多样的设备,就写上出了一套通用的网络协议。
这个网络协议是分层的,每一层都有各自的作用和指责。
应用层
最上层的,也是我们能直接接触到的就是应用层,我们电脑或手机使用的应用软件都是在应用层实现。那么当两个不同设备的应用需要通信的时候,应用就把应用数据传给下一层,也就是传输层。
所以,应用层只需要专注于为用户提供应用功能,比如HTTP、FTP、Telnet、DNS、SMTP等。应用测过是不用去关心数据是如何传输的,就类似于,我们寄快递的时候,只需要把包裹交给快递员,由他负责运输快递,我们不需要关心快递是如何被运输的。
而且应用层是工作在操作系统的用户态,传输层及以下则工作在内核态。
传输层
应用层的数据包会传给传输层,传输层是为应用层提供网络支持的。
在传输层会有两个传输协议,分别是TCP和UDP。
TCP的全称叫传输控制协议(Transmission Control Protocol),大部分应用使用的正式TCP传输层协议,比如HTTP应用层协议。TCP相比UDP多了很多特性,比如流量控制、超时重传、拥塞控制等,这些都是为了保证数据包能可靠的传输给对方。
UDP相对来说就很简单,简单到只负责发送数据包,不保证数据包是否能抵达对方,但它实时性相对更好,传输效率也高。当然,UDP也可以实现可靠传输,把TCP的特性在应用层上实现就可以,不过要实现一个商用的可靠UDP传输协议,也不是一件简单的事情。
应用需要传输的数据可能会非常大,如果直接传输就不好控制,因此当传输层的数据包大小超过MSS(TCP最大报文长度),就要将数据包分快,这样即使中途有一个分块丢失或损坏了,只需要重新发送这一分块,而不用重新发送整个数据包。在TCP协议中,我们把每个粉快成为一个TCP段(TCP Segment)。
当设备作为接收方时,传输层则要负责把数据包传给应用,但是一台设备上可能会有很多应用在接收或传输数据,因此需要用一个编号将应用区分开来,这个编号就是端口。
比如80端口通常时web服务器用的,22端口通常是远程登录服务器用的。而对于浏览器(客户端)中的每个标签栏都是一个独立的进程,操作系统会为这些进程分配临时的端口号。
由于传输层的报文中会携带端口号,因此接收方可以识别出该报文是发送给哪个应用。
网络层
传输层可能大家刚接触的时候,会认为它负责将数据从一个设备传输到另一个设备,事实上它并不负责。
实际场景中的网络环节是错综复杂的,中间有各种各样的分叉路口,如果一个设备的数据的数据要传输给另一个设备,就需要在各种各样的路径和节点进行选择,而传输层的设计理念是简单、高效、专注,如果传输层还负责这一块功能就有点违背设计原则了。
也就是说,我们不希望传输层协议处理太多的事情,只需要服务好应用即可,让其作为应用见数据传输的媒介,帮助实现到应用的通信,二十几的传输功能就交给下一层,网络层(internet layer).
网络层最常使用的是IP协议(internet Protocol),IP 协议将会将传输层的报文作为数据部分,再加上IP报头组装成IP报文,如果IP报文大小超过MTU(以太网中一般为1500字节)就会再次进行分片,得到一个即将发送到网络的IP报文。
网络层负责将数据从一个设备传输到另一个设备,世界上那么设备,又该如何找到对方呢?因此网络层需要有区分设备的编号。
我们一般用IP地址给设备进行编号,对于IPv4协议,IP地址共32位,分成了四段(比如:192.168.100.1),每段是8位。只有一个单纯的IP地址虽然做到了区分设备,但是寻址起来就特别麻烦,全世界那么多台设备,难道一个一个去匹配?这显然不科学。
因此,需要将IP地址分成两种意义:
一个是网络号,负责标识该IP地址是属于哪个子网的;
一个主机号,负责标识同一子网下的不同主机;
怎么分的呢?这需要配合子网掩码才能算出IP地址的网络号和主机号。
举个例子,比如10.100.122.0/24后面的/24表示就是255.255.255.0子网掩码,255.255.255.0二进制是「11111111-11111111-11111111-00000000」
那么,在寻址的过程中,先匹配到相同的网络号(表示要找到同一个子网),才会去找对应的主机。
除了寻址能力,IP协议还有另一个重要的能力就是路由。实际场景中,两台设备并不是用一条网线连起来的,而是通过很多网关、路由器、交换机等众多网络设备连接起来的,那么就会形成很多网络的路径,因此当数据包到达一个网络节点,就需要通过路由算法决定下一步走那条路径。
路由器寻址工作中,就是要找到目标地址的子网,找到后进而把数据包转发给对应的网络内。
所以,IP协议的寻址作用是告诉我们去往下一个目的地该朝哪个方向走,路由则是根据下一个目的地选择路径。寻址更想在导航,路由更像在操作方向盘。
网络接口层
生成了IP头部后,接下来要交给网络接口层(Link Layer)在IP头部的前面加上MAC头部,并封装成数据帧(Data frame)发送到网络上。
应用层 应用层 --- 应用数据
| |
传输层 传输层 --- TCP头|应用数据
| |
网络层 网络层 --- IP头|TCP头|应用数据
| |
网络接口层 网络接口层 ----帧头|IP头|TCP头|应用数据|帧尾
| |
以太网
IP头部中的接收方IP地址表示网络包的目的地,通过这个地址我们就可以判断要将包发到哪里,但在以太网的世界中,这个思路是行不通的。
什么是以太网呢?电脑上的以太网接口,Wi-Fi接口,以太网交换机、路由器上的千兆,万兆以太网接口,还有网线,他们都是以太网的组成部分。以太网就是一种在局域网内,把附近的设备连接起来,是他们之间可以进行通讯的技术。
以太网在判断网络包目的地址时和Ip的方式不同,因此必须采用相匹配的方式才能在以太网中将包发往目的地,而MAC头部就是干这个用的,所以,在以太网进行通讯要用到MAC地址。
MAC头部是以太网使用的头部,它包含了接收方和发送方的MAC地址等信息,我们可以通过ARP协议获取对方的MAC地址。
所以说,网络接口层主要为网络层提供链路级别传输的服务,负责在以太网、Wi-Fi这样的底层网络上发送原始数据包,工作在网卡这个层次,使用MAC地址来标识网络上的设备。
总结
综上所述,TCP/IP网络通常是由上到下分成4层,分别是应用层,传输层,网络层和网络接口层。
网络接口层的传输单位是帧(Frame),IP层的传输单位是包(packet),TCP层的传输单位是段(segment),HTTP的传输单位则是消息或报文(message)。但这些名词并没有什么本质区分,可以统称为数据包。
2.2键入网址到网页显示,期间发生了什么?
孤单小弟——HTTP
浏览器第一步要做的就是解析URL(网址)
首先浏览器做的第一步工作就是要对URL进行解析,从而生成发送给Web服务器的请求信息。
URL元素组成:
http:+//+Web服务器+/+目录名+/+.....+文件名
URL开头表示访问数据的协议、//后面的字符串表示服务器的名称、/后面表示数据文件的路径名(可省略)
长长的URL网址实际上是请求服务器里的文件资源,Web服务器后面是数据的路径名。
当没有路径名是,就代表访问根目录下事先设置的默认文件,也就是/index.html或者/default.html这些文件,就不会发生混乱了。
生产HTTP请求信息
对URL进行解析之后,浏览器确定了web服务器和文件名,接下来就是根据这些信息来生成HTTP请求信息了。
a .请求报文
b.响应报文
一个孤单单的HTTP数据包表示:“我这么一个小小的数据包,没亲没友,直接发到浩瀚的网络,谁会知道我呢?谁能载我一程呢?谁能保护我呢?我的目的地在哪呢?”。充各种疑问的它,没有停滞不前,毅然踏上了征途!
真是地址查询——DNS
通过浏览器解析URL并生成HTTP消息后,需要委托操作系统叫消息发送给web服务器。
但在发送之前,还有一项工作需要完成,那就是查询服务器域名对应的IP地址,因为委托操作系统发送消息时,必须提供通信对象的IP地址。
所以,有一种服务器就专门保存了web服务器域名与Ip的对应关系,他就是DNS服务器。
域名中的层级关系
DNS中的域名都是用句点来分隔的,比如www.server.com,这里的句点代表了不同层次之间的界限。在,域名中,越靠右的层级越高。
实际上域名最后还有一个点,比如www.server.com.,这个最后一个点代表根域名。
也就是,.根域是在最顶层,它下一层就是.com顶级域,在下面是server.com。
所以域名的层级关系类似一个树状结构:
- 根DNS服务器(.)
- 顶级域DNS服务器(.com)
- 权威DNS服务器(server.com)
根域的DNS服务器信息保存在互联网中所有的所得DNS服务器中。
这样一来,任何DANS服务器就可以找到任意一台DNS服务器,就可以通过它找到根域DNS服务器,然后再一路顺藤摸瓜找到位于下层的某台目标DNS服务器。
域名解析的工作流程:
- 客户端首先会发出一个DNS请求,问www.server.com的IP是啥,并发给本地DNS服务器(也就是客户端的TCP/IP设置中填写的DNS服务器地址。
- 本地域名服务器收到客户端的请求后,如果缓存里的表格能找到www.server.com的,则它直接返回IP地址。如果没有,本地DNS会去问它的根域名服务器:“老大,能告诉我www.server.com的I的IP地址吗?”根域名服务器是最高层次的,它不直接用于域名解析,但能指明一条道路。
- 根DNS收到来自本地NDS的请求后,发现后置是.com,说:“www.server.com的I这个域名归.com区域管理,“我给你.com顶级域名服务器地址给你,你去问他吧。“
- 本地DNS收到顶级域名服务器的地址后,发起请求问”老二,你能告诉我www.server.com的I的IP地址吗?”
- 顶级域名服务器说:“我给你负责www.server.com的I区域的权威DNS服务器的地址,你去问他应该能闻到”。
- 本地DNS于是转向问权威DNS服务器:“老三,www.server.com的I对应的IP是啥呀?”server.com的权威DNS服务器,它是域名解析结果的原出处。为啥叫权威呢?就是我的域名我做主。
- 权威DNS服务器查询后将对应的Ip地址X.X.X.X告诉本地DNS。
- 本地DNS再将IP地址返回客户端,客户端和目标建立连接。
URL解析->生成发送给web服务器的http请求信息->web服务器响应报文->Http消息发送给web服务器->客户端发出DNS请求->本地DNS服务器->根DNS服务器->顶级域名服务器->权威DNS服务器查询服务器域名对应的IP地址并告诉本地DNS->本地DNS将IP返回客户端->客户端和目标建立连接->把http的传输工作交给系统的协议栈-->网络应用程序(浏览器、web服务器)socket库-->操作系统--协议栈:TCP(需要连接)、UDP(不需要连接)-->操作系统--协议栈:IP(传送网络包、确定路由,ICMP、ARP协议)-->驱动程序--网卡驱动程序(控制网卡)-->硬件--物理硬件网卡
可靠传输——TCP
http是基于TCP协议传输的。
源端口号、目的端口号;序号;确认号;状态为:SYN、ACK、RST、FIN;窗口大小。
tcp是面向连接的,因而双方要维护连接的状态,这些带状态为的包的发送,回应起双方的状态变更
TC P要做流量控制;拥塞控制;
TCP传输数据前,要进行三次握手建立连接:
- 一开始,客户端和服务器都处于close状态,先是服务器主动监听某个端口,处于listen状态
- 然后客户端主动发起SYN发起一个连接,然后处于syn-sent状态;
- 服务器收到发起的连接,返回SYN,并且ACK确认客户端的SYN,之后处于SYN- RCVD状态;
- 客户端收到服务器发送的SYN和AC K之后,发送对SYN确认的ACK,之后处于ESTABLISHE D状态,因为它已发一收成功了。
- 服务端收到ACK的ACK后,处于ESTABLISHED状态,因为它也一发一收成功了。
所以三次握手的目的是保证双方都有发送和接收的能力。
TCP分割数据:
MTU:
MSS:
Linux系统是如何发网络包的?
网络模型
为了似的多种设备能通过网络相互通信,和为了解决各种不同设备在网络互联网中兼容性问题,国际标准化组织制定了开放式系统互联通信参考模型(open system interconnection reference model),也就是OSI网络模型,该模型主要有7层,分别是应用测过、表示测过、会话层、出啊数层、网络层、数据链路层以及物理层。
每一层负责的职能都不同,如下:
- 应用层:负责给应用程序提供统一的接口
- 表示层:负责把数据转换成兼容另一个系统能识别的格式
- 会话层:负责建立、管理和终止表示层实体之间的通信会话。
- 传输层:负责端到端的数据传输
- 网络层:负责数据的路由、转发、分片
- 数据链路层:负责数据的封帧和差错检测
- 物理层:负责在物理网络中传输数据帧
常见、实用的是四层模型、即TCP/IP网络模型,Linux系统正式按照这套网络模型来实现网络协议栈的。
应用层:负责向用户提供一组应用程序,比如HTTP、DNS|FTP等。
传输层:负责端到端的通信,比如TCP、UDP等
网络层:负责网络包的封装、分片、路由、转发,比如IP、ICMP等
网络接口层:负责网络包在物理网络中的传输,比如网络包的封帧、MAC寻址、差错检测,以及通过网卡传输网络帧等。
OSI参考模式的应用层、表示层、会话层相当于TCP/IP模型的应用层,OSI参考模式的数据链路层、物理层相当于TCP/IP模型的网络接口层。
Linux网络协议栈
物理链路并不能传输任意大小的数据包,所以在以太网中,规定了最大传输单元(MTU)是1500字节,也就是规定了单次传输的最大IP包大小。
当网络包超过MTU大小,就会在网络层分片,以确保分片后的IP不会超过MTU大小,如果MTU越小,需要的分包就越多,那么网络吞吐能力就越差,如果MTU越大,需要的分包就越好,那么网络吞吐能力就越好。
Linux网络协议帧,类似于TCP/IP的四层结构:
应用程序
内核:
系统调用
LVS
Socket
TCP UDP
IP ICMP
ARP
MAC
网卡驱动个程序 网卡驱动程序
网卡 (硬件) 网卡
Linux接收网络包的流程
网卡是计算机里的一个硬件,专门负责接收和发送网络包,当网卡接收到一个网络包后,会通过DMA技术,将网络包写入到指定的内存地址,也就是写入到Ring Buffer,这是一个环形缓冲区,接着就会告诉操作系统这个网络包已经到达。
那应该怎么告诉操作系统这个网络包已经到达了呢?
最简单的一种方式就是处罚中断,也就是没当网卡收到一个网络包,就出发一个中断告诉操作系统。
但是网络包很多,频繁的触发中断,会影响其他任务进程,从而影响系统的整体效率。
所以为了解决频繁中断带来的性能开销,Linux内核在2.6版本中引入了NAPI机制,它是混合中断轮询的方式来接受网络包,它的核心概念是,采用中断唤醒数据接收服务陈故乡,然后poll的方法来轮训数据。
因此,当有网络包到达时,会通过DMA技术,将网络包写入指定的内存地址,接着网卡向CPU发起硬件中断,当CPU收到硬件中断请求后,根据中断表,调用已经注册的中断处理函数。
硬件中断处理函数会做如下的事情:
需要先暂时屏蔽中断,表示已经知道内存中有数据了,告诉网卡下次再收到数据包直接写内存就可以了,不要再通知CPU了,这样可以提高效率,避免CPU不停的被中断。
接着,发起软中断,然后回复刚才屏蔽的中断。
硬件中断处理函数做的事情很少,主要耗时的工作都交给软中断处理了。
软中断的处理
内核中的ksoftirqd线程专门负责软中断的处理,当ksoftirqd内核线程收到软中断后,就会来轮训处理数据。
ksofitirqd线程会从ring buffer 中获取一个数据帧,用sk_buff表示,从而可以作为一个网络包交给网络协议栈进行逐个层处理。
网络协议栈
首先会进入到网络接口层,在这一层灰检查报文的合法性,如果不合法则丢弃,合法则会找出该网络包的上层协议的类型,比如是IPv4,还是IPv6,接着再去掉帧头帧尾,然后交给网络层。
到了网络层,则取出IP包,判断网络包下一步的走向,比如是交给上层处理还是转发出去。当确认这个网络包要发送给本机后,就会从IP头里看上一层协议的类型是TCP还是UDP,接着去掉IP头,然后交给传输层。
传输层去处TCP头或UDP头,根据四元组“源IP、源端口、目的IP、目的端口”作为标识,找到对应的Socket,并把数据放到Socket接口的缓冲区。最后,应用层程序调用Socket接口,将内核的Socket接收缓冲区的数据拷贝到应用层的缓冲区,然后唤醒用户进程。
Linux发送网络包的流程
发送网络包正好和上面接收网络包的流程相反。
- 首先,应用程序会带哦用socket发送数据包的接口,由于这个是系统调用,所以会从用户态陷入内核态的socket层,内核会申请一个内核态的sk_buff内存,将用户发发送的数据拷贝到sk_buff内存,并将其加入到发送缓冲区。
- 接下来,网络协议栈从socket发送欢送曲中取出sk_buff,并按照TCP/IP协议从上到下逐层处理。
- 如果使用的是TCP传输协议发送数据,那么先拷贝一个新的sk_buff副本,这是因为sk_buff后续在调用网络层,最后被到达网卡发送网卡发送完成后,这个sk_buff会被释放掉。而TCP协议是支持丢失重传的,在收到对方的ACK前,这个sk_buff不能删除。所以内核的做法就是每次调用网卡发送的时候,实际上传出去的是sk_buff的一个拷贝,等收到AC看在真正删除。
- 你可能会好奇,为什么全部数据包只用一个结构体来描述呢?协议栈采用的是分层结构,上层向下层传递数据时需要增加包头,下层向上层传输数据时又需要去掉包头,如果每一层都用一个结构体,那在层之间传递数据的时候,就要多次拷贝,这将大大降低CPU效率。
- 于是,为了在层级之间传递数据时,不发生拷贝,只用sk_buff一个结构体来描述所有的网络包,那他是如何做到的呢?是通过调整sk_buffa中的data指针,比如:
当接首报文时,从过协议栈层层往上传送数据包,通过增加skb->data的值,来住不剥离协议首部。
当要发送报文时,创建sk_buff结构体,数据缓存区的头部预留足够的空间,用来填充个层首部,在经过下层协议时,通过减少skb->data的值来增加协议首部。
- 至此,传输层的工作也就都玩好吃呢过了。
- 然后交给网络层,在网络层里会做这些工作:选取路由(确认下一跳IP)、填充IP头、netfiter过滤,对超过MTU大小的数据包进行分片。处理完这些工作后会交给网络接口层处理。
- 网络接口层会通过ARP协议获得下一跳的MAC地址,然后对sk_buff填充帧头和帧尾,接着讲sk_buff放到网卡的发送队列中。
- 这一些工作准备好后,会触发软中断,告诉网卡驱动程序,这里有新的网络包需要发送,驱动程序会从发送队列中读取sk_buff,将这个sk_buff挂到ring buffer中,接着讲sk_buff数据映射到网卡可访问的内存DMA区域,最后触发真实的发送。
当数据发送完成以后,其实工作并没有结束,因为内存还没有清理。当返送玩好吃呢过的时候,网卡设备会触发一个硬中断来释放内存,主要是释放sk_buff内存和清理ringbuffer内存。
最后,当收到这个TCP报文的ACK应答时,传输层就会释放原始的sk_buff.
HTTP
HTTP基本概念
HTTP是什么?
HTTP是超文本传输协议,也就是HyperText Transfer Protocol.
1.协议
协:代表两个以上的参与者
议:对参与者的一种行为约定规范。
HTTP是一种用在计算机世界里的协议。它使用计算机能够理解的语言确立了一种计算机之间交流通信的规范,以及相关的各种控制和错误处理方式。
2.传输
HTTP是一个双向协议,是一个在计算机世界里专门用来在两点之间传输数据的约定和规范。
3.超文本
HTTP传输的内容是超文本。
超文本:超越普通文本的文本,它是文字、图片、视频等的混合体,有超链接,能从一个超文本跳转到另一个超文本。
HTML是常见的超文本,它本身只是纯文字文件,但内部用很多标签定义了图片、视频等的连接,再经过浏览器的解释,呈现给我们的就是一个文字、有画面的网页了。
HTTP(超文本传输协议):
HTTP在计算机世界在两点之间 传输 文字、图片、音频、视频等超文本 数据的约定和规范
那HTTP适用于从互联网服务器传输超文本到本地浏览器的协议,这种说法正确吗?
这种说法是不正确的,因为也可以是服务器到服务器,所以采用两点之间的描述会更准确。
HTTP常见的状态码有哪些?
1xx:提示信息,表示目前是协议处理的中间状态还需要后续的操作;
2xx:服务器成功处理客户端的请求
200 OK:表示一切正常。非head服务请求,服务器返回的响应头都会有body数据。
204 No Content:也是一切正常,但响应头没有body数据。
206 Partial Content:应用于HTTP分块下载或断点续传,表示响应返回的body数据并不是资源的全部,二是其中的一部分,也是服务器处理成功的状态。
3xx:该状态码表示客户端请求的资源发生了变动,需要客户端用新的URL重新发送请求获取资源,也就是重定向。
301 moved permanently:表示永久重定向,说明请求的资源已经不存在了,改用新的URL再次访问。
302 Found:表示临时重定向,说明请求的资源还在,但暂时需要用另一个URL来访问。
304 Not Modified:不具有跳转的含义,表示资源为修改,重定向已经存在的缓冲文件,也称缓存重定向,告诉客户端可以继续使用缓存资源。
400 Bad Request:表示客户端请求的报文有错误。
403 Forbidden:表示服务器禁止访问资源。
404 Not Found:表示请求的资源在服务器上不存在或未找到。
5xx:该类状态码表示客户端的请求报文正确,但是服务器处理时内部发生了错误,属于服务器端的错误码。
500 intenal Server Error:是个笼统的错误码,服务器发生了什么错误,我们并不知道。
501 Not Implemented:表示客户端请求的功能还不支持。
502 Bad Gateway:通常是服务器作为网关或代理时返回的错误码,表示服务器自身正常,访问后段服务器发生了错误。
503 Service Unavailable:表示服务器当前很忙,暂时无法响应客户端。
HTTP常见字段有哪些?
1、Host字段
指客户端发送请求时,用来指定服务器的域名。
如
Host: www.A.com
有了host字段,就可以将请求发往同一台服务器上的不同网站。
2、Content-Length字段
服务器在返回数据时,会有conten- length字段,表明本次回应的数据长度
Content-Length: 1000
由于http是基于tcp传输协议进行通信的,而使用了tcp传输协议,就会存在一个粘包问题,http协议通过设置回车符、换行符作为http header的边界,通过content- length字段作为http body的边界,这两个方式很好的解决了粘包问题。
http header的边界:回车符、换行
http body的边界:content- length字段
3、connection字段
常用于客户端要求服务器使用Http长连接机制,以便其他请求复用。
http长连接的特点:只要任意一段没有明确提出断开连接在,额保持tcp连接状态。
http/1.1的版本都是默认长连接,但为了兼容老版本的http,需要指定connection首部字段的值为keep- alive。
开启了http keep-alive机之后,连接就不会中断,而是保持连接。
4、content- type字段
content- type字段用于服务器回应时,告诉客户端,本次数据是什么格式。
Content-Type: text/html; Charset=utf-8
上面的类型表明,发送的是王爷,而且编码时utf-8.
5、accept字段
客户端请求时,可以使用accept字段声明自己可以接受那些数据格式。
Accept: */*
表示可以接受任何格式。
6、content- encoding字段
该字段说明数据的压缩方法。表示服务器返回的数据用了什么压缩格式。
Content-Encoding: gzip
上面服务器返回的数据采用了gzip的方式压缩,告知客户需要用此方式解压。
7、accept- coding字段
客户用这个字段说明自己可以接受哪些压缩方法。
Accept-Encoding: gzip, deflate
get与post
get与post有什么区别?
根据RFC 规范,GET的语义是从服务器获取指定的资源,这个资源可以是图片、页面、静态的文本、视频等。get请求的参数位置一般是写在URL中,URL规定只能支持ASCII,所以GET请求的参数只允许ASCII自负,而且浏览器会对URL的长度有限制。(http协议本身对URL 长度并没有做任何规定)
根据RFC规定,POST的语义是根据请求负荷(报文body)对指定的资源做出处理。
post请求携带的数据的位置一般是写在报文body,body中的数据可以是任意格式的数据,只要客户端与服务器端协商好即可,而且而且浏览器不会对 body 大小做限制。
GET和POST都是安全和幂等的吗?
安全和幂等:
在http协议里,安全是指请求方法不会破坏服务器上的资源。
幂等:指多次执行相同的操作,结果都是相同的。
get方法是安全幂等的,无论操作多少次,服务器上的数据都是安全的,且梅西的结果都是想用的。所以可以对get请求的数据做缓存,这个缓存可以做到浏览器本身上(彻底避免浏览器发请求),也可以做到代理上(nginx),而且在浏览器中的get请求可以保存为书签。
post因为是新增或提交数据的操作,会修改服务器上的资源,所以是不安全的,且多次提交数据教会创建多个资源,所以不是幂等。一般浏览器不会缓存post请求,不不能保存为书签。
实际应用中,开发者不一定按rfc规范定义的语义来实现get和post方法:
get方法可以实现新增或删除的请求,不安全幂等。
post实现查询数据的请求,安全幂等。
post:用body传输数据
get:用URL传输数据,这样数据在浏览器地址栏容易看到。
http传输的内容都是明文,虽然在地址栏看不到post提交的body数据,但是只要抓个包就都能看到了。
所以要避免传输过程中数据被窃取,就要用https协议,这样所有的http数据都会被加密传输。
get请求可以带body吗?
RFC规范并没有规定GET请求不能带body的。理论上,任何请求都可以带body。只是因为RFC规定定义的GET请求是获取资源,所以根据这个寓意不需要用到body。
另外URL中的查询参数不是GET所独有的,post请求的URL中也可以有参数。
HTTP缓存技术
HTTP缓存有哪些实现方式?
对于以下具有重复性的HTTp请求,可以把这对请求-响应的数据都缓存在本地,那么下次就直接读取本地的数据,不必再通过网络获取服务器的响应了。
http有两种实现方式:强制缓存和协商缓存
什么是强制缓存?
指的是只要浏览器判断缓存没有过期,则直接使用浏览器的本地缓存,决定是否使用缓存的主动性在浏览器这边。
用两个HTTP响应头部response hesder实现强制缓存:
cache-control,是一个相对的时间,优先级更高,选项更多,设置更加精细。
具体实现流程:
当浏览器第一次请求访问服务器资源时,服务器会在返回这个资源的同时,在response头部加上cache-control,ccache -control中设置了过期的时间大小。
浏览器在次请求访问服务器中的资源时,会先通过请求资源的时间与cache-control中设置的过期时间大小,来计算出该资源是否过期,如果没有,则使用该缓存,否则重新请求服务器;
服务次再次收到请求后,会再次更新responce头部的cache-coontrol.
expires,是一个绝对的时间
什么是协商缓存?
服务端告知客户端是否可以使用缓存的方式称为协商缓存。
协商缓存用两种头部来实现:
1、请求头部中的if-modified-since字段和响应头部中的last-modifief字段实现。
响应头部中的last-modified:标示这个响应资源的最后修改时间;
请求头部的if- modified- since:当资源过期了,发现响应头中具有last- modified声明,则再次发起请求的时候带上last- modified的时间,服务器收到请求后发现有if-modified-since则与被请求资源的最后修改时间进行对比last- modified。最后修改时间交心,说明资源被改过,则返回最新资源http 200ok;如果最后修改时间较旧,说明资源无新修改,响应http304走缓存。
第二种:请求头部中的if-none- match字段,与响应头部的ETag字段
if-none match:资源过期时,浏览器发现响应头里有ETag,则再次请求服务器发起请求时,会将请求有if-none-match值设置为ETag值。服务器收到请求后进行对比,如果资源没有变化返回304,如果有资源变化返回200.
为什么ETag的优先级更高?
这是因为ETag主要解决了last-modified几个比较难解决的问题:
1、最后修改时间可能会改变,导致客户端认为文件被改动了从而重新请求。
2、有些文件是在秒级以内修改了,if-modified-since能检查到的粒度是秒级的,使用ETag能保证这种需求下客户端能在1秒哪能刷新对错;
3、有些服务器不能精确获取文件的最后修改时间。
ETag:唯一标识响应资源
注意:协商缓存这两个字段都需要配合强制缓存中的cache-control字段来使用,只有在未能命中强制缓存的时候,才能发期带有协商缓存字段的请求。
浏览器请求-有缓存-cache-control是否过期-否-从缓存读取;过期-判断是否有etag--是——带if-none-match向web服务器请求——服务器决策——判断是200还是304——有更新——200——请求响应;无更新——304——从缓存读取;过期-判断是否有etag——否——判断是否有last-modified——都——向web服务器请求——请求响应;过期-判断是否有etag——是——带if-modifified-since向web服务器请求——服务器决策-判断是200还是304——有更新——200;无更新——304——从缓存读取;
HTTP特性
HTT P/1.1的优点有哪些?
简单、灵活、易于扩展、应用广泛、跨平台。
1、简单
Http基本的报文格式就是header+body,头部信息是key-value简单文本的形式,易于理解,降低了学习和使用的门槛。
2、灵活和易于扩展
HTTP协议里的各类请求方法、URI/URL、状态码、头字段等每个组成要求都没有被固定死,都允许开发人员自定义和扩充。
同时HTTP由于是工作在应用层(OSI的 第七层),则它下层可以随意变化,比如:
https就是在Http与tcp之间加了SSL/TLS安全传输层;
http/1.1和http/2.0传输协议使用的是tcp协议,而到了http/3.0传输协议改用了UDP协议。
3、应用广泛和跨平台
互联网发展至今,http的应用的范围非常广泛,从台式机的浏览器到手机上的各种app,从看新闻,刷贴吧到购物、理财,吃鸡,htttp的应用遍地开花,同时具有天然的跨平台的优越性。
HTTP/1.1缺点有哪些?
缺点:无状态、明文传输、不安全。
1、无状态双刃剑
无状态的好处:
因为服务器不会去记忆http的状态,所以不需要额外的资源来记录状态信息,从而减轻了服务器的负担,能够把更多的cpu和内存用来对外提供服务。
无状态的坏处:
由于服务器没有记忆能力,在完成有关联性的操作时会非常麻烦。
比如购物网站的支付时身份验证操作,每操作一次服务器都要验证一次,因为服务器不知道这些请求是有关联的。
无状态的解决方案:
cookie技术:
类型为“小型文本文件”,是某些网站为了辨别用户身份,进行Session跟踪而储存在用户本地终端上的数据(通常经过加密),由用户客户端计算机暂时或永久保存的信息。
cookie在请求和响应报文中写入cookie信息来控制客户端的状态。
在客户端第一次请求后,服务器会下发一个装有客户信息的小贴纸,后续客户端请求服务器的时候,带上小贴纸,服务器就能识别出来是谁了。(生产cookie,记住客户端是谁)
2、明文传输双刃剑
优点:方便阅读,比如wire shark抓包都可以直接肉眼查看,为我们调试工作带来了极大便利性。
缺点:信息裸奔,信息的内容容易被窃取。
3、不安全
- 通信使用明文(不加密的意思),因此有可能遭遇伪装。比如账号信息容易泄露。
- 不验证通信方的身份,因此有可能遭遇伪装。如家的淘宝,拼多多。
- 无法证明报文的完整性,所以有可能已遭篡改。比如网页上植入垃圾广告,视觉污染。
HTTP的安全问题,可以用HTTPS的方式解决,也是通过引入SSL/TLS层,使得在安全上达到了极致。
HTTP/1.1的性能如何?
HTTp协议是基于TCP/IP,并且使用了请求/应答的通信模式,所以性能的关键就在这两点里。
1、长连接
早起HTTP/1.0性能上的一个很大的问题,那就是每发起一个请求,都要新建一次TCP连接(三次握手),而且是串行请求,做了无谓的TCP连接建立和断开,增加了通信开销。
为了解决上述TCP连接问题,HTTP/1.1提出了长连接的通信方式,也叫持久连接。这种方式的好处在于减少了TCP连接的重复建立和断开所造成的额外开销,减轻了服务器端的负载。
持久连接的特点是,只要任意一端没有明确提出断开连接,则保持TCP连接状态。
当然,如果某个HTTP长连接超过一定时间没有任何数据交互,服务端就会主动断开这个连接。
2、管道网络传输
HTTP/1.1采用了长连接的方式,这是的管道网络传输成为了可能。
即可在同一个TCP连接里面,客户端可以发起多个请求,只要第一个请求发出去了,不必等起其回来,就可以发第二个请求出去,可以减少整体的响应时间。
但是服务器必须按照请求的顺序发送对这些管道化请求的响应。
如果服务端在处理A请求时耗时比较长,那么后续的请求处理都会被阻塞住,这称为对头阻塞。
所以HTTP/1.1管道解决了请求的队头阻塞,但是没有解决响应的队头阻塞。
TIP注意:
实际上HTTP/1.1管道化技术不是默认开启,而且浏览器基本都没有支持,所以后面所有文章讨论HTTP/1.1都是建立在美誉使用管道化的前提。有这个功能,但没有被使用。
3、队头阻塞
请求-应答的模式会造成HTTP的性能问题。
因为当顺序发送的请求序列中的一个请求因为某种原因被阻塞时,在后面排队的所有请求也一同被阻塞了,会招致客户端一直请求不到数据,这也就是对头阻塞。
HTTP与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-TCP-IP-MAC;
HTTP-SSL/TLS-TCP-IP-MAC.
HTTPS 在HTTP与TCP层之间加入了SSL/TLS协议,可以很好的解决了上述风险:
信息加密(针对窃听风险):交互信息无法被窃取,但你的号因为自身忘记而没。
校验机制(针对篡改风险):无法篡改通信内容,篡改了就不能正常显示,但百度竞价排名依然可以搜索到垃圾广告。
身份证书(针对冒充风险):证明淘宝网是真的淘宝网。
HTTPS是如何解决上面这三个风险的?
- 混合加密的方式实现信息的机密性,解决了窃听的风险。
- 摘要算法的方式来实现完整性,他能为数据生成独一无二的指纹,指纹用于校验数据的完整性,解决了篡改的风险。
- 将服务器公钥发乳要数字证书中,解决了冒充的风险。
1、混合加密
对称加密、非对称加密:
- 在通信建立前采用非对称加密的方式交换「会话秘钥」,后续就不再使用非对称加密。
- 在通信过程中全部使用对称加密的「会话秘钥」的方式加密明文数据。
2、摘要算法+数字签名
为了保证消息的内容不被篡改,我们需要对内容计算出一个指纹,然后同内容一起传输给对方。
对方收到后,,先是对内容也计算出一个指纹,然后跟发送发发送的指纹做一个比较,如果指纹相同,说明内容没有被篡改,否则就可以判断内容被篡改了。
在计算机会用摘要算法(哈希函数)来计算出内容的哈希值,也就是内容的指纹,这个哈希值是唯一的,且无法通过哈希值推导出内容。
通过哈希算法可以确保内容不会被篡改,但是并不能保证“内容+哈希值”不会被中间人替换,因为这里缺少对客户端收到的信息是否来源于服务端的证明。
为了避免这种情况,计算机会用非对称加密算法来解决
那为了避免这种情况,计算机里会用非对称加密算法来解决,共有两个密钥:
- 一个是公钥,这个是可以公开给所有人的;
- 一个是私钥,这个必须由本人管理,不可泄露。
这两个密钥可以双向加解密的,比如可以用公钥加密内容,然后用私钥解密,也可以用私钥加密内容,公钥解密内容。
流程的不同,意味着目的也不相同:
- 公钥加密,私钥解密。这个目的是为了保证内容传输的安全,因为被公钥加密的内容,其他人是无法解密的,只有持有私钥的人,才能解密出实际的内容;
- 私钥加密,公钥解密。这个目的是为了保证消息不会被冒充,因为私钥是不可泄露的,如果公钥能正常解密出私钥加密的内容,就能证明这个消息是来源于持有私钥身份的人发送的。
非对称加密的主要用途在于:通过“私钥加密,公钥解密”的方式来确认消息的身份。、、s
数字签名算法,用的就是“私钥加密,公钥解密”的方式,私钥加密内容是对内容的哈希值加密,内容key-哈希值value(加密)。
私钥是由服务端保管,然后服务端会向客户端颁发对应的公钥。如果客户端收到的信息,能被公钥解密,就说明该消息是由服务器发送的。
3、数字证书
- 可以通过哈希算法来保证消息的完整性;
- 可以通过数字签名来保证消息的来源可靠性(能确认消息是由持有私钥的一方发送的);
但是这还远远不够,还缺少身份验证的环节,万一公钥是被伪造的呢?
将服务器公钥放在由数字证书认证机构(CA)颁发的数字证书中 ,公钥就是可信的。
- 服务器把自己的公钥注册到CA;
- CA用自己的私钥将服务器的公钥进行数字签名,然后颁发数证书;
- 客户端拿到服务器的数字证书后,使用CA的公钥确认服务器的数字证书的真实性;(CA的公钥+CA的数字签名,已经事先置入到了浏览器或操作系统里)
- 从数字证书获取服务器公钥后,使用它对报文加密后发送;
- 服务器用私钥对报文解密。
通过数字证书的方式保证服务器公钥的身份,解决冒充的风险。
#
HTTPS是如何建立连接的?其间交互了什么?
SSL/TLS协议基本流程:
- 客户端想服务器索要并验证服务器的公钥。
- 双方协商生产会话密钥。
- 双方采用会话密钥进行加密通信。
前两步是SSL/TLS建立过程,也就是TLS握手过程。
TLS的握手阶涉及四次通信,使用不同的密钥交换算法,TLS握手流程也会不一样,现在常用的密钥交换算法有两种:RSA算法、ECDHE算法。
TLS 协议建立的详细流程:
1、ClientHello
客户端向服务器发起加密通信请求,也就是ClientHello请求。
客户端主要向服务器发送以下信息:
- 客户端支持的TLS版本
- 客户端生产的随机数(CLient Random),用于生成会话密钥的条件之一。
- 客户端支持的密码套件列表,如RSA加密算法。
2、Server Hello
服务器收到客户端的请求后,客户端发出响应,也就是Server Hello。
服务器主要向可会淡回应以下信息:
- 确认TLS的版本,如果浏览器不支持,则关闭通信。
- 服务器生产的随机数(Server Random),也是后面用于生产会话密钥的条件之一。
- 确认密码的套件列表,如RSA加密算法。
- 服务器的数字证书
3、客户端回应
客户端收到服务器的回应后,首先通过浏览器或操作系统中的CA公钥,确认服务器的数字证书的真实性。
如果证书没有问题,客户端会从数字证书中取出服务器的公钥,然后用呀加密报文,想服务器发送如下信息:
- 一个随机数(pre-master key)。该随机数会被服务器的公钥加密。
- 加密通信算法改变的通知,该通知表示随后的信息都将用会话密钥加密通信。
- 客户端握手结束的通知,该通知表示客户端的握手阶段已结束。同时把之前所有内容发生的数据做个摘要,用来供服务器校验。
服务器和客户端有了这三个随机数(Client Random、Server Random、pre-master key),接着就用双方协商的加密算法,各自生成本次通信的「会话秘钥」。
4、服务器的最后回应
服务器收到客户端的第三个随机数(pre-master key)之后,通过协商的加密算法,计算本次通信的会话密钥。
然后,向客户端发送最后的信息:
- 加密算法改变 的通知,表示随后的信息都将用会话密钥加密通信。
- 服务器握手结束的通知,表示服务器握手阶段已经结束。这一项同时把之前所有内容的发生的数据做个摘要,用来供客户端校验。
至此,整个TLS的握手阶段全部结束。接下来,客户端与服务器加密通信,就完全是使用普通的HTTP协议,只不过这次是用“会话密钥”加密内容。
客户端校验数字证书的流程是怎样的?
数字证书签发和验证流程:
CA签发证书的过程,如上图部分:
首先CA会把持有者的公钥、用途、颁发着、有效时间等信息打成一个包,然后对这些信息进行Hash计算,得到一个Hash值;
然后CA会使用自己的私钥将该Hash值加密,生成Certificate Signature,也就是CA对证书做了签名;
最后将certificate signature添加在文件证书上,形成数字证书;
客户端校验服务端的数字证书的过程,如上图右边部分:
首先客户端会用同样的Hash算法获取该证书的Hash值H 1;
通常浏览器和操作系统集成了CA的公钥信息,浏览器收到证书后可以使用CA的公钥解密Certificate signature内容,得到一个Hash值H2;
最后比较H1和H2,如果值相同,则为可信赖的证书,否则认为证书不可信。
但证书验证过程还存在一个证书信任链的问题。
因为我们向 CA 申请的证书一般不是根证书签发的,而是由中间证书签发的,比如百度的证书,从下图你可以看到,证书的层级有三级:根证书——中间证书——xxx证书
客户端收到的是第三证书,第三证书无法根据本地已有的根证书中的公钥去验证第三证书是否可信。于是客户端根据第三证书中的签发者,找到该证书的颁发机构是中间证书的颁发机构,然后向CA请求该中间证书。
请求到证书后发现中间证书是由根证书的颁发机构签发的,由于该根证书没有在上级的额签发机构,所以说明他是根正顺,也就是自签证书。应用软件会检查此证书是否已经预载于根证书清淡上,如果有,则可以利用根证书中的公钥去验证中间证书,如果发现验证通过,就认为该中间证书是可信的。
中间证书被信任后,可以使用中间证书中的公告去验证第三证书的可信性,如果验证通过,就可以信任第三证书。
在这四个步骤中,最开始客户端知心人根证书,然后根证书信任中间证书,而中间证书又信任第三证书,于是客户端也信任第三证书。
总的来说,由于用户信任根证书,所以由根证书担保的第三证书可以信任,另外由于用户信任操作系统或浏览器的软件上,所以由软件上预载了根证书的都可以被信任。、
为什么会有信任链,为什么Root CA不直接颁发证书?搞那么多层级?
这是为了确根证书的绝对安全性,将根证书隔离的越严格越好,不然根证书如果失守了,那么整个信任链都会有问题。
HTTPS的应用数据是如何保证完整性的?
TLS在实现上分为握手协议和记录协议两层:
- TLS握手协议就是前面说的TLS四次握手的过程,负责协商加密算法和生成对称密钥,后续永磁密钥来保护应用程序数据(即HTTP数据)
- TLS记录协议负责保护应用程序数据并验证其完整性和来源,所以对HTTP数据加密是使用记录协议;
TLS记录协议主要负责消息(HTTP数据)的压缩,、加密以及数据的认证,过程如图:
具体过程如下:
首先,消息被分割成多个较短的片段,然后分别对每个片段进行压缩。
接下来,经过压缩的片段会被加上消息的认证码(MAC值,这个是通过Hash算法生成的),这是为了保护完整性,并进行数据的认证。通过附加信息认证码的MAC值,可以识别出篡改,为了防止重放攻击,在计算消息认证码时,还加上了片段的编码。
在接下来,经过压缩的片段再加上消息认证码会一起通过对称密码进行加密。
最后,上述经过加密的数据再加上有数据类型、版本号、压缩后的长度组成的报头就是最终的报文数据。
记录协议完成后,最终的报文数据将传递到传输控制协议TC片层进行传输。
HTTPS一定安全可靠吗?
客户端通过浏览器项服务端发起HTTPS请求时,被假基站转发到了一个中间人服务器,于是客户端和中间人服务器完成了TLS握手,然后这个中间人服务器再与真正的服务端完成TLS握手。
用户点击接收了中间人服务器的证书,中间人服务器与客户端在TLS握手过程中,实际上发送了自己伪造的证书给浏览器,而这个伪造的证书是能被浏览器(客户端)识别出是非法的,于是就会提醒用户该证书存在问题。
如果用户质疑点击继续浏览此网站,相当于用户接受了中间人伪造的证书,那么后续合作呢哥哥HTTPS通信都能被中间人监听了。
所,HTTPS协议本身到目前为止是还没有任何漏洞的,即使你成功进行中间人攻击,本质上是利用了客户端的漏洞(用户继续点击访问或者被恶意倒入伪造的根证书),并不是HTTPS不够安全。