配置

Nginx 1.19.4 新增了一个 ssl_reject_handshake 配置项,可以直接切断拒绝 SSL 握手请求,类似于返回 444 请求。而且它不需要强制要求 SSL 证书,这样也就无法通过 https 握手请求获取服务器的 SSL 信息了

新增加一个监听 443 端口的服务

1
2
3
4
server {
listen 443 ssl default_server;
ssl_reject_handshake on;
}

比如说:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#这里是新添加的443端口
server {
listen 443 ssl default_server;
ssl_reject_handshake on;
}


# 举例子,下面是原来的,不需要改动
server {
listen 443 ssl http2;

server_name example.com;
ssl_certificate /etc/nginx/conf.d/certs/example.com.crt;
ssl_certificate_key /etc/nginx/conf.d/certs/example.com.key;

注意

一定要新增加,如果添加到原有的 443 服务上,浏览器访问会出现 ERR_SSL_UNRECOGNIZED_NAME_ALERT

Nginx 版本要大于等于 1.19.4,可以通过 nginx -v 查看自己的版本信息

测试

ip 是你的服务器 ip

1
curl -v -k https://ip

比如说我的服务器套了 CDN,这样就无法直接得到我的服务器源站 ip 了,但是全球的 ipv4 地址是有限的,通过爬虫请求所有的 ipv4 地址,就会暴露出 SNI 信息,SNI 信息里面就可以看到你的证书和域名,这样也算是间接得知你的源站 ip 了

输入我的服务器 IP 进行测试,可以看到 subject 里包含了域名信息(subject: CN=v2try.com)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server accepted to use http/1.1
* Server certificate:
* subject: CN=v2try.com
* start date: Jul 21 00:00:00 2022 GMT
* expire date: Oct 19 23:59:59 2022 GMT
* issuer: C=AT; O=ZeroSSL; CN=ZeroSSL RSA Domain Secure Site CA
* SSL certificate verify ok.

开启配置项后再次测试

1
2
3
4
5
6
7
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS alert, unrecognized name (624):
* error:14094458:SSL routines:ssl3_read_bytes:tlsv1 unrecognized name
* Closing connection 0

关于 SNI

什么是 SNI 协议?

SNI 服务器名称指示(Server Name Indication)是为了解决一个服务器使用多个域名和证书的 TLS 扩展,主要解决一台服务器只能使用一个证书的缺点。开启 SNI 后,允许客户端在发起 SSL 握手请求时就提交请求的域名信息,负载均衡收到 SSL 请求后,会根据域名去查找证书,如果找到域名对应的证书,则返回该证书;如果没有找到域名对应的证书,则返回缺省证书。负载均衡在配置 HTTPS 监听器支持此功能,即支持绑定多个证书。

SNI 在 TLSv1.2 开始得到支持。从 OpenSSL 0.9.8 版本开始支持。

为什么需要使用 SNI 协议?

基于名称的虚拟主机允许多个 DNS 主机名由同一 IP 地址上的单个服务器(通常为 Web 服务器)托管。为了实现这一点,服务器使用客户端提供的主机名作为协议的一部分(对于 HTTP,名称显示在主机头中)。但是,当使用 HTTPS 时,TLS 握手发生在服务器看到任何 HTTP 头之前。因此,服务器不可能使用 HTTP 主机头中的信息来决定呈现哪个证书,并且因此只有由同一证书覆盖的名称才能由同一 IP 地址提供。

所以,需要由 SNI 协议在握手时提供主机名的信息。

了解 SNI 协议可以用来做什么?

如果我们要对流量进行识别,做流量检测等,HTTPS 流量是加密的,很难检测其内部的具体内容。SNI 协议给出了一个切入点,在 HTTPS 协议建立加密连接的开始阶段检测出访问的域名信息。