nginx:如何防止完全命名的 SSL 服务器块充当所有 SSL 的万能包

nginx:如何防止完全命名的 SSL 服务器块充当所有 SSL 的万能包

我有一个包含许多虚拟服务器的 Web 服务器。其中只有 1 个是 SSL。问题是,由于没有监听 SSL 的万能服务器块,因此对其他站点的任何 https 请求都由 1 个 SSL 块提供服务。

我的配置基本上是这样的:

# the catch all
server {
  listen 80 default;

  # I could add this, but since I have no default cert, I cannot enable SSL,
  # and this listen ends up doing nothing (apparently).
  # listen 443; 

  server_name _;
  # ...
}

# some server
server {
  listen 80;
  server_name server1.com;
  # ...
}

# some other server ...
server {
  listen 80;
  server_name server2.com;
  # ...
}

# ... and it's https equivalent
server {
  listen 443;
  ssl on;
  server_name server2.com;
  # ...
}

现在,由于没有 443 的默认侦听器,类似这样的请求https://server1.com最终将由server2.comhttps 块处理。这遵循server_name文档。

如果没有匹配,则将根据以下顺序使用配置文件中的 server { ... } 块:

  1. 具有匹配的 listen 指令的服务器块标记为 [default|default_server]
  2. 第一个具有匹配的 listen 指令(或隐式 listen 80;)的服务器块

这个问题的首选解决方案是什么?我是否需要为我的捕获所有服务器块设置虚拟证书,以便我可以监听 443 并处理不良请求?是否有我不知道的参数强制使用精确的主机名匹配server

答案1

理想情况下,我希望 nginx 根本不提供 https 服务,除非主机名匹配,或者让它重定向到同一主机上的 http。

两者都不可能。来自客户端的连接https://foo.example.com/除名称之一为“foo.example.com”的 SSL 证书外,其他证书均无法接受。在 SSL 连接被接受之前,没有重定向的机会。

如果您为每个站点配置 SSL,则用户点击证书错误后将获得他们请求的站点。如果您为 SSL 配置一个“全部捕获”站点,该站点仅提供错误页面,并为应该支持 SSL 的一个站点配置基于名称的虚拟主机,则可以向客户端提供错误页面。

SSL 和 HTTP 虚拟主机无法很好地协同运行。

答案2

唯一的方法是创建自签名 SSL 证书并使用它来控制传入的 https 请求。您可以通过几个简单的步骤创建自签名 SSL 证书这篇文章中概述

假设您创建了一个文件名为 server.crt 的自签名证书。然后,您需要在 nginx 配置中附加以下内容:

server {
    listen  443;

    ssl    on;
    ssl_certificate         /etc/nginx/ssl/server.crt;
    ssl_certificate_key     /etc/nginx/ssl/server.key;

    server_name server1.com;

    keepalive_timeout 60;
    rewrite ^       http://$server_name$request_uri? permanent;
}

您仍然会收到浏览器 SSL 警告消息,但至少您可以控制接下来发生的情况。

答案3

这就是我解决问题的方法:

  1. 创建自签名证书:

openssl req -nodes -x509 -newkey rsa:4096 -keyout self_key.pem -out self_cert.pem -days 3650

  1. 将其复制到 NginX 可以找到的地方:

cp self*.pem /etc/nginx/ssl/

  1. 设置一条捕获所有信息的路线:
server {
    listen 443 default_server ssl;

    ssl on;
    ssl_certificate /etc/nginx/ssl/self_cert.pem;
    ssl_certificate_key /etc/nginx/ssl/self_key.pem;

    return 301 http://$host;
}

这将做什么:它会给你警告(没有办法绕过它)在任何没有自己的证书的服务器上,但警告不会显示错误的证书名称。如果用户点击“仍然访问”,他们将被重定向到他们输入的站点的非 SSL 版本。

警告

如果您启用 SLL 的站点仅定义www.example.com(而没有定义example.com),那么您的捕获所有路由最终将https://example.com使用自签名证书和相应的警告提供服务。

答案4

现在您可以使用 TLS 服务器名称指示扩展 (SNI,RFC 6066)。HTTPS 侦听器将能够在提供适当的证书之前识别域名。

这意味着您需要为所有域名提供证书,并且当使用 SNI 识别其他域名之一时,您只需使用 HTTP 301 重定向到 HTTP 非加密版本,除非服务器名称与需要加密的单个域名匹配。

有关 SNI 的更多信息,请参阅 nginx 文档http://nginx.org/en/docs/http/configuring_https_servers.html

相关内容