💡 有理想,但不妄想, 💭 |

navyum

园龄:4个月粉丝:0关注:0

08.*应用层、HTTP(七层)

HTTP

发送格式:

图片

响应格式:

图片

HTTPS

与HTTP相比,多了SSL/TLS 握手协议

概念:前向安全性:

  • 密钥泄露后,即使拿到以前的记录,也无法通过密钥进行破解
  • RSA、DH加密算法是非前向安全的;ECDHE是前向安全的

SSL/TLS 握手协议:

  • 目的:
    • 通过非对称加密算法,握手后协商出对称加密密钥
  • 花费:
    • 2 RTT
      • TLS 1.2 通常情况下
    • 1 RTT
      • 使用会话复用技术后
    • 0 RTT
      • TLS 1.3 使用会话复用和Pre-shared Key(请求和Ticket一起发) #### TLS 密钥套件Ciper suite
  • 格式:
    • TLS + 密钥协商算法 + 证书签名算法 + WITH + 对称加密算法 + 摘要算法
  • 举例:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256(TLS 1.2)
  • 算法说明:
    • 密钥协商算法:TLS阶段,用于生成对称密钥或者加密对称密钥的要素(要素加密)
    • 签名算法:TLS阶段,用户客户端校验服务器证书有效性、ECDHE公钥的有效性(证书校验)
    • 对称加密算法:TLS完成后,数据传输时加密(数据传输)
    • 摘要算法:TLS最后阶段,对密钥协商过程数据做摘要并验证(过程验证)
  • 举例:TLS_AES_256_GCM_SHA384(TLS 1.3)
    • 密钥协商算法不在套件内,而是通过key_share扩展指定
    • 签名算法不在套件内,而是通过signature_algorithms扩展指定 Img

TLS 1.2 (ECDHE)握手过程:

Img * TCP 握手、挥手过程在内核协议栈进行,TLS在应用层 * TLS第一次握手: * 客户端发 client hello消息 * 消息包含:客户端TLS 版本号、支持的密码套件列表、客户端随机数 * TLS第二次握手: * 服务端发 server hello消息 * 消息包含:协商后的TLS 版本号、协商后的协议套件、服务端随机数 * 服务端发 certificate消息 * 消息包含:证书、证书对应的签名 * 服务端生成用于协议传输的公、私钥(基于协商的协议套件) * 服务端发 serverKeyExchange消息(ECDHE有该过程,RSA没有) * 消息包含:ECDHE公钥、公钥签名、椭圆曲线的参数 * 服务端发 serverHelloDone消息 * 消息包含:服务端协商相关数据已传输结束 * TLS第三次握手: * 客户端验证证书有效性(通过CA或者OSCP stampling) * 客户端生成用于协议传输的公、私钥(基于协商的协议套件) * 客户端发 clientKeyExchange消息 * ECDHE 消息包含:ECDHE公钥、公钥签名、椭圆曲线的参数 * RSA 消息包含:使用服务端证书公钥加密premaster secret后的字符串 * 客户端发 changeCipherSpec消息 * 计算出对称加密密钥,即会话密钥 * ECDHE:双端公钥+椭圆曲线的参数+双端随机数 * RSA:pre-master secret+双端随机数 * 消息包含:通知服务端后续使用对称加密 * 客户端发 Encrypted Handshake Message消息 * 先使用摘要算法,计算协商过程产生的数据摘要 * 客户端再使用对称加密的会话密钥对摘要加密 * 消息包含:加密的摘要 * TLS第四次握手:(ECDHE时,客户端无需等待第四次完成即可发用户数据) * 服务端发 changeCipherSpec消息 * 使用私钥解密出pre-master secret,计算出对称加密密钥,即会话密钥 * ECDHE:双端公钥+椭圆曲线的参数+双端随机数 * RSA:pre-master secret+双端随机数 * 消息包含:通知客户端后续使用对称加密 * 服务端发 Encrypted Handshake Message消息 * 先使用摘要算法,计算协商过程产生的数据摘要 * 服务端再使用对称加密的会话密钥对摘要加密 * 消息包含:加密的摘要

