在Nginx的默认SSL配置下,当客户端尝试建立TLS连接时发送的SNI不包含域名时,Nginx依旧会发送SSL/TLS证书给客户端,从而导致ip背后的域名信息泄露。此文主要介绍解决此问题的方法。(方法不完美,谨慎使用)


为了阻止Nginx发送证书给不合法的客户端,以下三个模块是必须的。

--with-stream
--with-stream_ssl_module
--with-stream_ssl_preread_module
sudo nginx -V
参看nginx具体包含的模块等信息

然后修改nginx.conf

sudo nano /etc/nginx/nginx.conf
stream {
map $ssl_preread_server_name $name { #根据ssl sni name选择策略
    backend.example.com      web; #把backend.example.com 改成你的
    default                  block; #只要sni name 不正确就断开连接
	}

upstream web {
    server 127.0.0.1:444; #正常的Web服务
	}

upstream block {
    server 127.0.0.1:80; #用于阻止不合法请求
	}

server {
    listen      443 reuseport; 
    listen [::]:443 reuseport;
    proxy_pass  $name;
    ssl_preread on; #开启ssl_preread
	}
}
添加在nginx.conf最后

然后修改nginx server 配置

server {
    listen 127.0.0.1:444 ssl http2; #端口号和stream中的要一样
    ssl_certificate       /path/to/example.crt;
    ssl_certificate_key   /path/to/example.key;
    ssl_trusted_certificate /path/to/example.ca-bundle;
    ssl_protocols         TLSv1.3 TLSv1.2;
    ssl_prefer_server_ciphers off;
    ssl_early_data on;
    ssl_ciphers         'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256';
    ssl_session_cache   shared:SSL:40m;
    ssl_session_timeout 4h;
    ssl_session_tickets off;
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.4.4;
    resolver_timeout 10s;
    ssl_dhparam /etc/nginx/nginx.pem;
    server_name           example.com;
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
    if ($host != "example.com") {
        return 404;
    }
        location / {
            root /usr/share/nginx/html;
            index index.html;
        }
}

server {
    listen 80;
    listen [::]:80;
    server_name example.com;
    return 301 https://example.com;
}

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _; #不提供正确的域名直接断开连接
    return 444;
}

效果图

出现 This site works only in browsers with SNI support. 就表示成功了!!!