Nginx

Nginx 和 https - 將 ip 地址指定為 server_name 會提供正確的網站但錯誤的證書

  • December 23, 2020

我想執行這個網址:https ://192.168.1.254並在地址欄中獲取一個具有正確內容和證書的網站。我正在獲取該網站,但在地址欄中出現無效證書錯誤,因為該證書取自不同的伺服器塊:預設伺服器塊000-default.conf

有人可以向我解釋這種行為嗎?

我的客戶端瀏覽器是 Google Chrome 版本 87.0.4280.88 (Official Build) (64-bit)

我的 Nginx 伺服器是:

root@OpenWrt:/etc/nginx/conf.d# nginx -V
nginx version: nginx/1.19.4 (x86_64-pc-linux-gnu)
built with OpenSSL 1.1.1h  22 Sep 2020
TLS SNI support enabled

我認為這個問題與 SNI 顯然不允許將 Literal IPv4 和 IPv6 地址作為 “HostName” 的方式有關。但真的是這樣嗎?

我有一個預設伺服器塊000-default.conf,如下所示:

server {
   server_name _;
   listen 80 default_server;
   listen 443 ssl default_server;

   ## To also support IPv6, uncomment this block
   # listen [::]:80 default_server;
   # listen [::]:443 ssl default_server;

   ssl_certificate '/etc/nginx/conf.d/_lan.crt';
   ssl_certificate_key '/etc/nginx/conf.d/_lan.key';
   return 404; # or whatever
}

另一個名為 luci-http.conf 的伺服器是這樣的:

server {
       listen 80;
       listen [::]:80;
       server_name openwrt.lan 192.168.1.254;
       # access_log /proc/self/fd/1 openwrt; # use logd (init forwards stdout).
       include conf.d/*.locations;
}

當我將http://192.168.1.254放在地址欄中時,它會為我提供正確的網頁。

我也有這個 https 伺服器: luci-https.conf

server {
       listen 443 ssl;
       listen [::]:443 ssl;

       server_name openwrt.lan 192.168.1.254;
       #include '/var/lib/nginx/lan_ssl.listen.default';
       ssl_certificate '/etc/nginx/conf.d/_lan.crt';
       ssl_certificate_key '/etc/nginx/conf.d/_lan.key';
       ssl_session_cache 'shared:SSL:32k';
       ssl_session_timeout '64m';
       # access_log /proc/self/fd/1 openwrt; # use logd (init forwards stdout).
       include conf.d/*.locations;
}

當我將https://192.168.1.254放在地址欄中時,它會為我提供正確的網頁和**_lan.crt**中的證書。如您所見,我在此和預設伺服器塊中有相同的證書/密鑰對。

但是,當我從luci-https.conf中刪除該 IP 地址作為 server_name並將其添加為 server_name 時:mysite.lan.conf我沒有看到相同的行為。

server {
       listen 443 ssl;
       listen [::]:443 ssl;
       #listen 192.168.1.254 ssl;
       #include '/var/lib/nginx/lan_ssl.listen';

       server_name mysite.lan www.mysite.lan fun.mysite.lan 192.168.1.254;

       root /www/mysite;
       index index.html index.htm index.nginx-debian.html;

       ssl_certificate '/etc/nginx/conf.d/mysite.lan.crt';
       ssl_certificate_key '/etc/nginx/conf.d/mysite.lan.key';
       ssl_session_cache 'shared:SSL:32k';
       ssl_session_timeout '64m';

       location / {
               try_files $uri $uri/ =404;
       }

       access_log /var/log/nginx/mysite.lan.access.log;
       error_log /var/log/nginx/mysite.lan.error.log;
}

現在,當我將https://192.168.1.254放在地址欄中時,它會為我提供正確的網頁,但再次是**_lan.crt中的證書,而不是mysite.lan.conf中的mysite.lan.crt**。

當我放..

ssl_certificate '/etc/nginx/conf.d/mysite.lan.crt';
ssl_certificate_key '/etc/nginx/conf.d/mysite.lan.key';

在預設伺服器塊000-default.conf中,然後當我將https://192.168.1.254放在瀏覽器地址欄中時,我得到了該證書,無論 192.168.1.254 是否被指定為luci-https.confmysite.lan中的 server_name .conf

因此,SNI 似乎將匹配作為 IP 地址的“主機名”,但它從預設伺服器塊獲取證書。這是為什麼?

… SNI 顯然不允許將文字 IPv4 和 IPv6 地址作為“主機名”。但真的是這樣嗎?

SNI 背後的想法是區分同一 IP 地址上的多個域。到目前為止,使用帶有 IP 地址的 SNI 並沒有真正的意義。因此,它也僅限於實際主機名。從RFC 6066引用:

“HostName”包含客戶端所理解的伺服器的完全限定DNS 主機名。“主機名”中不允許使用文字 IPv4 和 IPv6 地址

    server_name mysite.lan www.mysite.lan fun.mysite.lan 192.168.1.254;

因此,SNI 似乎將匹配作為 IP 地址的“主機名”,但它從預設伺服器塊獲取證書。

由於 SNI 僅用於實際主機名,因此 TLS 握手中沒有 SNI,因此使用預設的 HTTPS 配置。在 HTTPS 內部有 HTTP 協議,但它包含Host標頭。由於Host標頭指定了 IP 地址(因為 URL 確實如此),它將匹配這個特定的虛擬主機。因此:錯誤的證書,正確的內容。

引用自:https://serverfault.com/questions/1047374