nginx。如何拒绝对未列出的 ssl 虚拟服务器的请求?

and*_*dbi 18 ssl nginx virtualhost ssl-certificate

我在同一个 IP 上有一个通配符 SSL 证书和几个子域。现在我希望我的 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;
  //}
}
Run Code Online (Sandbox Code Playgroud)

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

ice*_*box 22

这个时候,这个问题的答案就可以更新了。

\n

对于 Nginx \xe2\x89\xa5 1.19.4:\n http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_reject_handshake

\n
server {\n    listen               443 ssl default_server;\n    ssl_reject_handshake on;\n}\n\nserver {\n    listen              443 ssl;\n    server_name         example.com;\n    ssl_certificate     example.com.crt;\n    ssl_certificate_key example.com.key;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
http {\n    # control options\n    strict_sni on;\n    strict_sni_header on;\n\n    # fake server block\n    server {\n        server_name  localhost;\n        listen       80;\n        listen       443 ssl default_server; # "default_server" is necessary\n        ssl_certificate /root/cert.crt; # Can be any certificate here\n        ssl_certificate_key /root/cert.key; # Can be any certificate here\n\n        location / {\n            return 444;\n        }\n    }\n\n    # normal server blocks\n    server {\n        server_name  normal_domain.tld;\n        listen       80;\n        listen       443 ssl;\n        ssl_certificate /root/cert.crt; # Your real certificate here\n        ssl_certificate_key /root/cert/cert.key; # Your real certificate here\n\n        location / {\n            echo "Hello World!";   \n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

对于不熟悉将补丁应用到 Nginx 的新手,可以查看: https: //stackoverflow.com/questions/64225024/64225025#64225025

\n


小智 18

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

server {
    ...

    if ($host !~* ^validname\.domain\.com$ ) {
        return 444;
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

注意:是的,通常if是邪恶的,但if在这种情况下使用是安全的。(如果您需要说服自己,请阅读链接页面。)

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

server {
    listen 80;
    listen 443 ssl;
    return 444;
}
Run Code Online (Sandbox Code Playgroud)

因为匹配的 SSL 证书validname.domain.com不会匹配某个随机域名。我已经试过了,nginx 表现得就像块根本不存在一样。

这也行不通:

server {
    listen       443;
    server_name    _;
    return 444; 
}
Run Code Online (Sandbox Code Playgroud)

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


cjc*_*cjc 7

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

  • 这不是真的:您可以在较低级别执行其他操作,例如在没有任何响应的情况下断开连接,如其他答案中所述。 (3认同)

小智 7

这里的大多数答案都是关于为什么它不起作用,而不是如何使它起作用。

以下是方法 - 您需要将这种全能服务器设置为“default_server”,并需要提供证书/密钥的路径,以便它可以解密传入的 ssl 请求并匹配 Host 标头:

server {
    listen 80 default_server;
    listen 443 ssl default_server;
    server_name _;
    ssl_certificate <path to cert>;
    ssl_certificate_key <path to key>;
    return 404;
}
Run Code Online (Sandbox Code Playgroud)

注意那里的 ssl_certificate/ssl_certificate_key。如果未指定它们,nginx 仍会尝试使用此类 default_server 并失败,因为它无法接受带 oa cert/key 的 ssl 连接。可以使用任何证书/密钥,例如自签名。...

生成自签名证书:

openssl req -x509 -newkey rsa:4096 -nodes -out cert.pem -keyout key.pem -days 365 
Run Code Online (Sandbox Code Playgroud)

另见https://serverfault.com/a/841643/87439