Por que o Nginx ignora os pontos no cabeçalho “Host”?

2

Estou passando por um comportamento estranho no Nginx com solicitações que têm um ponto final no nome do host, ou seja, domain.com. em vez de domain.com sozinho. Eu configurei uma configuração de servidor simples para testar, assim:

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;
}

Inicialmente, esperava-se que as solicitações feitas para example.com. fossem enviadas para o primeiro bloco e as solicitações feitas para example.com fossem enviadas para o segundo. Solicitações cujo cabeçalho Host não corresponde a nenhum bloco, por exemplo, www.example.com , eu esperava ser enviado para o primeiro bloco novamente, pois era o padrão implícito.

No entanto, ao testar, descobri que as solicitações feitas para example.com. foram enviadas para o bloco segundo . Depois de brincar por um bom tempo com vários nomes alternativos, expressões regulares, etc. Eu decidi escrever a variável $host para um cabeçalho personalizado para que eu pudesse olhar para ele. Acontece que o Nginx está realmente soltando o ponto final do valor $host . Tanto quanto eu posso dizer que uma solicitação recebida em example.com. é considerada idêntica a uma recebida em example.com , pelo menos no que se refere à seleção de servidores. Isso parece indesejável, já que os pontos finais podem resultar em vários erros. .

Para tornar as coisas ainda mais confusas, depois de algum googling, encontrei a página de alterações do Nginx , que tem o changelog 0.1.29 :

Bugfix: nginx did not take into account trailing dot in "Host" header line.

Então, anos depois, o changelog 1.5.9 diz:

Bugfix: resolver did not understand domain names with a trailing dot. Thanks to Yichun Zhang.

Embora eu não tenha certeza se o "resolvedor" se refere a um componente do Nginx que está em jogo quando recebe uma requisição. (A partir da leitura dos documentos, parece que talvez o resolvedor não faça nada a menos que uma requisição esteja sendo desviada para algum outro host, cujo nome deve então ser resolvido.)

O que está acontecendo aqui? O Nginx deve estar perdendo o ponto final quando avaliar os nomes dos servidores? Se este for comportamento pretendido, o ponto final também não deve ser eliminado do parâmetro server_name para produzir um erro "nome do servidor em conflito"?

Sei que um nome de domínio sem um ponto final é tecnicamente um nome de domínio "relativo" em vez de "absoluto", embora a maioria das pessoas pareça tratá-los como todos em relação à . zone. Faça uma diferença prática. Mas não deveria Nginx, pelo menos, ser capaz de fazer essa distinção, se desejar?

Por fim, existe uma maneira melhor de capturar e redirecionar solicitações feitas para example.com. do que adicionar if ($http_host = 'domain.com.') ? Eu tenho disse que isso é ineficiente, pois exige que o cabeçalho Host seja avaliado duas vezes.

    
por Joseph Montanaro 07.04.2017 / 00:49

2 respostas

2

TLDR;

Isso parece um erro do Nginx, provavelmente porque poucas pessoas sabem que nomes de domínio totalmente qualificados terminam em um ponto.

Plano de fundo

Eu tive que ler sua declaração "nomes de domínio totalmente qualificados terminam com um ponto". Eu encontrei este recurso útil que explica isso muito bem. Há também uma pergunta e resposta do SF . Parece que apenas uma pequena minoria (inclusive eu até agora) sabia que um domínio poderia até ter um ponto final.

Nota

Observe que um "cabeçalho de host" e "Nginx server_name" são bem diferentes. O server_name define as solicitações que o servidor Nginx responderá. O "cabeçalho do host" faz parte do cabeçalho HTTP enviado pelo cliente para o servidor.

Exemplo

Eu tentei seus servidores de exemplo, com example.com mapeado para o meu servidor, com os mesmos resultados que você no nginx 1.9.11. Eu também tentei apenas com o servidor "example.com". definido, mas não "example.com". Quando enrolei essa configuração, recebi uma resposta do meu servidor padrão, em vez do "exemplo.com". servidor.

Documentação

A documentação do Nginx server_name não menciona um ponto final. A documentação permite um curinga após o ponto (example.com. *). Gostaria de saber se quem escreveu a documentação sabia sobre nomes de domínio totalmente qualificados.

Teoria

Eu tenho que saber, se você definir "example.com" e "example.com". em Nginx qual é a diferença? "exemplo.com" teria que ser considerado o URL completo da raiz do DNS, portanto, há uma suposição "." depois de qualquer maneira.

Conclusão

Eu acho que você está tecnicamente correto que o Nginx server_name deve atender ao ponto final. Não tenho certeza se deve tratar de forma diferente ou distinta de um server_name sem o ponto final, pelos motivos descritos acima.

Isso parece ser um erro no Nginx como resultado da supervisão. Também pode ser deliberado, baseado em práticas comuns, e não na RFC .

    
por 07.04.2017 / 01:25
2

No nível do DNS, example.com e example.com. são o mesmo nome. Isso não significa apenas que eles devem ser tratados da mesma forma, isso significa que ambos irão codificar exatamente a mesma seqüência de octetos em um pacote DNS. Tentar tratá-los como diferentes em protocolos que usam DNS (como, por exemplo, HTTP) é garantia de causar confusão e problemas.

Se um software usa nomes do DNS e trata o mesmo nome com e sem um ponto final como diferente, esse software tem um bug.

    
por 07.04.2017 / 08:12