服务器名称指示(Server Name Indication,SNI)是一种用于改进SSL/TLS协议的扩展。SNI允许客户端在TLS握手过程中指定它们正在尝试访问的主机名(域名),从而使服务器能够选择正确的证书以进行加密通信。这在托管多个SSL/TLS网站的服务器上特别有用,因为不同的网站可能需要不同的证书。

image

SNI的工作原理

  1. 客户端发送请求:客户端在TLS握手的初始阶段发送“ClientHello”消息时,会包含一个扩展字段,其中包括客户端试图访问的服务器的主机名。
  2. 服务器响应:服务器接收到“ClientHello”消息后,根据所请求的主机名选择并发送相应的SSL/TLS证书。
  3. 握手继续:客户端验证服务器提供的证书,并继续完成TLS握手过程,建立加密连接。

为什么需要SNI

在SNI之前,SSL/TLS握手过程中不包含主机名信息,因此服务器无法知道哪个证书应用于哪个网站。这对虚拟主机(多个网站托管在同一IP地址上)来说是个问题,因为无法在握手过程中选择正确的证书。

SNI的优点

  • 虚拟主机支持:允许在同一IP地址上托管多个使用不同SSL/TLS证书的网站。
  • 节省IP地址:减少了对独立IP地址的需求,从而节省了IPv4地址空间。
  • 增强安全性:不同网站可以使用不同的证书和加密标准。

支持SNI的浏览器和服务器

现代浏览器:大多数现代浏览器(如Chrome、Firefox、Edge、Safari等)都支持SNI。

服务器软件:许多服务器软件(如Apache、Nginx、IIS等)也支持SNI。

配置SNI

在服务器上配置SNI,通常需要设置虚拟主机和相应的证书。例如,在Nginx中配置SNI的示例:

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate /path/to/example.com.crt;
    ssl_certificate_key /path/to/example.com.key;

    ...
}

server {
    listen 443 ssl;
    server_name another-example.com;

    ssl_certificate /path/to/another-example.com.crt;
    ssl_certificate_key /path/to/another-example.com.key;

    ...
}

每个server块对应一个虚拟主机,服务器根据客户端请求的主机名选择相应的配置块和证书。

限制

  • 兼容性问题:非常旧的客户端(如老版本的浏览器或操作系统)可能不支持SNI,从而无法正确访问使用SNI的站点。
  • 加密域名泄漏:在TLS握手过程中,主机名以明文形式传输,这在某些安全场景下可能是个问题。

总之,SNI是解决虚拟主机SSL/TLS证书问题的关键技术,使得在同一IP地址上托管多个安全网站成为可能。