为什么 Chrome 又不支持我的 HTTP/2 网站了?

wxy 的头像

·

·

·

15,695 次阅读

昨晚偶尔清理 Chrome 插件时发现我的 “HTTP/2 and SPDY indicator”插件好像好久没亮了。这个插件在你访问到一个支持 HTTP/2 (或之前的 SPDY 协议)的网站时会点亮,而我明明记得之前专门让 https://linux.cn/ 支持了 HTTP/2 。

我的第一反应是不是这个插件有问题了?于是打开 Chrome 调试工具,然后发现,真的是请求和响应都是 HTTP/1.1 哎!

经过一番研究,原来是从 Chrome 51 开始,在 2016 年 5 月 31 日之前,对支持 NPN 协商协议的 HTTP/2 网站还会采用 HTTP/2 访问;而之后就只支持 ALPN 协商协议的 HTTP/2 网站了——而目前 ALPN 协议仅被鲜少有发行版支持 openssl-1.0.2 支持。

发生了什么?

服务器端

我们知道,最初的 Web 访问协议是 HTTP/1,包括以前的 HTTP/1.0 和现在大部分网站采用的 HTTP/1.1(HTTP/0.9 是试验性协议,已经废弃)。但是随着 Web 应用越来越复杂,之前的 HTTP/1.x 协议就看起来不能满足日益庞杂的 Web 服务需求了。比如说,明文请求、请求复用等问题。因此,谷歌就开发了一个新的传输层协议,名为 SPDY。由于这个新的协议用了的人都说好,因此谷歌就把这个协议提交到了 IETF,然后大家觉得,SPDY 这名字不好听(SPDY 是谷歌的注册商标),就干脆叫 HTTP/2 吧!

SPDY 协议是基于 SSL/TLS 的,谷歌开发了一个名为 下一代协议协商 Next Protocol Negotiation (NPN)的 SSL/TLS 扩展,用于在客户端连接服务器时协商是否采用 HTTP/2 协议。SPDY 协议是由 Web 服务器所实现支持的,而 NPN 则是由 OpenSSL 等 SSL 实现支持的。

但是,随着 SPDY 被提交到 IETF,然后变成了 HTTP/2 协议,谷歌也放弃了 SPDY 的开发,全力投入到了 HTTP/2 的开发中,之前所采用 NPN 也被一种新的协商协议 ALPN —— 应用层协议协商 Application-Layer Protocol Negotiation 所替代。NPN 和 ALPN 是不兼容的,它们的主要不同是:

  • NPN 是服务器发送所支持的协议列表,由客户端进行选择。而 ALPN 则是客户端发送该列表,由服务端选择。
  • 在 NPN 中,最终的选择结果是在 Change Cipher Spec 之后发送给服务端的,也就是说是被加密了的。而在 ALPN 中,所有的协商都是明文的。

这样做的好处主要是安全性方面的考虑,但是这造成了一个问题就是,NPN 已经广泛地被 OpenSSL 支持,而 ALPN 则目前只有最新的 openssl-1.0.2 才支持。当前的几个主流 Linux 发行版的 OpenSSL 版本以及支持的协商协议如下:

Linux 发行版OpenSSL 版本所支持的协商协议
CentOS/Oracle Linux/RHEL 5.10+0.9.8e不支持
CentOS/Oracle Linux/RHEL 6.5+, 7.0+1.0.1eNPN
Ubuntu 12.04 LTS1.0.1NPN
Ubuntu 14.04 LTS1.0.1fNPN
Ubuntu 16.04 LTS1.0.2gALPN 和 NPN
Debian 7.01.0.1eNPN
Debian 8.01.0.1kNPN

从上面我们可以看到,基本上所有的服务器级的 Linux 发行版都不支持 OpenSSL 及 ALPN,唯一支持的 Ubuntu 16.04 LTS 显然用的不会很多。不要小看这 0.0.1 的版本差异,对于别的软件来说这 0.0.1 的差异基本上可以忽略,但是对于 OpenSSL 来说,那就是两个版本代际。OpenSSL 是个相当底层的库,很多重要的软件都依赖于它,因此各个发行版在升级 OpenSSL 时采用的态度是相当保守,比如我们可以看看 CentOS 系统中有哪些软件使用了 OpenSSL:

$ lsof | grep libssl | awk '{print $1}' | sort | uniq
anvil
fail2ban
gdbus
gmain
httpd
postfix
mysqld
NetworkManager
nginx
php-fpm
puppet
sshd
sudo
tuned
zabbix_agent

没有经过足够的测试,Linux 发行版是不会在产品级(服务器级)的环境中随便升级的。为了解决旧版本(1.0.1)中的安全问题,他们宁可将新的版本(1.0.2)中安全修复移植回旧版本,也不会升级到有新功能的新版本(1.0.2),这就是你见到了各种 1.0.1e、1.0.1k 这样的版本号的原因。

当然,你可以自己编译一个最新 OpenSSL 替代你系统中的 openssl-1.0.1,但是我想你不会这样做的,是吧?

顺便提一句,NPN 和 ALPN 可以并存,但是会客户端会优先选择 ALPN。

