Nginx と https - server_name として IP アドレスを指定すると、正しい Web サイトが表示されますが、証明書が間違っています

Nginx と https - server_name として IP アドレスを指定すると、正しい Web サイトが表示されますが、証明書が間違っています

この URL を実行したい:https://192.168.1.254アドレスバーに正しいコンテンツと証明書があるウェブサイトを取得します。ウェブサイトは取得できますが、証明書が別のサーバーブロックから取得されているため、アドレスバーに無効な証明書エラーが表示されます。デフォルトサーバーブロック000-デフォルト.conf

誰かこの動作を説明してくれませんか?

私のクライアントブラウザは、Google Chrome バージョン 87.0.4280.88 (公式ビルド) (64 ビット) です。

私の 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が明らかに許可していないことに関係していると思う「ホスト名」としてのリテラル IPv4 および IPv6 アドレスしかし、本当にそうなのでしょうか?

デフォルトのサーバーブロックがあります000-デフォルト.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アドレスバーに入力すると、正しい Web ページが表示されます。

私にはこの 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ご覧のとおり、このブロックとデフォルトのサーバー ブロックには同じ証明書/キー ペアがあります。

しかし、そのIPアドレスをserver_nameから削除するとluci-https.conf次の server_name として追加します。マイサイト.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証明書ではありません:マイサイトからマイサイト.lan.conf予想通り。

入れると…

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

デフォルトのサーバーブロック内000-デフォルト.conf代わりにその証明書を取得できますhttps://192.168.1.254ブラウザのアドレスバーに192.168.1.254がserver_nameとして指定されているかどうかluci-https.confまたはマイサイト.lan.conf

つまり、SNI は IP アドレスである「ホスト名」に一致するようですが、証明書はデフォルトのサーバー ブロックから取得されます。なぜでしょうか?

答え1

... SNI では、リテラル IPv4 および IPv6 アドレスを「ホスト名」として使用できないようです。しかし、本当にそうなのでしょうか?

SNIの背後にある考え方は、同じIPアドレス上の複数のドメインを区別することです。IPアドレスでSNIを使用することは、あまり意味がありません。したがって、実際のホスト名に限定されます。引用元:RFC 6066:

「HostName」には完全修飾名が含まれますDNSホスト名クライアントが理解するサーバーの... 「HostName」ではリテラル 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。ヘッダーは IP アドレスを指定するためHost(URL も指定するため)、この特定の仮想ホストと一致します。したがって、証明書は間違っていますが、コンテンツは正しいです。

関連情報