摘要

  • RFC 2817 提议在已建立的 HTTP/1.1 连接上启动 TLS,让明文和加密流量都能走 80 端口;TLS 握手前的 Host 字段还能帮助服务器挑选虚拟主机证书。
  • 它保留了 https 独立的 URI 地址空间。RFC 作者在 2000 年直言,通用网页浏览对取代 443 端口的做法兴趣很小。

给一栋楼开两扇门,本来不算灾难。Web 的麻烦是,其他应用协议也可能照着办:普通服务占一扇,安全版本再占一扇。1997 年 12 月的 IETF 会议上,应用领域的负责人重申应结束这种成对分配“安全端口”的习惯。三年后的方案像一位想省房租的经理:老门照用,客人进来后再上锁。

2000 年 5 月的 RFC 2817给这套做法规定了 HTTP/1.1 Upgrade: TLS/1.0。一条已经通向 80 端口的 TCP 连接,可以从普通 HTTP 切换为 TLS 保护的 HTTP。它还试图解决另一道当时的题。Host 字段让多个网站共享一个 IP 地址,但先开始的 TLS 握手没法按这份方案所需的方式得知客户想访问哪个名字、该拿哪张证书。先用明文 HTTP 报出 Host,服务器就能在握手前选定虚拟主机。柜台先问名字,再装门锁。

协议没有让敏感请求冒险排在锁前面。RFC 2616把 Upgrade 定义为相邻 HTTP 节点之间的切换。客户如果接受明文答复,可以在普通请求中提出 TLS 选项;服务器也可照常明文回答。若明文答复不可接受,RFC 2817 要求客户先发 OPTIONS *。这一步是预演:锁谈妥之后,真正需要保护的请求才上路。

服务器同意切换时回复 101 Switching Protocols,列出 TLS/1.0, HTTP/1.1,并在响应头结束后转换协议。TLS 握手完成,再继续 HTTP 对话。服务器还可以用 426 Upgrade Required 说明资源必须使用哪种升级。426 只是柜台通知;客户仍要依照规定完成 Upgrade 交换。墙上贴“必须上锁”四个字,门不会自己咔哒一声关好。

代理服务器把走廊拉长了。Upgrade 只约束一跳:代理发出的 101 改变客户与代理的连接,源站发给代理的 101 则改变另一段。若要让 TLS 直达源站,RFC 2817 规定先用 CONNECT 穿过代理建隧道,目的端仍可以是 80 端口。收到成功的 2xx,客户才在隧道里与源站协商升级。同一个端口并没有把沿途每段连接揉成一段。

地址栏的问题更顽固。RFC 2817 明确让 http:// 与 https:// 保持不同的 URI 空间。同月发表的 RFC 2818记录既有路线:https 默认去 443 端口,先发 TLS ClientHello,握手后才传 HTTP,并按 URL 中的主机名检查证书。把两种传输方式放进同一扇网络门,并不会自动把两种地址合并。

RFC 2817 对自己的时代也很坦率。它说,人们普遍接受方案背后的想法,却很少有兴趣为一般网页浏览实现 443 的替代方案;新建在 HTTP 之上的应用,例如互联网打印,反而更需要这种机制。这是 2000 年文件中的观察,足以说明工程上的省门计划碰上了一条已经写进软件和链接的老路。

共享 80 端口有真实的诱惑:少占一批成对端口,利用 Host 选择证书,还能用 426 表达服务器的要求。它也必须经过明文前奏、明确的接受步骤和代理隧道,同时照顾 https 自己的地址。TLS 可以来敲 80 的门;443 的门牌已经印在请柬上。