关于Nginx开启SNI验证的方法

发布于 2023-08-03  144 次阅读


前言

3年后回过来看看,发现此文章有一些地方表达不清,修改的同时,顺便把单/多域名的实现方法合并在一起,免得臃肿

我来简单地介绍一下,开启SNI验证有啥用 :“在Nginx的默认SSL配置下,当客户端尝试建立TLS连接时发送的SNI不包含域名时,Nginx依旧会发送SSL/TLS证书给客户端,从而导致ip背后的域名信息泄露。此文主要介绍解决此问题的方法。”                       简而言之 ,就是能够防止别人通过抓包的方式,获取你的ip背后的域名信息(?)

注意事项

开启此功能后,如果你有使用CDN加速的必要,

必须开启CDN的SNI回源!

必须开启CDN的SNI回源!

必须开启CDN的SNI回源!

否则可能会导致各种5xx错误

如上图,输入你配置的域名即可

安装准备

  • 系统:Linux
  • 一台能上网的电脑
  • 一个正常的大脑
  • 一双手
  • 键盘 :lol:

一、安装过程

1.检查nginx模块

在终端中输入sudo nginx -V,你可以看到你当前nginx支持的模块

其中安装sni验证必须具备以下三个模块:

--with-stream
--with-stream_ssl_module
--with-stream_ssl_preread_module

如果有这三个模块,你就可以跳过1、2步骤啦;反之,则需要跟紧步伐 :lol:

2.下载源码包

再次输入sudo nginx -V,会得到(类似)下列信息:

nginx version: nginx/1.14.1   #你的nginx版本,记着
built by gcc 8.3.1 20190507 (Red Hat 8.3.1-4) (GCC) 
built with OpenSSL 1.1.1d  10 Sep 2019 (running with OpenSSL 1.1.1c FIPS  28 May 2019)
TLS SNI support enabled
configure arguments:  #已安装的模块
--prefix=/usr/local/nginx 
--with-http_stub_status_module 
--with-http_ssl_module 
--with-http_v2_module 
--with-http_gzip_static_module 
--with-http_sub_module 
--with-stream 
--with-stream_ssl_preread_module 
--with-stream_ssl_module 
--with-cc-opt=-DTCP_FASTOPEN=23

注意!如果你不想升级nginx,则请将下面的命令中的1.14.1替换为你的Nginx版本!

在终端输入:

wget http://nginx.org/download/nginx-1.14.1.tar.gz|将1.14.1改为你的Nginx版本 :neutral:

下载可能会有点慢哈 :???: ,期间可以喝杯茶~ :oops:

3.编译源码

这是最关键的一步!能不能成功安装就看这一步

将下载下来的源码压缩包解压缩

tar -zxvf nginx-1.14.1.tar.gz |记得将1.14.1改为你的版本
cd nginx-1.14.1               |同上

配置

sudo ./configure --with-http_stub_status_module --with-http_ssl_module --with-http_v2_module --with-http_gzip_static_module --with-http_sub_module --with-stream --with-stream_ssl_preread_module --with-stream_ssl_module

最后

sudo make
sudo make install

检查编译是否成功:

如果到最后提示make [1],就表明此次编译是成功的,反之,则是失败的

二、配置文件

每个人的nginx配置文件目录各有不同 :smile:  ,我的就是在/usr/local/nginx/conf

进入配置文件所在目录,并编辑:

cd /usr/local/nginx/conf 
sudo vim nginx.conf |每个人的配置文件也不同,有些是vhost的配置文件

SNI验证可以单域名亦可多域名,咱先介绍单域名的配置方法

单域名

在nginx.conf最后一个括号后加上:

stream {
    map $ssl_preread_server_name $name 
    { 
        backend.example.com      web;   #把backend.example.com 改成你想开启SNI验证的域名
        default                  block; #只要sni name 不正确就断开连接
    }

    upstream web 
    {
        server 127.0.0.1:444;
    }

    upstream block 
    {
        server 127.0.0.1:81;
    }

    server 
    {    
        listen      443 reuseport; 
        listen [::]:443 reuseport;
        proxy_pass  $name;
        ssl_preread on; #同上
    }

    server {
        listen 81;
        listen [::]:81;
        return 444;
    }
}

多域名

stream { 
    map $ssl_preread_server_name $name 
    { 
        #根据ssl sni name选择策略 #比如我想对cannon.org.cn开启sni验证,则: 
        cannon.org.cn web; 
        #我还想对blog.cannon.org.cn开启sni验证: 
        blog.cannon.org.cn web; 
        #以此类推,其他域名的添加方法也是如此 #格式:域名+(空格)web;(别忘记加;) 
        default block; 
        #只要sni name 不正确就断开连接 
    }  
    upstream web 
    { 
        server 127.0.0.1:444; #正常的Web服务 
    } 
    upstream block { 
        server 127.0.0.1:81; #用于阻止不合法请求 
    } 
    server 
    { 
        listen 443 reuseport; 
        listen [::]:443 reuseport; 
        proxy_pass $name; 
        ssl_preread on; #开启ssl_preread 
    }
    server 
    {
        listen 81;
        listen [::]:81;
        return 444;
    } 
}

对于这套实现方法,咱觉得挺像C里面switch,如果Client不提供或者提供的SNI不正确,则跳转到端口号为81的server块返回444状态码并拒绝访问,规避一些安全漏洞

三、启动nginx

在终端中输入:

sudo nginx -t

如出现xxxxxxxx test is successful,则说明配置木有问题,反之则需要查错(发在评论区上可以让大家一起帮你查错 :cool: )

最后,重启:

Ubuntu 18.04,centos7及以上:
systemctl restart nginx
以下的我就不知道了

参考文献


世界上本没有博客,直到有了程序员