9. HTTP/2 连接 (HTTP/2 Connections)
HTTP/2 连接是在可靠传输 [TCP] 之上运行的应用层协议, 并使用传输层安全 (Transport Layer Security, TLS) [TLS13] 保护网络上交换的数据.
HTTP/2 使用与 HTTP/1.1 相同的 "http" 和 "https" URI 方案. HTTP/2 也共享相同的默认端口号: "http" URI 使用 80, "https" URI 使用 443. 因此, 实现需要在处理指向 http://example.org/foo 或 https://example.com/bar 等目标资源 URI 的请求时, 先发现上游服务器 (客户端希望与之建立连接的直接对等方) 是否支持 HTTP/2.
9.1. 连接管理 (Connection Management)
HTTP/2 连接是持久的. 为获得最佳性能, 预期客户端在确定不再需要与服务器通信之前 (例如用户离开某个特定网页时), 或在服务器关闭连接之前, 不会关闭连接.
对于给定的主机和端口对, 客户端 SHOULD NOT 打开多于一个 HTTP/2 连接; 其中主机可以派生自 URI、所选择的替代服务 [ALT-SVC], 或已配置的代理.
客户端可以创建额外连接作为替代连接, 例如替换接近耗尽可用流标识符空间的连接 (Section 5.1.1), 刷新 TLS 连接的密钥材料, 或替换遇到错误的连接 (Section 5.4.1).
客户端 MAY 为以下目的向同一目标打开多个连接: 创建新连接以尝试原子性请求 (见 Section 9.1.2), 或替换在 GOAWAY 帧中收到且大于 0、并处于 "active" 或 "idle" 状态的任何流标识符 (见 Section 6.8).
鼓励服务器尽可能长时间保持连接打开, 但必要时允许终止空闲连接. 当任一端点选择关闭传输层 TCP 连接时, 发起终止的端点 SHOULD 先发送 GOAWAY 帧 (Section 6.8), 以便双方能够可靠判断先前发送的帧是否已被处理, 并优雅地完成或终止任何仍有必要执行的剩余任务.
9.1.1. 连接复用 (Connection Reuse)
无论是直接连接到源服务器, 还是通过 CONNECT 方法创建的隧道连接到源服务器 (Section 8.5), 连接 MAY 被复用于具有多个不同 URI authority 组件的请求. 只要源服务器具有权威性 (Section 10.1), 连接就可以复用. 对于不使用 TLS 的 TCP 连接, 这取决于主机是否解析到同一 IP 地址.
对于 "https" 资源, 连接复用还取决于是否拥有对 URI 中主机有效的证书. 服务器出示的证书 MUST 满足客户端为该源建立新的 TLS 连接时会执行的任何检查.
源服务器可能提供包含多个源的证书, 其中每个源都对使用该连接具有权威性. 例如, 证书可能在 subjectAltName 字段中包含多个主机名. 或者, 包含通配符的主机名也可能适用于其他源.
在某些情况下, URI authority 可能不同于证书中标识的源集合 (例如, 某些部署使用 URI 携带在其他地方建立的身份断言), 且 authority 的其他属性也不匹配. 客户端 MAY 尝试使用现有连接, 但 MUST 使用客户端认为具有权威性的 URI 发送请求. 如果服务器不希望接受该请求, 它 SHOULD 生成 421 (Misdirected Request) 状态码, 这将导致客户端重试请求.
如果客户端发现它试图复用的连接已不可用, 它 MAY 在新连接上重试不安全请求.
代理 MAY 复用到同一源服务器的连接.
9.1.2. 421 (Misdirected Request) 状态码 (The 421 Status Code)
421 (Misdirected Request) 状态码表示请求被定向到无法生成响应的服务器. 当服务器未被配置为针对请求 URI 中包含的 scheme 与 authority 组合生成响应时, 可以发送此状态码.
收到 421 (Misdirected Request) 响应的客户端 MAY 在不同连接上重试请求, 无论请求方法是否幂等. 这是可行的, 因为只有在服务器选择不提供权威响应之前, 才允许生成 421 响应码.
代理 MUST NOT 生成此状态码. 421 响应是可缓存的; 除非响应另有指示, 默认情况下它可按启发式方式缓存 (见 [HTTP-CACHING] 的 Section 4.2.2).
9.2. TLS 特性的使用 (Use of TLS Features)
HTTP/2 实现 MUST 对 "https" URI 使用 TLS 1.2 [TLS12] 或更高版本. [TLSBCP] 给出了 TLS 实现使用的一般指导.
TLS 实现 MUST 支持 Server Name Indication (SNI) [TLS-EXT] 扩展. HTTP/2 客户端 MUST 在 TLS 握手期间指示目标域名, 除非提供了用于指示目标主机的替代机制.
依赖 TLS 1.3 [TLS13] 或更高版本的 HTTP/2 部署 SHOULD 在客户端和服务器上支持并使用 TLS Application-Layer Protocol Negotiation (ALPN) 扩展 [TLS-ALPN]. 这样可以在 TLS 握手期间标识 HTTP/2 的使用, 而不消耗一次往返.
虽然连接级选项并非 HTTP 使用所特有, 使用 HTTP/2 的服务器可以表达其对连接的偏好. TLS 提供加密, 可以尽量降低窃听者获知客户端与服务器之间交换信息的能力. TLS 还提供完整性保护, 确保信息在传输过程中不会因无意的网络损坏或主动攻击者而被修改.
协商使用 HTTP/2 后, MUST 遵循 [TLS12] Section 7.4.1.4 中的规则. 这些规则使用服务器证书建立身份; 客户端证书不能用于此目的. 还要求检查证书链和证书颁发机构 (CA).
如果 HTTP/2 是通过 TLS 1.2 协商的, MUST 提供 TLS 1.2 密码套件黑名单 (Section 9.2.2).
不鼓励使用压缩的 TLS 证书; HTTP/2 中客户端和服务器使用的证书 SHOULD NOT 被压缩, 除非客户端显式请求.
9.2.1. TLS 1.2 特性 (TLS 1.2 Features)
本节描述特定于 HTTP/2 的 TLS 1.2 使用限制. 由于这些限制主要已在 TLS 1.3 中得到处理, 鼓励实现使用 TLS 1.3 或更高版本. 仅使用 TLS 1.2 的实现 MUST 遵守本节要求.
9.2.1.1. HTTP/2 客户端的 TLS 1.2 特性 (TLS 1.2 Features for HTTP/2 Clients)
HTTP/2 客户端实现 MUST 支持通过握手中的扩展字段发送 TLS Server Name Indication (SNI) [TLS-EXT].
HTTP/2 客户端 MUST 支持 TLS Application-Layer Protocol Negotiation (ALPN) [TLS-ALPN].
9.2.1.2. HTTP/2 服务器的 TLS 1.2 特性 (TLS 1.2 Features for HTTP/2 Servers)
如果服务器通过 ALPN 或 NPN 以外的某种方式协商 HTTP/2, 服务器 MUST 给客户端提供机会来指示其是否愿意使用 HTTP/2.
HTTP/2 服务器 SHOULD 发送 extended master secret 扩展 [RFC7627]. 如果客户端不支持此扩展, 服务器 MUST NOT 恢复先前建立的会话. 如果协商了 extended master secret, 服务器 MAY 恢复先前建立的会话.
9.2.2. TLS 1.2 密码套件 (TLS 1.2 Cipher Suites)
基于 TLS 1.2 的 HTTP/2 部署 MUST 支持 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 [TLS-ECDHE] 以及 secp256r1 [RFC8422] 椭圆曲线. 注意, 客户端通过 TLS ClientHello 消息中的 supported_groups 扩展 [TLS13] 指示它支持的曲线, 服务器则通过选择该扩展提供的任一列出曲线来指示对某条曲线的支持.
客户端 MAY 通告支持 TLS 1.2 上用于 HTTP/2 的任何密码套件. 然而, 下列密码套件具有已知的低质量属性, 因此禁止在 TLS 1.2 上的 HTTP/2 中使用. 这些套件具有以下一项或多项属性:
- NULL 密码套件, 不提供加密.
- 基于流密码的套件, 其在 TLS 中的使用容易受到攻击.
- 基于 RC4 的套件, 存在严重安全问题.
- 基于 3DES 的套件, 提供的实际安全强度低于 112 位.
- CBC 模式块密码套件, 对 TLS 中的攻击敏感, 特别是在 TLS 1.2 及更早版本中.
- 基于 RSA 密钥交换的套件, 不提供前向保密性.
- 使用不鼓励与 TLS 一起使用的 Diffie-Hellman 参数的套件.
- 使用 SHA-1 摘要且对 AEAD 算法支持较差的套件.
禁止密码套件的完整列表见 Appendix A.
9.3. 连接前言 (Connection Preface)
在 HTTP/2 中, 每个端点都需要发送连接前言, 作为对所用协议的最终确认, 并建立 HTTP/2 连接的初始设置. 客户端和服务器分别发送不同的连接前言.
客户端连接前言以 24 个八位组的序列开始, 其十六进制表示为:
0x505249202a20485454502f322e300d0a0d0a534d0d0a0d0a
也就是说, 连接前言以字符串 PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n 开始. 此序列 MUST 后跟一个 SETTINGS 帧 (Section 6.5), 该帧 MAY 为空. 客户端在收到服务器连接前言后立即发送客户端连接前言.
| 注意: 选择客户端连接前言是为了尽量降低 HTTP/2 连接被处理其他 HTTP
| 协议的服务器视为有效 HTTP/1.1 请求的可能性. 注意, HTTP/1.1 请求不太可能
| 合理地包含 "PRI" 作为方法 token.
服务器连接前言由一个可能为空的 SETTINGS 帧 (Section 6.5) 组成, 它 MUST 是服务器在 HTTP/2 连接中发送的第一个帧.
正在升级且已收到需要 HTTP/1.1 (或更早版本) 的 101 (Switching Protocols) 响应的客户端 MUST 立即发送客户端连接前言.
服务器接收客户端连接前言, 客户端接收服务器连接前言. 连接前言中的 SETTINGS 帧 MUST 被确认 (见 Section 6.5.3), 作为进一步连接建立的一部分 (见 Section 3.4).
为避免不必要的延迟, 允许客户端在发送客户端连接前言之后立即向服务器发送其他帧, 而无需等待接收服务器连接前言. 但需要注意的是, 服务器连接前言中的 SETTINGS 帧可能包含为了与服务器通信而必须遵守的参数. 客户端收到 SETTINGS 帧后, SHOULD 遵守其中建立的任何参数. 在某些配置中, 服务器可能在客户端发送其他帧之前传输 SETTINGS, 从而提供避免此问题的机会.
客户端和服务器 MUST 将无效连接前言视为 PROTOCOL_ERROR 类型的连接错误 (Section 5.4.1). 在这种情况下 MAY 省略 GOAWAY 帧 (Section 6.8), 因为无效前言表明对等方未使用 HTTP/2.
第 9 章完成!
References
- [TCP] RFC 793
- [TLS13] RFC 8446
- [TLS12] RFC 5246
- [TLS-EXT] RFC 6066
- [TLS-ALPN] RFC 7301
- [TLSBCP] RFC 9325
- [TLS-ECDHE] RFC 5289
- [RFC8422] RFC 8422
- [RFC7627] RFC 7627
- [ALT-SVC] RFC 7838
- [HTTP-CACHING] RFC 9111