配置虚拟默认 vhost 并防止虚拟主机使用 https 请求回退到 IP-PD 主机

配置虚拟默认 vhost 并防止虚拟主机使用 https 请求回退到 IP-PD 主机

背景

考虑 4 个假设的 FQDN,它们都解析为 192.0.2.42:

现在,考虑两个假设的服务器绑定到 192.0.2.42(显然,不是同时的......我只是说明两种不同的情况):

  • 服务器有一个默认的“站点”。任何指向解析为服务器 IP 地址的 FQDN 端口 443 的 https 请求最终都会映射到该 IP 地址。

  • 服务器已启用基于名称的虚拟主机。example.com 和www.example.com是全部捕获的默认值。foo.example.org 和 legacy.example.net 被映射到另外两个虚拟主机。

问题:

请求https://example.comhttps://www.example.comhttps://foo.example.org, 和https://legacy.example.net一切按预期进行......但也存在两个不良的副作用:

  • https://192.0.2.42(RFC-9110 称之为“IP-PD 参考标识“) 在浏览器显示警告且用户将其删除后,将转到默认站点。Strict-Transport-Security 标头无法挽救局面。

  • 攻击者可以将其控制的域(例如“badguys.example”)指向 192.0.2.42,并将用户发送到https://badguys.example,并且(假设实际的 FQDN 不是那么明显,浏览器本身有错误,和/或用户是个十足的白痴),并且与 192.0.2.42 相同的场景也会出现。再一次,STS 无法挽救局面。

解决方案(魔鬼藏在细节中)

据我了解,正确的解决方案如下:

  • 如果尚未完成,请启用基于名称的虚拟主机。

  • 创建一个“虚拟默认”虚拟主机,捕获所有未明确映射到“真实”虚拟主机之一的请求。

  • 配置 SNI。除其他事项外,默认虚拟主机负责向 example.com 提供 TLS 证书,www.example.com、foo.example.org 和 SAN 中的 legacy.example.net

血腥的细节?

  • 默认 vhost 需要一个自己的唯一 FQDN,该 FQDN 解析为 192.0.2.42(而不是 127.0.0.1 或其他 IP 地址……否则,SNI 将失败。)对吗?

  • 它不必是全球 DNS 可解析的……只需将其塞入运行 Apache(或 Nginx、Tomcat 或任何正在运行的服务器)的 /etc/hosts 中就足够了。对吗?

  • 默认虚拟主机的 FQDN(例如“default999.example.com”)需要与其他 4 个名称一起位于 SAN 中。否则,当 Apache(或其他程序)启动时,它会对其默认主机的证书进行健全性检查,如果一切不 100% 完美,就会出错。对吗?

  • 事实上,它必须是组织控制下的 TLD 的子域(例如“default999.example.com”),因为没有 CA 会允许您将理论上无法通过 DNS 解析且不在您明显拥有和控制的 TLD 下的 IP 地址或主机名粘贴到 SAN 中。对吗?

  • 假设默认 vhost 的期望行为是“通过返回 4xx 状态代码来处理所有请求”......事实上哪一个是最合适的?

    • 421?
    • 422?
    • 400?

在我真正仔细研究 4xx 响应代码列表之前,我认为一定至少有一个是专门与 vhosts 相关并且明确表示为这样的意思,“您向一个 URL 发出了一个 http(s) 请求,该 URL 的 FQDN 解析为此服务器的 IP 地址,但该服务器尚未将其映射到站点,因此返回此错误。”

但……据我所知,自 Apache 首次推出基于名称的虚拟主机以来的大约 25 年里,没有任何 IETF(或微软、Apache 或任何其他人)成员认为特定于他们的错误足够重要,值得拥有自己的正确 http 响应代码。421 或 422几乎似乎匹配...但在阅读了他们的官方定义后(RFC 9110), 我不确定。

  • 这听起来像421仅适用于用户代理合并同一服务器上两个 vhost 的请求但服务器本身拒绝允许合并的场景中的 http2 请求。

  • 这听起来像422仅用于将对服务器的请求编码为请求正文中的 xml

  • 我在这里看到过一些帖子提到 404... 但对我来说,404总是意思是“网站好,文件坏”。也许我有点吹毛求疵,但当主机本身是无效的。

那么...400(无效主机)听起来是最好的选择,或者有人能想到更好的选择吗?

最后...回到最重要的问题的一部分...我是否正确地指出必须为默认 vhost 提供一个在 SAN 中列出的真实 fqdn?至少对于 Apache、Nginx 和 IIS 来说是这样?

相关内容