TLS 1.2 和 1.3对比:

Img * 性能:TLS 1.2 握手4次,2RTT;TLS 1.3 握手2次,1RTT * 安全:TLS 1.3 将支持的密码套件缩减到五个,但都是前向安全

TLS 握手性能优化:

  • 硬件优化:
    • 提升CPU性能(HTTPS协议是计算密集型)
  • 软件优化:
    • 软件升级:openssl
    • 协议升级:
      • 使用TLS 1.3
      • 密钥交换算法使用ECDHE(替换RSA
    • 证书优化:
      • 证书传输:
        • 选择使用ECDSA替换RSA(前者协议数据更小)
      • 验证过程:
        • OCSP 在线证书状态协议:向CA查询证书的有效状态,按需查询。建议使用。
        • CRL 证书吊销列表:向CA拉取证书吊销列表,一次查全量,但数据太大。
        • OCSP Stapling
          • 原先为了验证的服务器的身份,服务器会在 TLS 握手过程中,把自己的证书发给客户端用于验证
          • 使用OCSP Stapling,服务端向CA周期性地查询证书状态,在握手时返回给客户端,这样客户端就不用再去查询有效性了
  • 工程优化:
    • 会话复用:
      • 含义:把首次TLS握手协商的对称加密密钥缓存起来,后续需要建立 HTTPS 连接时,直接复用
      • 基于Session ID
        • 服务端和客户端都缓存。使用唯一Session ID将密钥缓存到内存
      • 基于Session Ticket
        • 仅客户端缓存。客户端握手时上传Session Ticket,服务端解密验证
      • 基于Pre-shared Key
        • 在 TLS 1.3支持
        • 客户端重连后,不进行握手,而是直接发 HTTP请求,将Session Ticket同时传给服务器
    • 会话复用的缺点:
      • 非前向安全
      • 无法应对重放攻击
      • 应对方法:需要设置好有效期 #### 实战经验:
  • wireshark解析TLS加密报文:
    • 修改系统环境变量:export SSLKEYLOGFILE=“/data/sslkeylogfile”
    • 修改wireshark配置
      • 【编辑】->【首选项】->【Protocols】->【TLS】->【Pre-Master Secret log】-> “/data/sslkeylogfile”

HTTP/1.0

  • 略过

HTTP/1.1

  • 基于TCP,使用文本进行传输 #### HTTP/1.1 的改进:
  • 长连接:复用TCP连接,避免TCP握手的消耗
  • 管道网络传输(pipeline):客户端的请求可以并发,但服务端响应需要有序(HTTP2.0 解决)
  • 缓存策略:更复杂的缓存,协商缓存
  • 大文件范围请求Range:断点续传
  • 必须要Host头字段:一台服务器可以托管多个域名的网站

HTTP/1.1 存在的问题:

  • 并发连接有限
    • 浏览器最大并发连接数是 6 个
    • TCP 和 TLS 握手耗时
  • HTTP队头阻塞问题
    • 同一连接只能在完成一个 HTTP 事务(请求和响应)后,才能处理下一个事务
  • HTTP头部巨大且重复
  • 不支持服务器推送消息,需要通过轮询方式

针对 HTTP/1.1 优化手段:

  • 减少请求:
    • 缓存数据、304 Not Modify
    • 减少重定向次数
    • 合并请求
    • 按需获取
  • 数据压缩:
    • Accept-Encoding、Content-Encoding
    • 无损压缩:gzip
    • 有损压缩:webp、png、heif

HTTP/2.0

特征:

  • 兼容HTTP/1.1,基于TCP,使用二进制传输
  • 语义不改变,只是全部都是小写
  • 语法改变大,HTTP报文的传输格式改变
  • “h2”表示使用 TLS加密(HTTPS)的HTTP/2.0,“h2c”非加密(HTTP)

HTTP/2.0 的改进:

HPACK头部压缩
  • 静态表编码:
    • 共61组,HTTP/2.0协议内默认编码好了
  • 动态表编码:
    • 非静态表的头部,由客户端和服务端自行构建
    • 仅对同一个TCP连接生效、当出现重复传输完全相同的HTTP头部时,才会起作用
    • 存放在内存中,如果连接一直占用,可能会占用较高内存
  • Huffman 编码(压缩算法) Img
  • 存在的问题:
    • HPACK队头阻塞问题:动态表发生变化+并发下,如果完整的编码未被接收,会导致后续压缩结果无法被发送,造成队头阻塞
二进制格式编码
  • HTTP/1.1 使用文本,HTTP/2.0 使用二进制

  • 化整为零,将传输信息(header+body)分割为更小的帧 Img

  • 名词解释:

    • HEADERS 帧:传输请求Header 内容
    • DATA 帧:传输请求正文(多个 Data帧属于同一个流,有先后顺序)
    • Frame Header:帧头(属于帧内的结构)
    • Frame Payload:帧数据(属于帧内的结构)
  • h2包解析: Img

多路复用
  • 含义:
    • 一条 TCP 连接在同一时间可以跑多个Stream
  • TCP connection、stream、message、frame的关系: Img
    • connection可以有多个Stream
    • Stream包含两个Message请求message响应message
    • Message包含一个或者多个Frame(Message 对应 HTTP/1 中的请求或响应)
    • Frame是 HTTP/2 最小单位,以二进制压缩存放 HTTP/1 中的头部和包体,Frame是有顺序的,一个 Frame 可以由多个 TCP 报文构成`
服务器推送(Server Push/ Cache Push)
  • 作用:
    • 将可能会用到的数据先发送给客户端缓存下来
  • 服务端推送时创建的stream ID是偶数
  • 客户端请求时创建的stream ID是奇数
解决HTTP的队头阻塞
  • 通过Stream多路复用解决
  • 同一个tcp连接中,http1的请求需要排队等待http事务完成后才能进行下一个(默认不开启pipeline,即使开启,服务端响应需要有序返回,这样也会阻塞);
  • http2使用流可以在同一个tcp中实现并发

HTTP/2.0 未解决的问题:

  • TCP队头阻塞问题
    • 发生丢包时依赖tcp重传,得等到收到数据包后才能继续处理后续的流
  • 网络迁移需要重新建立TCP连接
    • 一个 TCP 连接是由四元组确定,IP地址或者端口变动,就需要TCP与 TLS重新握手(TCP存在连接状态导致,UDP无该问题)

帧协议格式:

图片
  • 帧长度:
    • 单个帧最大2^24 = 16M
  • 帧类型:
    • 大致可以分成:
      • 数据帧:HEADERS 、DATA
      • 控制帧:SETTINGS、PING、PRIORITY等
    • 此外 gRPC 定义了几种自用的新帧类型。
  • 帧标志:
    • End Headers:表示header传输结束,在HEADERS帧使用
    • End stream:表示客户端或者服务端单方面数据传输结束,在HEADRS帧(get)、DATA帧(post)使用
    • Padded:表示该流是用来填充的,在任意帧都使用
    • Ack:表示确认,在PING帧SETTING帧中使用
  • 流标识符:Stream ID
    • 流 ID 是递增的:
      • 客户端发起的 ID 是奇数
      • 服务器端发起的 ID 是偶数
    • 流是可并发的:
      • 一个连接上可以同时有多个流,即“多路复用”也就是并发多请求;
    • 流是双向的
      • 客户端和服务器都可以创建流,双方互不干扰
      • 一个流对应一次http请求、响应
    • 流之间是独立的
      • 但流内部的帧是有严格顺序的
    • 流是有优先级的:
      • 在流上发送PRIORITY帧,让服务器优先处理某些流
      • e.g. 先传 HTML/CSS,后传图片,优化用户体验
    • 流是可取消的:
      • 在流上发送RST_STREAM帧可以随时终止流,取消接收或发送
    • 第0号流比较特殊,不能关闭,也不能发送数据帧,只能发送控制帧,用于流量控制。

数据收发:

  • 从不同层对应的消息:
    • 在“流”内看,消息由有序的“帧”序列组成
    • 在“TCP”的层面上看,消息是乱序收发的“帧”
      • 多个请求/响应之间没有了顺序关系,不需要根据请求顺序排队等待 图片 图片
  • 数据发送过程:
    1. 发送方将多个请求分到多个流中,然后将请求内容拆成帧,进行二进制传输
    2. 多个请求的帧,在传输层打散乱序发送
    3. 接收方根据每个帧首部的流标识符重新进行组装
    4. 可以根据优先级,决定优先处理哪个流的数据
    5. 因为TCP滑动窗口的原因,如果某个包没被确认,虽然后续包已到达,也不会被确认,而是一直阻塞
    6. 1.1 vs 2.0 发送示意图: 图片

HTTP/3.0(HTTP-over-QUIC)

  • 在HTTP/3.0中,数据流由传输层QUIC提供,而在HTTP/2中,流由HTTP层完成 ### QUIC:
  • 特征:
    • QUIC 基于UDP,是一个自己处理数据流的传输层协议,自身实现了TCP的一些特性
    • QUIC 使用且必须用TLS 1.3传输层安全协议
    • QUIC流 可以是单向的、也可以是双向的,由发起端决定
    • QUIC 在用户空间中实现,使用QUIC意味着选择了套接字API之外的另一套API
    • 建立过程:可能在首次握手时协商使用HTTP/2协议,通过Alt-Svc头部,服务器通告客户端它对HTTP/3的支持与偏好。所以首次连接可能会有TCP连接和UDP同时进行(跟DNS解析ipv4和ipv6同时进行类似)
      • e.g. Alt-Svc: h3=“:50781”,建议客户端使用UDP端口50781提供的HTTP/3

解决HTTP/2.0 的问题:

  • TCP 队头阻塞:
    • QUIC的流基于UDP连接,每个流相互独立,互不影响(因为UDP不管顺序,不管丢包,所以传输层没有阻塞问题)
  • TCP 建立连接的延迟更低:
    • HTTP2.0:tcp + tls = 1RTT +2 RTT
    • QUIC:传输层握手和tls合并
  • 网络迁移(wifi和蜂窝互换)需要重新建立TCP连接
    • HTTP2.0 基于TCP,tcp 五元组唯一确认一个连接
    • QUIC 基于UDP,使用唯一的connection id,端口号同UDP端口

QUIC协议:

  • 总览:
UDP Header
Packet Header -----
QUIC Frame Header -- TLS1.3
HTTP3 Frame Header --
HTTP Message -----
Img
  • Packet(负责连接可靠):
    • 定义Connection ID,类似TCP连接四元组
      • 64比特位(8字节)整数标识
    • Packet Number实现了类似TCP的可靠的连接
      • 重传:当 UDP 报文丢失后,通过 Packet Header 中的 Packet Number 实现报文重传。
      • Packet Number 单调递增,重传的包Packet Number不一样:
        • RTT是精确的,没有TCP重传导致的RTT歧义
        • 包可以被乱序确认
          • 通过Stream ID + Offset可以确认是同一个包,即使packet Number不一样
    • Connection ID实现了连接迁移:
      • 记录Destination Connection ID,在客户端 IP 地址、端口变化后,绕过 UDP 四元组,继续维持连接
    • 一个 Packet 报文中可以存放多个 QUIC Frame,不能超过PMTUD(1200字节) Img
    • 上图Area Data即多个QUIC Frame,即在一个connection 中并发多个请求
  • QUIC Frame(负责字节流有序):
    • 一个Frame不可跨越多个Packet传输
    • Frame Type
      • 定义不同类型的Frame
        • QUIC STREAM Frame 应用层数据传输
        • other Frame 状态管理 Frame通用头
    • QUIC STREAM Frame
      • Stream Id 实现有序的字节流:
        • 在无序的 Packet 报文中,Stream Id相同表示同一个HTTP消息(消息过大时,可跨Packet传输)
        • 最低2位比特位用于识别连接的类型(单向、双向、发起者)
          • 最低1比特位表示流的发起者:
            • 0:双数流,客户端发起; 1:单数流,服务器发起
          • 第2个比特位识别单/双向流:
            • 0:双向;1:单向
      • offset用于重建字节流,实现消息的序列化:
        • 通过Offset字段完成类似于TCP协议中的Sequence序号,进行累计确认
      • Length 指明了Frame数据的长度
      • 以下为QUIC STREAM Frame格式:
        • Stream Data即HTTP/3 Frame Stream Frame
  • HTTP/3 Frame(负责HTTP语义): HTTP3 通用Frame头信息
    • Type:类似 HTTP/2的帧类型:
      • DATA帧、HEADERS帧、SETTINGS帧、GOAWAY帧、MAX_PUSH_ID帧(限制服务器推送消息数量)
    • Frame Payload
      • 存放二进制的 HTTP message
    • 作用:
      • 可跨越多个Packet
      • 实现服务器推送
      • 实现 QPACK 编解
      • 权重优先级设定
      • 流量控制
  • HTTP Message(具体消息内容):
    • 通用HTTP协议数据,header、body等

QUIC机制:

自定义连接:
  • 不再以四元组标识,而是以一个64位的随机数作为Connection ID来标识
  • 加密算法的版本协商与传输层握手合并完成,以减小延迟
自定义重传机制:
  • Packet Number(数据包编号):在QUIC协议中,每个数据包都有一个唯一的编号,用于标识数据包在传输过程中的顺序和重传情况。Packet Number 用于确保数据包按正确的顺序传输,并在需要时进行重传
无阻塞的多路复用:
  • 同一条 QUIC Connection Id上可以创建多个 stream 来发送多个请求(跟HTTP 2.0 一致)
  • QUIC为每个Stream分配独立的滑动窗口。在传输层面如果出现丢包,只影响包所在的stream,其他stream无需等待。(跟HTTP2.0差异点,因为是基于UDP的)
自定义流量控制:
  • stream级别的滑动窗口:
    1. QUIC 通过 window_update帧来告诉对端它可以接受的字节数
    2. QUIC 窗口的起始位置为当前收到的最大 offset
    3. QUIC 的 ACK 是基于 offset 的,每个 offset 的包来了,进了缓存,就可以应答(相信中间的空档一定会到来)
    4. QUIC为每个Stream分配独立的滑动窗口,相互之间不影响 窗口示意图:TCP 和 QUIC 图片
    5. 可用窗口左边界:
      • TCP:已确认的序号
      • QUIC:收到的最大Offset
  • 连接级别的流量控制窗口:
    • 对所有的stream做整体大小控制
服务器推送(Server Push/ Cache Push)
  • 作用:
    • 将可能会用到的数据先发送给客户端缓存下来,需要客户端同意
  • 过程:
    • 服务器通过请求流发送一个 PUSH_PROMISE 帧,使该推送请求看上去像是一个响应,然后通过新的流发送实际推送数据
    • 客户端可随时通过CANCEL_PUSH 帧取消推送
    • 客户端可以设置推送次数限制

HTTP/3.0机制

头部压缩
  • QPACK:
    • 为什么要改HPACK:
      • 由于动态表具有时序性,QUIC中数据流互相独立,并发下因为可能还未建立动态表会导致失败
    • QPACK使用两个额外的单向QUIC流,用于在两个方向上传递动态表信息
      • QPACK Encoder Stream:用于传输动态表信息 Img

      • QPACK Decoder Stream:用于对传输内容的确认响应 Img

二进制格式编码
  • 同HTTP2.0相似,将传输信息(header+body)分割为更小的帧 Img
HTTP/3.0 Frame:

Img * 帧类型与HTTP2基本相同 * 流的相关功能前置到传输层QUIC实现 * 头部压缩算法使用QPACK

对比:

图片 * 参考: * https://http3-explained.haxx.se/zh/why-QUIC/why-tcphol * https://xiaolincoding.com/network * https://kiosk007.top/post/quic-%E5%8D%8F%E8%AE%AE/

本文作者:navyum

本文链接:https://www.cnblogs.com/navyum/p/18509330

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   navyum  阅读(14)  评论(0编辑  收藏  举报
//自己上传到博客园的js
点击右上角即可分享
微信分享提示