当未为特定虚拟主机配置 HTTPS/SSL 并针对该虚拟主机的域启动 HTTPS 请求时,nginx 默认行为存在一个有趣的问题。我在 ISPConfig 安装上测试 Let's Encrypt 时发现了这个问题。
这是我的服务器配置:
- Debian 9(Stretch)
- nginx/1.10.3;使用 OpenSSL 1.1.0f 构建于 2017 年 5 月 25 日(使用 OpenSSL 1.1.0k 运行于 2019 年 5 月 28 日);已启用 TLS SNI 支持
现在的问题是:通过 HTTPS 请求未配置 SSL 的虚拟主机的网站会导致浏览器显示另一个配置为 HTTPS 的随机页面。到目前为止,我是这样想的:
- 请求服务器通过 HTTPS 加载域名 abc.com
- 由于此虚拟主机未配置 HTTPS / SSL,但请求了 HTTPS 连接,因此服务器正在查找配置了 HTTPS / SSL 并标记为“default_server”的虚拟主机
- 由于没有这样的虚拟主机(因为没有域名,所以没有有效的证书,所以不能),nginx 正在从随机虚拟主机(例如 xyz.com)建立与 SSL 证书的 HTTPS 连接
- 这会导致某些浏览器显示安全警告,即颁发证书的 CN 不是请求的域。忽略安全警告将通过 HTTPS 加载证书中提到的 xyz.com。其他浏览器会直接重定向到此域,而不会发出任何警告。
出于安全考虑,浏览器行为是正确的。
我的问题:
如果未配置 HTTPS,是否可以配置 nginx 以通过 HTTP 传送网站?如果没有,我该如何返回 503 而不是使用随机证书。
答案1
如果未配置 HTTPS,是否可以配置 nginx 通过 HTTP 提供网站
不。如果客户端连接到端口 443,希望使用 TLS,它将要讲 TLS。如果 nginx 尝试发送其他类型的回复(而不是响应 TLS 握手),例如纯文本 HTTP 回复,则客户端的 TLS 库会将其作为无法识别/损坏的数据包拒绝。
如果不是,我该如何返回 503 而不是使用随机证书。
也不是。当 nginx 在 HTTPS 端口上收到 TLS 握手时,它只有两个选择:要么使用其他证书完成握手,要么完全拒绝 TLS 握手。
它不能发送纯文本 HTTP 响应(它将被丢弃),也不能发送 HTTPS 响应,因为那是唯一可能的后TLS 握手——即后证书交换。
最简单的解决方案 — — 特别是如果你真的有安全顾虑 — — 是启用 HTTPS适用于所有虚拟主机。所有虚拟主机的证书均可免费获取。
廉价的解决方案是创建一个虚拟的“默认服务器”,它具有自己的证书(可以是自签名证书,例如example.com
或invalid.invalid
),并配置为在访问时始终返回 HTTP 错误。