为什么 Nginx 忽略“Host”标头中的尾随点?

为什么 Nginx 忽略“Host”标头中的尾随点?

我在 Nginx 中遇到了一个奇怪的行为,请求的主机名后面有一个点,而domain.com.不是domain.com单独的一个。我设置了一个简单的服务器配置来测试,如下所示:

server {
    listen 80;
    server_name example.com.;
    root /var/www/example;
    index server1.txt;
}

server {
    listen 80;
    server_name example.com;
    root /var/www/example;
    index server2.txt;
}

最初,我预计对 的请求example.com.将被发送到第一个块,对 的请求example.com将被发送到第二个块。对于Host标头与任何块都不匹配的请求(例如)www.example.com,我预计会再次发送到第一个块,因为它是隐式默认值。

然而,经过测试,我发现,请求example.com.被发送到第二块。在尝试了各种替代名称、正则表达式等一段时间后,我决定将$host变量写入自定义标头,以便查看它。结果发现 Nginx 实际上是放下值的尾随点$host。据我所知,在 收到的请求example.com.被认为与在 收到的请求相同example.com,至少就服务器选择而言。这似乎是不可取的,因为尾随点可能会导致各种错误。

更令人困惑的是,经过谷歌搜索后我发现Nginx 更新日志页面,在 0.1.29 更新日志中有:

错误修复:nginx 没有考虑“Host”标题行中的尾随点。

几年后,1.5.9 更新日志写道:

错误修复:解析器无法理解带有尾随点的域名。感谢张亦春。

虽然我不确定“解析器”是否是指 Nginx 在收到请求时正在运行的组件。(从阅读文档来看,听起来解析器可能不会执行任何操作,除非将请求转发到其他主机,然后必须解析其名称。)

这是怎么回事?Nginx 在评估服务器名称时是否应该删除尾随的点?如果预期行为,是否也应该从参数中删除尾随的点server_name以产生“冲突的服务器名称”错误?

我知道,没有尾随点的域名在技术上是“相对”域名,而不是“绝对”域名,尽管现在大多数人似乎都将它们视为与区域相关的域名,.因此实际上没有区别。但如果需要,Nginx 至少应该能够做出这种区分吗?

最后,有没有example.com.比添加更好的方法来捕获和重定向对 的请求if ($http_host = 'domain.com.')?我一直在告诉这是低效的,因为它需要对Host标题进行两次评估。

答案1

在 DNS 级别,example.comexample.com.是同一个名称。这不仅仅意味着它们应该被同等对待,还意味着它们都将在 DNS 数据包中编码为完全相同的八位字节序列。在使用 DNS 的协议(例如 HTTP)中尝试将它们视为不同肯定会引起混乱和问题。

如果某个软件使用来自 DNS 的名称,并将带尾随点和不带尾随点的相同名称视为不同,则该软件存在缺陷。

答案2

TLDR;

这看起来像是一个 Nginx 错误,可能是因为很少有人知道完全合格的域名以点结尾。

背景

我必须仔细阅读你的陈述“完全合格的域名以点结尾”。我发现这一有用的资源这很好地解释了这一点。还有一个 SF这里有问答。似乎只有极少数人(直到现在包括我自己)知道域名后面还可以有一个点。

笔记

请注意,“主机头”和“Nginx 服务器名称”完全不同。服务器名称定义 Nginx 服务器将回复的请求。“主机头”是客户端发送给服务器的 http 头的一部分。

例子

我尝试了您的示例服务器,将 example.com 映射到我的服务器,结果与您在 nginx 1.9.11 上的结果相同。我还尝试了仅定义服务器“example.com.”但没有定义“example.com”。当我卷曲该配置时,我收到了来自我的默认服务器的响应,而不是“example.com.”服务器。

文档

Nginx server_name 文档没有提到结尾的点。文档允许在点后使用通配符 (example.com.*)。我想知道编写文档的人是否知道完全限定域名。

理论

不过,我不得不怀疑,如果你在 Nginx 中定义“example.com”和“example.com。”,它们有什么区别?“example.com”必须被假定为来自 DNS 根的完整 URL,因此它后面有一个假定的“。”。

结论

我认为从技术上来说,您可能是正确的,Nginx server_name 应该考虑尾随的点。出于上述原因,我不确定它是否应该将其与没有尾随点的 server_name 区别对待。

这似乎是由于疏忽而导致的 Nginx 错误。这也可能是故意的,基于常见做法,而不是请求函数

相关内容