服务器中不支持 ALPN 的 HTTP/2 h2

Posted

技术标签:

【中文标题】服务器中不支持 ALPN 的 HTTP/2 h2【英文标题】:HTTP/2 h2 with no ALPN support in server 【发布时间】:2018-05-25 07:36:43 【问题描述】:

在阅读了 HTTP/2 RFC (#7540) 和 TLS-ALPN RFC (#7301) 之后,我仍然无法 找出缺少 ALPN 时的预期行为。

假设我有一个使用 HTTP/2“h2”(通过 TLS)的客户端,它与支持 HTTP/2 的服务器通信,但不在“服务器 hello”中发送 ALPN 扩展。 客户的预期行为是什么?

到目前为止,我见过的大多数客户端都认为服务器不支持 HTTP/2 并将连接降级到 http/1.1,但很少有人忽略 (go-gRPC) 继续使用 HTTP/2。

如果使用在客户端(“h2”)和服务器(“h2c”)之间进行 SSL 终止的 AWS 经典 LB,此方案可能更实用。在此示例中,客户端发送值为“h2”的 ALPN 扩展,LB 在没有 ALPN 的情况下执行 SSL 握手(正如他的预期),最终 JAVA gRPC 由于 HTTP/1.1 降级而失败。

【问题讨论】:

【参考方案1】:

回答问题,不用alpn,但是用npn,还是可以支持grpc的。

两个澄清,

    grpc 的 http2 协商可以通过 alpn 或 npn 进行。 如果客户端支持 alpn,它会在 Client Hello 中发送 alpn 扩展和 npn 扩展。 如果服务器支持 alpn,则服务器仅使用带 h2 的 alpn 响应。如果不支持 alpn 并且 npn 是“服务器 LB 配置”中的配置,它将发送 npn 和 h2。 如果您不配置 alpn,我在 haproxy 和 nginx 中注意到的内容,除非配置,否则它不会默认为 npn。 grpc 客户端坚持使用 h2。如果 alpn 和带有 h2 的 npn 都没有发生,客户端将断开连接,因为它假定 h2 不受支持,并且 h2 对于 grpc 是强制性的

【讨论】:

【参考方案2】:

这完全取决于客户端和服务器。许多人仍然支持 SPDY 和 HTTP/2 支持的旧 NPN TLS 扩展,尽管官方规范说只使用 ALPN。

例如,在browser side 上,Chrome、Firefox 和 Opera 现在仅支持基于 ALPN 的 HTTP/2,尽管它们过去都支持基于 NPN 的 HTTP/2。在编写 Safari 时,IE 和 Edge 仍然允许使用 NPN 或 ALPN。

在服务器端,一些(例如 Nginx)同时支持,而一些(例如 Apache)仅支持 ALPN。

我也会质疑“降级”的术语。 ALPN 扩展是使用 h2 的请求,在发送单个 HTTP 消息之前作为 TLS 协商的一部分发生。因此,它不再是真正的降级,而是升级请求不成功。

【讨论】:

恕我直言,ALPN 扩展在 TLS 协商中是可选的。到目前为止我所看到的是,当服务器响应“server hello”不包含 ALPN 时,握手成功完成,并且(通常)客户端发送加密的 http/1.1 数据。 我的问题实际上是关于规范,我想知道这是否是公认的行为,或者它是否写在 RFC(我没有找到)中,当服务器缺少 ALPN扩展,客户端默认选择http/1.1 正确。它是可选的。就像 TLSv1.2 支持是可选的一样。不支持 TLSv1.2 的客户端不会“降级”到 TLSv1.0 - 它从一开始就从未在 TLSv1.2 上启动!如果服务器只支持 TLSv1.2,那么客户端就无法连接。 在我看来,规范很清楚。要通过 HTTPS (h2) 使用 HTTP/2,必须使用 ALPN:tools.ietf.org/html/rfc7540#section-3.3。如果没有 ALPN 支持,您将无法通过 HTTPS 使用 HTTP/2(尽管正如我所说,目前一些客户端和服务器仍然允许使用 ALPN 的前身 NPN)。因此,您只剩下 HTTP/1.1、1.0 甚至 0.9(不寒而栗)。协商 HTTP/2 的其他方法(“升级”或“先验知识”)在 HTTP/2 规范中明确标记为仅用于非安全 HTTP 连接。 我接受您的评论。对 AWS CLB 作为 SSL 终止的示例场景有什么想法吗?

以上是关于服务器中不支持 ALPN 的 HTTP/2 h2的主要内容,如果未能解决你的问题,请参考以下文章

我可以通过 NPN 协商使用 OkHttp 发送 http/2 请求吗?

golang http2 client 和server 使用非TLS 模式(h2c)

Android grpc 错误:TLS ALPN 协商失败,协议:[grpc-exp,h2]

尝试通过 python 套接字升级到 http2

通过 JAX-RS 客户端支持 HTTP/1.1 和 HTTP/2

sh RPM使用静态OpenSSL 1.1在CentOS 6/7上使用ALPN构建Nginx 1.11.x(在Chrome中支持http / 2支持需要1.02+)