Nginx开启TLS SNI支持多SSL证书
在为本域名添加SSL证书之后发现访问之前添加SSL的域名访问突然提示:
此服务器无法证明它是sharuru.space;其安全证书来自zer.moe。出现此问题的原因可能是配置有误或您的连接被拦截了。
经过查询后发现是因为”SSLv2的设计顺应经典的公钥基础设施PKI(public key infrastructure)设计,后者认为一个服务器只提供一个服务从而也就只使用一个证书。这意味着服务器可以在TLS启动的早期阶段发送或提交证书,因为它知道它在为哪个域服务。”
但是现在虚拟主机发展迅速很多都是一台主机对应多个域名但是SSL的连接方式是:建立SSL连接->发送HTTP请求,在建立SSL连接的时候根本不知道是哪个域名,所以服务端通常会返回配置中第一个可用证书。 这也就导致了当nginx配置如下时访问https://zer.moe一切正常,而访问https://sharuru.space的时候会提示证书错误,因为返回的证书是来自配置中第一个zer.moe的证书。
server { listen 443; server_name zer.moe; ssl on; ssl_certificate zer.crt; ssl_certificate_key zer.key; ... } server { listen 443; server_name sharuru.space; ssl on; ssl_certificate sharuru.crt; ssl_certificate_key sharuru.key; ... }
所以在2004年,EdelKey project为OpenSSL里面的TLS/SNI开发了一个补丁。2006年这个补丁进入OpenSSL的开发分支,2007年,它被向后移植到了OpenSSL 0.9.8,也就是当前的发行版本。
SNI(Server Name Indication)定义在RFC 4366,是一项用于改善SSL/TLS的技术,在SSLv3/TLSv1中被启用。它允许客户端在发起SSL握手请求时(具体说来,是客户端发出SSL请求中的ClientHello阶段),就提交请求的Host信息,使得服务器能够切换到正确的域并返回相应的证书。
但是正常情况下默认编译或者是apt yum安装的是默认关闭TLS SNI的,用nginx -V来查看自己的nginx是否开启了TLS SNI:
# /usr/local/nginx/sbin/nginx -V ... TLS SNI support disabled ...
显示TLS SNI support disabled所以我们需要来手动编译一下nginx并把支持SNI的OpenSSL添加进去。
# wget http://www.openssl.org/source/openssl-1.0.2d.tar.gz # tar zxvf openssl-1.0.2d.tar.gz # wget http://nginx.org/download/nginx-1.9.6.tar.gz # tar nginx-1.9.6.tar.gz # cd nginx-1.9.6 #./configure --prefix=/usr/local/nginx \ ... --with-http_ssl_module \ --with-openssl=../openssl-1.0.2d/ # make && make install
经过几分钟的等待之后编译完成,再执行nginx -V查看一下。
# /usr/local/nginx/sbin/nginx -V nginx version: nginx/1.9.6 built by gcc 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04) built with OpenSSL 1.0.2d 9 Jul 2015 TLS SNI support enabled configure arguments: --prefix=/usr/local/nginx --with-openssl=../openssl-1.0.2d/ --with-http_ssl_module
这时候SNI就开启完成了,再次访问之后就不会再出现证书错误了。
不过需要注意的一点就是只有以下版本及更高版本的浏览器才支持SNI:
- Internet Explorer 7
- Mozilla Firefox 2.0
- Opera 8.0
- Google Chrome
- Safari 3.2.1
杀个花先