HTTPS之SNI

SNI

SNI(Server Name Indication)是 TLS 的扩展,用来解决一个服务器拥有多个域名的情况。

在客户端和服务端建立 HTTPS 的过程中要先进行 TLS 握手,握手后会将 HTTP 报文使用协商好的密钥加密传输。

在 TLS 握手信息中并没有携带客户端要访问的目标地址。这样会导致一个问题,如果一台服务器有多个虚拟主机,且每个主机的域名不一样,使用了不一样的证书,该和哪台虚拟主机进行通信?

和 HTTP 协议用来解决服务器多域名的方案类似,HTTP 在请求头中使用 Host 字段来指定要访问的域名。TLS 的做法,也是加 Host,在 TLS 握手第一阶段 ClientHello 的报文中添加。

SNI 在 TLSv1.2 开始得到支持。从 OpenSSL 0.9.8 版本开始支持。所以基本市场上的终端设备都支持。

使用 WireShark 抓包看一下 ClientHello:

可以看到包中的 SNI 扩展字段:

1
2
3
4
5
6
7
8
Extension: server_name
Type: server_name (0x0000)
Length: 19
Server Name Indication extension
Server Name list length: 17
Server Name Type: host_name (0)
Server Name length: 14
Server Name: www.github.com

这里指定了该 TLS 握手的目标域名为 www.github.com 。
通过 SNI,拥有多虚拟机主机和多域名的服务器就可以正常建立 TLS 连接了。

nginx支持TLS协议的SNI扩展

nginx手册

JDK支持SNI扩展

默认为true

System.setProperty( “jsse.enableSNIExtension”, “true” );

jdk关于SNI支持的bug

1.8.141版本修复了

Custom HostnameVerifier disables SNI extension