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 是证书覆盖的名字,两者匹配连接才算有效。