Nginx. 如何拒绝对未列出的 SSL 虚拟服务器的请求?

Nginx. 如何拒绝对未列出的 SSL 虚拟服务器的请求?

我有一个通配符 SSL 证书和多个子域位于同一个 IP 上。现在我希望我的 nginx 只处理提到的服务器名称并断开其他服务器的连接,这样它看起来就好像 nginx没有为未列出的服务器名称运行(没有响应、拒绝、死机、没有一个字节的响应)。我做了以下事情

ssl_certificate         tls/domain.crt;
ssl_certificate_key     tls/domain.key;

server {
  listen 1.2.3.4:443 ssl;
  server_name validname.domain.com;
  //
}

server {
  listen 1.2.3.4:443 ssl;
  server_name _;
  // deny all;
  // return 444;
  // return 404;
  //location {
  //  deny all;
  //}
}

我几乎尝试了最后一个服务器块中的所有方法,但都没有成功。我收到了来自已知虚拟服务器的有效响应或错误代码。请帮忙。

答案1

它不是那样工作的:SSL 握手发生在 HTTP 之前,因此在您重定向或在 nginx 配置中执行任何其他操作之前,证书上的名称将在浏览器中进行评估。

答案2

此时,该问题的答案可以更新了。

对于 Nginx ≥ 1.19.4: http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_reject_handshake

server {
    listen               443 ssl default_server;
    ssl_reject_handshake on;
}

server {
    listen              443 ssl;
    server_name         example.com;
    ssl_certificate     example.com.crt;
    ssl_certificate_key example.com.key;
}

对于 Nginx < 1.19.4:使用https://git.hakase.app/Hakase/openssl-patch

http {
    # control options
    strict_sni on;
    strict_sni_header on;

    # fake server block
    server {
        server_name  localhost;
        listen       80;
        listen       443 ssl default_server; # "default_server" is necessary
        ssl_certificate /root/cert.crt; # Can be any certificate here
        ssl_certificate_key /root/cert.key; # Can be any certificate here

        location / {
            return 444;
        }
    }

    # normal server blocks
    server {
        server_name  normal_domain.tld;
        listen       80;
        listen       443 ssl;
        ssl_certificate /root/cert.crt; # Your real certificate here
        ssl_certificate_key /root/cert/cert.key; # Your real certificate here

        location / {
            echo "Hello World!";   
        }
    }
}

对于不熟悉如何将补丁应用于 Nginx 的新手,你可以检查一下:https://stackoverflow.com/questions/64225024/64225025#64225025

答案3

cjc 的回答已经正确指出了启用 SSL 时尝试匹配主机名的问题。但是,可以这样做,如下所示:

server {
    ...

    if ($host !~* ^validname\.domain\.com$ ) {
        return 444;
    }
    ...
}

注意:是的,一般来说if是邪恶的,但在这种情况下使用是安全的if。(如果您需要确认,请阅读链接页面。)

与建议相反,仅添加以下块是行不通的:

server {
    listen 80;
    listen 443 ssl;
    return 444;
}

因为匹配的 SSL 证书validname.domain.com不会匹配某个随机域名。我试过了,nginx 表现得好像根本没有阻止一样。

这也行不通:

server {
    listen       443;
    server_name    _;
    return 444; 
}

因为它将使每一个端口 443 上的 HTTPS 连接失败,甚至那些应该通过的也失败了。我也试过了。wget报告了 SSL 握手错误。

答案4

我今天实施了上述解决方案,效果非常好。现在所有未指定的 URL 都将被删除。将此服务器代码放在实际虚拟服务器条目之前是关键 - 所有格式错误的 URL 现在都会转到此“默认”服务器。

... 
server {
     listen       443;
     server_name    _;
     return 444; }

server {
     listen       443;
     server_name  [URL]

相关内容