术语表

SNI (服务器名称指示)

最后核实

定义

SNI 是 TLS 的一个扩展,客户端在 ClientHello 中写明要访问的域名,使同一个 IP 能为多个 HTTPS 站点分别返回各自的证书。

SNI(Server Name Indication)是 RFC 6066 定义的 server_name 扩展。客户端在握手的第一条消息 ClientHello 里带上要访问的域名,服务器据此挑选对应的证书和虚拟主机。按规范这个字段只能填域名,不能填 IP 地址。

为什么重要

没有 SNI 时,服务器要等握手结束、读到 HTTP 的 Host 头才知道访问的是哪个站点,所以一个 IP 加端口只能挂一张证书。共享虚拟主机、CDN、负载均衡能在同一个 IP 上承载大量 HTTPS 站点,靠的就是 SNI;在 Nginx 或宝塔面板里给多个站点各配一张证书,背后也是按 SNI 分流。客户端没发 SNI,或发了服务器不认识的名字,服务器就返回默认站点的证书,浏览器随即报证书域名不匹配。另外 SNI 是明文传输的,即使在 TLS 1.3 中也一样,链路上的设备能看到访问的域名;要隐藏它需要 ECH。

例子

对同一个 IP 指定 SNI,查看返回的证书:

openssl s_client -connect 203.0.113.10:443 -servername example.com </dev/null 2>/dev/null \
  | openssl x509 -noout -subject -ext subjectAltName

去掉 -servername 再执行一次。如果拿到的是另一张证书,说明服务器按 SNI 选证书,第二张就是它的默认证书。

常见误区

  • 每个 HTTPS 站点都要独立 IP。 这是 SNI 普及之前的情况。如今主流浏览器和 HTTP 客户端都会发送 SNI,多张证书完全可以共用一个 IP。
  • TLS 1.3 把 SNI 加密了。 没有。TLS 1.3 加密了服务器证书,但 SNI 仍是明文,要加密得靠 ECH。
  • SNI 就是证书里的 SAN。 SNI 是客户端请求的名字,SAN 是证书覆盖的名字,两者匹配连接才算有效。

延伸阅读