【网络篇】HTTP知识
键入网址到网页显示,期间发生了什么?
浏览器第一步是解析URL,这样就得到了服务器名称和文件的路径名,然后根据这些信息生成http请求,通过DNS查询得到我们要请求的服务器地址,然后添加TCP头、IP头以及MAC头,MAC 头部包含了接收方和发送方的 MAC 地址等信息,接收方的MAC可以通过ARP协议获取,ARP 协议会在以太网中以广播的形式,通过IP地址得到对应的MAC地址,这时网络包只是存放在内存中的一串二进制数字信息,这些数字信息需要通过网卡转换成电信号的形式发送出来,再通过交换机抵达路由器,通过路由器抵达服务器,当数据包抵达服务器后,服务器会依次检查 MAC 头、IP 头以及TCP 头,根据TCP头的端口号将包发给 HTTP 进程,服务器的 HTTP 进程收到访问页面请求后,将这个网页封装在 HTTP 响应报文中,客户端得到 HTTP 响应报文后,于是交给浏览器去渲染页面,这样我们就能看到我们想要的内容了。
Linux 系统是如何收发网络包的?
发送数据包
应用程序会调用 Socket 发送数据包的接口,由于这个是系统调用,所以会从用户态陷入到内核态中的 Socket 层,内核会申请一个内核态的 sk_buff 内存,将用户待发送的数据拷贝到sk_buff 内存,并将其加入到发送缓冲区。 接下来,网络协议栈从 Socket 发送缓冲区中取出 sk_buff,并按照 TCP/IP 协议栈从上到下逐层处理。
- 第一次,调用发送数据的系统调用的时候,内核会申请一个内核态的 sk_buff 内存,将用户待发送的数据拷贝到 sk_buff 内存,并将其加入到发送缓冲区。
- 第二次,在使用 TCP 传输协议的情况下,从传输层进入网络层的时候,每一个 sk_buff 都会被克隆一个新的副本出来。副本 sk_buff 会被送往网络层,等它发送完的时候就会释放掉,然后原始的 sk_buff 还保留在传输层,目的是为了实现 TCP 的可靠传输,等收到这个数据包的 ACK 时,才会释放原始的 sk_buff 。
- 第三次,当 IP 层发现 sk_buff 大于 MTU 时才需要进行。会再申请额外的 sk_buff,并将原来的 sk_buff 拷贝为多个小的 sk_buff。
当有网络包到达时,会通过 DMA 技术,将网络包写入到指定的内存地址(Ring Buffer,是一个环形缓冲区),接着网卡向 CPU 发起硬中断,硬中断会暂时屏蔽中断,避免 CPU 持续中断影响效率。接着,发起软终端,内核中的 ksoftirqd 线程专门负责处理软中断,当收到软中断后,就会 poll 轮询处理数据。ksoftirqd 线程会从 Ring Buffer 获取数据帧作为一个网络包交给网络协议栈进行处理。
HTTP 常见的状态码有哪些?
1xx 类状态码属于提示信息,是协议处理中的一种中间状态,实际用到的比较少。
2xx 类状态码表示服务器成功处理了客户端的请求:
200 OK 是最常见的成功状态码,表示一切正常。如果是非 HEAD 请求,服务器返回的响应头都会有 body 数据。204 No Content 也是常见的成功状态码,与 200 OK 基本相同,但响应头没有 body 数据。206 Partial Content 是应用于 HTTP 分块下载或断点续传,表示响应返回的 body 数据并不是资源的全部,而是其中的一部分,也是服务器处理成功的状态。
301 Moved Permanently 表示永久重定向,说明请求的资源已经不存在了,需改用新的 URL 再次访问。302 Found 表示临时重定向,说明请求的资源还在,但暂时需要用另一个 URL 来访问。注:301 和 302 都会在响应头里使用字段 Location ,指明后续要跳转的 URL,浏览器会自动重定向新的URL。304 Not Modified 不具有跳转的含义,表示资源未修改,重定向已存在的缓冲文件,也称缓存重定向,也就是告诉客户端可以继续使用缓存资源,用于缓存控制。
400 Bad Request 表示客户端请求的报文有错误,但只是个笼统的错误。403 Forbidden 表示服务器禁止访问资源,并不是客户端的请求出错。404 Not Found 表示请求的资源在服务器上不存在或未找到,所以无法提供给客户端。
500 Internal Server Error ,是个笼统通用的错误码,服务器发生了什么错误,我们并不知道。501 Not Implemented 表示客户端请求的功能还不支持。502 Bad Gateway 通常是服务器作为网关或代理时返回的错误码,表示服务器自身工作正常,访问后端服务器发生了错误。503 Service Unavailable 表示服务器当前很忙,暂时无法响应客户端,类似“网络服务正忙,请稍后重试”的意思。
HTTP 常见字段有哪些?
Host 字段:客户端发送请求时,用来指定服务器的域名。
Host:www.A.com 有了 Host 字段,就可以将请求发送到同一台服务器上的不同网站。
Content-Length 字段:服务器在返回数据时,会有 Content-Length 字段,表明本次回应的数据长度。
HTTP 是基于 TCP 的,TCP 存在“粘包问题”,HTTP 协议通过设置回车符、换行符作为 HTTP header 的边界,通过 Content-Length 字段作为 HTTP body 的边界来解决“粘包问题”
Connection 字段: 用于开启 http 长链接模式。
Content-type 字段:用于服务器回应时,告诉客户端,本次数据是什么格式。
客户端请求的时候,可以使用 Accept 字段声明自己可以接受哪些数据格式。Accept: */* 表示客户端可以接受任何格式的数据。
Content-Encoding 字段: 表示服务器返回的数据使用了什么压缩格式。
GET 和 POST 有什么区别?
GET 的语义是从服务器获取指定的资源。
POST 的语义是根据请求负荷(报文body)对指定的资源做出处理。
GET 和 POST 方法都是安全和幂等的吗?
- 安全:在 HTTP 协议里,安全是指请求方法不会破坏服务器上的资源。
- 幂等:多次执行相同的操作,结果都是相同的。
GET是安全且幂等的,POST是不安全且不幂等的。
HTTP 缓存技术
HTTP 缓存实现方式?
HTTP 特性
到目前为止,HTTP 常见版本有 HTTP/1.1,HTTP/2.0,HTTP/3.0,不同版本的 HTTP 特性不同
HTTP/1.1 的优点有哪些?
1.简单:报文格式简单,就是 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.应用广泛和跨平台:无论是pc端还是手机APP,HTTP 的应用被广泛使用。
HTTP/1.1 的缺点有哪些?
Cookie 是一种由服务器通过 HTTP 响应发送到客户端(通常是浏览器)的小型文本数据,用于存储客户端的信息。每次客户端发起请求时,浏览器会将相关的 Cookie 信息自动附加到 HTTP 请求头中,以便服务器可以读取并使用这些信息。
HTTP/1.1 的性能如何?
HTTP 与 HTTPS 有哪些区别?
HTTPS 解决了 HTTP 的哪些问题?
- 混合加密的方式实现信息的机密性,解决了窃听的风险。
- 摘要算法的方式来实现完整性,解决了篡改的风险。
- 将服务器公钥放入到数字证书中,解决了冒充的风险。
- 在通信建立前采用非对称加密的方式交换「会话秘钥」,后续就不再使用非对称加密。
- 在通信过程中全部使用对称加密的「会话秘钥」的方式加密明文数据。
- 对称加密只使用一个密钥,运算速度快,密钥必须保密,无法做到安全的密钥交换。
- 非对称加密使用两个密钥:公钥和私钥,公钥可以任意分发而私钥保密,解决了密钥交换问题但速度慢。
- 公钥加密,私钥解密。这个目的是为了保证内容传输的安全,因为被公钥加密的内容,其他人是无法解密的,只有持有私钥的人,才能解密出实际的内容;
- 私钥加密,公钥解密。这个目的是为了保证消息不会被冒充,因为私钥是不可泄露的,如果公钥能正常解密出私钥加密的内容,就能证明这个消息是来源于持有私钥身份的人发送的。
通过数字证书的方式保证服务器公钥的身份,解决冒充的风险。
HTTPS 是如何建立连接的?其间交互了什么?
- 客户端向服务器索要并验证服务器的公钥
- 双方协商生产「会话秘钥」
- 双方采用「会话秘钥」进行加密通信
1. ClientHello首先,由客户端向服务器发起加密通信请求,也就是 ClientHello 请求。在这一步,客户端主要向服务器发送以下信息:(1)客户端支持的 TLS 协议版本,如 TLS 1.2 版本。(2)客户端生产的随机数( Client Random ),后面用于生成「会话秘钥」条件之一。(3)客户端支持的密码套件列表,如 RSA 加密算法。2. SeverHello服务器收到客户端请求后,向客户端发出响应,也就是 SeverHello 。服务器回应的内容如下:(1)确认 TLS 协议版本,如果浏览器不支持,则关闭加密通信。(2)服务器生产的随机数( Server Random ),也是后面生产「会话秘钥」条件之一。(3)确认的密码套件列表,如 RSA 加密算法。(4)服务器的数字证书。3.客户端回应客户端收到服务器的回应之后,首先通过浏览器或者操作系统中的 CA 公钥,确认服务器的数字证书的真实性。 如果证书没有问题,客户端会从数字证书中取出服务器的公钥,然后使用它加密报文,向服务器发送如下信息:(1)一个随机数( pre-master key )。该随机数会被服务器公钥加密。(2)加密通信算法改变通知,表示随后的信息都将用「会话秘钥」加密通信。(3)客户端握手结束通知,表示客户端的握手阶段已经结束。这一项同时把之前所有内容的发生的数据做个摘要,用来供服务端校验。服务器和客户端有了这三个随机数(Client Random、Server Random、pre-master key),接着就用双方协商的加密算法,各自生成本次通信的「会话秘钥」。4. 服务器的最后回应服务器收到客户端的随机数( pre-master key )之后,通过协商的加密算法,计算出本次通信的「会话秘钥」。 然后,向客户端发送最后的信息:(1)加密通信算法改变通知,表示随后的信息都将用「会话秘钥」加密通信。(2)服务器握手结束通知,表示服务器的握手阶段已经结束。这一项同时把之前所有内容的发生的数据做个摘要,用来供客户端校验。至此,整个 TLS 的握手阶段全部结束。接下来,客户端与服务器进入加密通信,就完全是使用普通的 HTTP 协议,只不过用「会话秘钥」加密内容。
RSA 算法的缺陷
不支持前向保密。
因为客户端传递随机数(用于生成对称加密密钥的条件之一)给服务端时使用的是公钥加密,服务端收到后,会用私钥解密得到随机数。一旦服务端的私钥泄露了,过去被第三方截获的所有 TLS 通讯密文都会被解密。
HTTPS ECDHE 握手解析
第一次握手
客户端首先会发送 Client Hello 消息,消息中包含客户端使用的 TLS 版本号、支持的密码套件列表和生成的随机数。
第二次握手
服务端回复 Server Hello 消息,消息中包含服务端确认的 TLS 版本号,服务端的随机数、选择的密码套件和数字证书。
由于服务端选择了 ECDHE 密钥协商算法,会在发送完证书后,发送 Server Key Exchange 消息,这个过程服务器做了三件事:
- 选择椭圆曲线,确定基点,公开给客户端
- 生成随机数作为私钥,保留在本地
- 根据基点和私钥计算出服务端的公钥,公开给客户端(公钥会用RSA算法签名,防止被修改)
随后,服务端发送 Server Hello Done 消息,至此 TLS 两次握手完成。
第三次握手
客户端校验证书,确认合法后,生成随机数作为私钥,再根据服务端给的信息生成公钥,然后用 Client Key Exchange 消息给服务端。
客户端和服务端根据对方的椭圆曲线公钥、自己的椭圆曲线私钥、椭圆曲线基点计算出共享密钥(客户端和服务端计算得到的结果相同),最终的会话密钥就是用客户端随机数、服务端随机数、共享密钥生成的。
算好密钥后,客户端发送一个 Change Cipher Spec 消息,告诉服务端后续改用对称加密算法通信。接着发送之前的信息摘要,用对称密钥加密,让服务端验证本次生成的对称密钥是否可以正常使用。
TLS 第四次握手
服务端发送算好密钥后发送与客服端同样的消息,至此握手完成。
RSA 和 ECDHE 握手过程的区别:
- RSA 密钥协商算法不支持前向保密,ECDHE 密钥协商算法支持前向保密
- 使用了 RSA 密钥协商算法,TLS 完成四次握手后,才能进行数据传输,而对于 ECDHE 算法,客户端可以不用等服务端最后一次 TLS 握手,就可以提前发送加密的 HTTP 数据,节省了一个消息的往返时延。
- 使用 ECDHE,在 TLS 第二次握手中,会出现服务端发出的 Server Key Exchange 消息。而 RSA 握手过程没有该消息。
HTTPS 的应用数据是如何保证完整性的?
- TLS 握手协议负责协商加密算法和生成对称密钥;
- TLS 记录协议负责保护应用程序数据并验证其完整性和来源。
具体过程如下:
- 首先,消息被分割成多个较短的片段,然后分别对每个片段进行压缩
- 接下来,经过压缩的片段会被加上消息认证码
- 再接下来,经过压缩的片段再加上消息认证码会一起通过对称密码进行加密
- 最后,加密的数据再加上由数据类型、版本号、压缩后的长度组成的报头就是最终的报文数据
- 记录协议完成后,最终的报文数据将传递到 TCP 层进行传输
HTTPS 一定安全可靠吗?
问题:https 一定安全可靠吗?如果有假基站起了转发全部信息的作用,这样是不是假基站就获取到全部信息了,从而造成信息泄露?
为什么抓包工具能截取 HTTPS 数据?
如何避免被中间人抓取数据?
HTTP/1.1、HTTP/2、HTTP/3 的演变
HTTP/1.1 相比 HTTP/1.0 提高了什么性能?
- 使用长连接的方式改善了 HTTP/1.0 短连接造成的性能开销。
- 支持管道网络传输,只要第一个请求发出去了,不必等其回来,就可以发第二个请求出去,可以减少整体的响应时间。
- 请求 / 响应头部未经压缩就发送,首部信息越多延迟越大。只能压缩 Body 的部分;
- 发送冗长的首部。每次互相发送相同的首部造成的浪费较多;
- 服务器是按请求的顺序响应的,如果服务器响应慢,会招致客户端一直请求不到数据,也就是 队头阻塞;
- 没有请求优先级控制;
- 请求只能从客户端开始,服务器只能被动响应。
HTTP/2 做了哪些优化?
- 头部压缩:如果发送多个请求,头部一样或相似,那么会压缩相同部分
- 二进制格式:相较于以前的文本格式,提高了传输效率
- 并发传输
- 服务器主动推送资源
HTTP/2 缺陷
还是会造成队头阻塞,但是问题不在 http 上了,而是在 TCP 上,因为 TCP 一旦出现丢包,所有的 http 请求都必须等待这个包重传。
HTTP/3 做了哪些优化
把 HTTP 下层的 TCP 协议改成了 UDP
基于 UDP 的 QUIC 协议可以实现类似 TCP 的可靠性传输。
- 无队头阻塞
- 更快的连接建立
- 连接迁移
HTTP/1.1 如何优化?
1.尽量避免发送 HTTP 请求
- 使用缓存
2.在需要发送 HTTP 请求时,减少请求次数
- 减少重定向请求次数(可以把重定向的任务交给代理服务器)
- 合并请求
- 延时发送请求(请求网页时,可以按需获取,用户向下滑动页面时,再向服务器获取接下来的资源)
3.减少服务器的 HTTP 响应的数据大小
- 有损压缩
- 无损压缩
HTTPS 如何优化?
对于硬件优化的方向
- 因为 HTTPS 是属于计算密集型,应该选择计算力更强的 CPU,而且最好选择支持 AES-NI 特性的 CPU,这个特性可以在硬件级别优化 AES 对称加密算法,加快应用数据的加解密。
对于软件优化的方向
- 考虑把软件升级成较新的版本,比如将 Linux 内核 2.X 升级成 4.X, 将 openssl 1.0.1 升级到 1.1.1,因为新版本的软件不仅会提供新的特性,而且还会修复老版本的问题。
对于协议优化的方向
- 密钥交换算法应该选择 ECDHE 算法,而不用 RSA 算法,因为 ECDHE 算法具备前向安全性,而且客户端可以在第三次握手之后,就发送加密应用数据,节省了 1 RTT。
- 将 TLS1.2 升级 TLS1.3,因为 TLS1.3 的握手过程只需要 1 RTT,而且安全性更强。
对于证书优化的方向
- 服务器应该选用 ECDSA 证书,而非 RSA 证书,因为在相同安全级别下,ECC 的密钥长度比 RSA 短很多,这样可以提高证书传输的效率;
- 服务器应该开启 OCSP Stapling 功能,由服务器预先获得 OCSP 的响应,并把响应结果缓存起来,这样 TLS 握手的时候就不用再访问 CA 服务器,减少了网络通信的开销,提高了证书验证的效率;
对于重连 HTTPS 时,我们可以使用一些技术让客户端和服务端使用上一次 HTTPS 连接使用的会话密钥,直接恢复会话,而不用再重新走完整的 TLS 握手过程。
常见的会话重用技术有 Session ID 和 Session Ticket,用了会话重用技术,当再次重连 HTTPS 时, 只需要 1 RTT 就可以恢复会话。对于 TLS1.3 使用 Pre-shared Key 会话重用技术,只需要 0 RTT 就可以恢复会话。
这些会话重用技术虽然好用,但是存在一定的安全风险,它们不仅不具备前向安全,而且有重放
攻击的风险,所以应当对会话密钥设定一个合理的过期时间。
什么是重放攻击?
重放攻击是攻击者截获并重新发送(“重放”)之前合法通信的数据包,以欺骗系统、用户或服务,使其认为这些数据包是新的合法请求,从而造成未经授权的操作或访问。
既然有 HTTP 协议,为什么还要有 RPC?
- TCP 是无边界的数据流,上层需要定义消息格式用于定义消息边界。于是就有了各种协议,HTTP 和各类 RPC 协议就是在 TCP 之上定义的应用层协议。
- RPC 本质上不算是协议,而是一种调用方式,而像 gRPC 和 Thrift 这样的具体实现,才是协 议,它们是实现了 RPC 调用的协议。目的是希望程序员能像调用本地方法那样去调用远端的服务方法。同时 RPC 有很多种实现方式,不一定非得基于 TCP 协议。
- 从发展历史来说,HTTP 主要用于 B/S 架构,而 RPC 更多用于 C/S 架构。但现在其实已经没分那么清了,B/S 和 C/S 在慢慢融合。很多软件同时支持多端,所以对外一般用 HTTP 协议,而内部集群的微服务之间则采用 RPC 协议进行通讯。
- RPC 其实比 HTTP 出现的要早,且比目前主流的 HTTP/1.1 性能要更好,所以大部分公司内部都还在使用 RPC。
- HTTP/2.0 在 HTTP/1.1 的基础上做了优化,性能可能比很多 RPC 协议都要好,但由于是这几年才出来的,所以也不太可能取代掉 RPC。
既然有 HTTP 协议,为什么还要有 WebSocket?
- TCP 协议本身是全双工的,但我们最常用的 HTTP/1.1,虽然是基于 TCP 的协议,但它是半双工的,对于大部分需要服务器主动推送数据到客户端的场景,都不太友好,因此我们需要使用支持全双工的 WebSocket 协议。
- 在 HTTP/1.1 里,只要客户端不问,服务端就不答。基于这样的特点,对于登录页面这样的简单场景,可以使用定时轮询或者长轮询的方式实现服务器推送(comet)的效果。
- 对于客户端和服务器之间都要互相主动发送大量数据的场景,比如网页游戏,考虑使用 WebSocket 协议。
- WebSocket 与 socket 几乎没有任何关系,只是叫法相似。WebSocket工作在应用层。
- 正因为各个浏览器都支持 HTTP 协议,所以 WebSocket 会先利用 HTTP 协议加上一些特殊的 header 头进行握手升级操作,升级成功后就跟 HTTP 没有任何关系了,之后就用 WebSocket 的数据格式进行收发数据。
完!