浏览器端(Chrome)

从 Chrome 51 开始,谷歌就去掉了对 SPDY 的支持,不过这不是个事,因为不但使用 SPDY 的 Web 服务器比较少,而且从 SPDY 升级到 HTTP/2 也很简单,这方面 Nginx、Apache 等服务器的配置都很简单。

但不幸的是,在 Chrome 51 中,谷歌也去掉了对 NPN 的支持!如果你的 Web 服务器使用的是 openssl-1.0.2 以下的版本,不支持 ALPN 协商,那么 Chrome 51 及以后版本就会以 HTTP/1 协议访问你的网站。

谷歌对放弃 NPN 支持做了一个简短的解释,但是不管怎么说,NPN 协议在 Chrome 51 之后的版本不会再次回来了。而另一方面,OpenSSL 在 2016 年 12 月 31 日之后也不会继续发布 openssl-1.0.1 系列的新版本了,安全修复到此为止。

而在这种情况下,你原本支持 HTTP/2 的网站通过连接复用等 HTTP/2 所提供的新特性,在 Chrome 下访问取得了不错的体验,而现在又跌回了之前的残旧状态。

怎么办呢?

有几种办法:

换浏览器

山不来就我,我去就山。Chrome 51+ 不支持带 NPN 的 HTTP/2 网站,作为浏览者,你可以使用其它的浏览器,比如 Safari、Edge 之类的。这样,你就可以用新的协议来访问世界上那 10% 支持 HTTP/2 的 Web 服务器了。

但是,作为服务器运营者,你却不能忽视高达 50% 以上的 Chrome 用户

换服务器

如上面所示,Ubuntu 16.04 LTS 是目前唯一官方支持 openssl-1.0.2 的 Linux 发行版,如果你一直采用 Ubuntu 做服务器,考虑一下升级吧。LTS 版本的支持期长达五年。

当然,在产品环境中,即便你是 Ubuntu 服务器,更新版本也是一件重大事宜,宜慎思之。

重新编译

既然换服务器不是一个好的选择,那你还有一个方案,就是使用新的 openssl-1.0.2 源代码重新编译你的 Web 服务器,比如 nginx。

下面我简单介绍一下如何用 openssl-1.0.2 来编译 nginx。(1.0.2 系列的最新版本是 1.0.2j,当然你要非用 1.1.0,我也无话可说……)

首先下载并解压 openssl-1.0.2j:

# wget https://www.openssl.org/source/openssl-1.0.2j.tar.gz
# tar -zxvf openssl-1.0.2j.tar.gz

然后在编译 nginx 的时候使用 --with-openssl=../openssl-1.0.2j 选项以及你的其它选项:

./configure --with-openssl=../openssl-1.0.2j --with-http_v2_module --with-http_ssl_module

配置并编译之后,你可以用 nginx -V来看一下你的 nginx 中的 OpenSSL 版本。

这种自行编译的好处是灵活性高,但是你需要随时注意各个组件是否有严重的安全漏洞,并在出了修复版本之后重新编译。

容器

除了自己编译之外,如果你的系统环境中已经有了容器支持,你还可以在容器中运行一个 Ubuntu 16.04 LTS,并将 Web 服务器运行在其中。

总结

以上就是 HTTP/2 和 Chrome 之间的故事,你准备去升级 HTTP/2 支持了吗?要知道相比 HTTP/2 的访问体验,你肯定不会想再回到 HTTP/1 了。

7 条回复

  1. kashu [Chromium 66.0|Xubuntu 14.04] 的头像
    kashu [Chromium 66.0|Xubuntu 14.04]

    "插件好像好久没亮了",那个插件叫什么名字?
    从头到翻到尾就没看到那个插件是什么…… (´・ω・`)

    来自吉安
  2. ivmm [Chrome 55.0|Mac 10.12] 的头像
    ivmm [Chrome 55.0|Mac 10.12]

    Debian jessie backports 已经提供 openssl 1.0.2 了。

    来自绍兴
  3. linux [Chrome 54.0|Mac 10.11] 的头像
    linux [Chrome 54.0|Mac 10.11]

    第一句。。。

    来自北京
  4. kashu [Chromium 66.0|Xubuntu 14.04] 的头像
    kashu [Chromium 66.0|Xubuntu 14.04]

    额……看到了,原来是,哈哈……

    来自吉安
  5. 来自黑龙江哈尔滨的 Chrome Mobile 46.0|Android 6.0 用户 的头像
    来自黑龙江哈尔滨的 Chrome Mobile 46.0|Android 6.0 用户

    请教一下,想学linux,能不能推荐本书籍,或其他学习方式,谢谢

    来自哈尔滨
  6. 绿色圣光 [Firefox 45.0|GNU/Linux] 的头像
    绿色圣光 [Firefox 45.0|GNU/Linux]

    我也装上那个扩展试试。

    来自青岛
  7. 来自浙江杭州的 Firefox 45.0|GNU/Linux 用户 的头像
    来自浙江杭州的 Firefox 45.0|GNU/Linux 用户

    鸟哥的linux私房菜基础篇,

    来自杭州

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注