Preservar o nome de host HTTP original entre um proxy reverso e seu aplicativo Web back-end

Azure API Management
Azure App Service
Azure Application Gateway
Azure Front Door
Azure Spring Apps

Recomendamos que você preserve o nome de host HTTP original ao usar um proxy reverso na frente de um aplicativo Web. Ter um nome de host diferente no proxy reverso daquele que é fornecido ao servidor de aplicativos back-end pode levar a cookies ou redirecionar URLs que não funcionam corretamente. Por exemplo, o estado da sessão pode ser perdido, a autenticação pode falhar ou URLs de back-end podem ser inadvertidamente expostas aos usuários finais. Você pode evitar esses problemas preservando o nome do host da solicitação inicial para que o servidor de aplicativos veja o mesmo domínio que o navegador da Web.

Estas orientações aplicam-se especialmente a aplicações alojadas em ofertas de plataforma como serviço (PaaS), como o Serviço de Aplicações do Azure e as Aplicações Azure Spring. Este artigo fornece orientações de implementação específicas para o Azure Application Gateway, Azure Front Door e Azure API Management, que são serviços de proxy reverso comumente usados.

Nota

As APIs da Web geralmente são menos sensíveis aos problemas causados por incompatibilidades de nomes de host. Eles geralmente não dependem de cookies, a menos que você use cookies para proteger as comunicações entre um aplicativo de página única e sua API de back-end, por exemplo, em um padrão conhecido como Backends for Frontends. As APIs da Web geralmente não retornam URLs absolutas para si mesmas, exceto em determinados estilos de API, como Open Data Protocol (OData) e HATEOAS. Se a implementação da API depender de cookies ou gerar URLs absolutos, as orientações fornecidas neste artigo se aplicam.

Se você precisar de TLS/SSL de ponta a ponta (a conexão entre o proxy reverso e o serviço back-end usa HTTPS), o serviço back-end também precisará de um certificado TLS correspondente para o nome de host original. Esse requisito adiciona complexidade operacional quando você implanta e renova certificados, mas muitos serviços PaaS oferecem certificados TLS gratuitos que são totalmente gerenciados.

Contexto

O host de uma solicitação HTTP

Em muitos casos, o servidor de aplicativos ou algum componente no pipeline de solicitação precisa do nome de domínio da Internet que foi usado pelo navegador para acessá-lo. Este é o anfitrião do pedido. Pode ser um endereço IP, mas geralmente é um nome como contoso.com (que o navegador resolve para um endereço IP usando DNS). O valor do host normalmente é determinado a partir do componente host do URI de solicitação, que o navegador envia para o aplicativo como o Host cabeçalho HTTP.

Importante

Nunca use o valor do host em um mecanismo de segurança. O valor é fornecido pelo navegador ou por algum outro agente de usuário e pode ser facilmente manipulado por um usuário final.

Em alguns cenários, especialmente quando há um proxy reverso HTTP na cadeia de solicitações, o cabeçalho do host original pode ser alterado antes de chegar ao servidor de aplicativos. Um proxy reverso fecha a sessão de rede do cliente e configura uma nova conexão com o back-end. Nesta nova sessão, ele pode transferir o nome do host original da sessão do cliente ou definir um novo. Neste último caso, o proxy geralmente ainda envia o valor original do host em outros cabeçalhos HTTP, como Forwarded ou X-Forwarded-Host. Esse valor permite que os aplicativos determinem o nome do host original, mas somente se estiverem codificados para ler esses cabeçalhos.

Por que as plataformas da Web usam o nome do host

Os serviços PaaS multilocatários geralmente exigem um nome de host registrado e validado para rotear uma solicitação de entrada para o servidor back-end do locatário apropriado. Isso ocorre porque normalmente há um pool compartilhado de balanceadores de carga que aceitam solicitações de entrada para todos os locatários. Os locatários geralmente usam o nome do host de entrada para procurar o back-end correto para o locatário do cliente.

Para facilitar os primeiros passos, essas plataformas geralmente fornecem um domínio padrão pré-configurado para rotear o tráfego para sua instância implantada. Para o Serviço de Aplicativo, esse domínio padrão é azurewebsites.net. Cada aplicativo Web que você cria obtém seu próprio subdomínio, por exemplo, contoso.azurewebsites.net. Da mesma forma, o domínio padrão é azuremicroservices.io para o Azure Spring Apps e azure-api.net para o Gerenciamento de API.

Para implantações de produção, você não usa esses domínios padrão. Em vez disso, você fornece seu próprio domínio para se alinhar com a marca da sua organização ou aplicativo. Por exemplo, contoso.com pode resolver os bastidores do contoso.azurewebsites.net aplicativo Web no Serviço de Aplicativo, mas esse domínio não deve estar visível para um usuário final que visita o site. No entanto, esse nome de host personalizado contoso.com deve ser registrado no serviço PaaS para que a plataforma possa identificar o servidor back-end que deve responder à solicitação.

Diagrama que ilustra o roteamento baseado em host no Serviço de Aplicativo.

Por que os aplicativos usam o nome do host

Duas razões comuns pelas quais um servidor de aplicativos precisa do nome do host são construir URLs absolutos e emitir cookies para um domínio específico. Por exemplo, quando o código do aplicativo precisa:

  • Retorne uma URL absoluta em vez de relativa em sua resposta HTTP (embora geralmente os sites tendam a renderizar links relativos quando possível).
  • Gere um URL para ser usado fora de sua resposta HTTP onde URLs relativos não podem ser usados, como para enviar um link para o site por e-mail para um usuário.
  • Gere um URL de redirecionamento absoluto para um serviço externo. Por exemplo, para um serviço de autenticação como o Microsoft Entra ID para indicar onde ele deve retornar o usuário após a autenticação bem-sucedida.
  • Emitir cookies HTTP restritos a um determinado host, conforme definido no atributo do Domain cookie.

Você pode atender a todos esses requisitos adicionando o nome de host esperado à configuração do aplicativo e usando esse valor definido estaticamente em vez do nome de host de entrada na solicitação. No entanto, essa abordagem complica o desenvolvimento e a implantação de aplicativos. Além disso, uma única instalação do aplicativo pode servir vários hosts. Por exemplo, um único aplicativo Web pode ser usado para vários locatários de aplicativos que têm seus próprios nomes de host exclusivos (como tenant1.contoso.com e tenant2.contoso.com).

E, às vezes, o nome do host de entrada é usado por componentes fora do código do aplicativo ou em middleware no servidor de aplicativos sobre o qual você não tem controle total. Seguem-se alguns exemplos:

  • No Serviço de Aplicativo, você pode impor HTTPS para seu aplicativo Web. Isso faz com que todas as solicitações HTTP que não são seguras redirecionem para HTTPS. Nesse caso, o nome do host de entrada é usado para gerar a URL absoluta para o cabeçalho do Location redirecionamento HTTP.
  • O Azure Spring Apps usa um recurso semelhante para impor HTTPS. Ele também usa o host de entrada para gerar a URL HTTPS.
  • O Serviço de Aplicativo tem uma configuração de afinidade ARR para habilitar sessões adesivas, de modo que as solicitações da mesma instância do navegador sejam sempre atendidas pelo mesmo servidor back-end. Isso é realizado pelos front-ends do Serviço de Aplicativo, que adicionam um cookie à resposta HTTP. O cookie está Domain definido para o host de entrada.
  • O Serviço de Aplicativo fornece recursos de autenticação e autorização para permitir facilmente que os usuários entrem e acessem dados em APIs.
    • O nome do host de entrada é usado para construir a URL de redirecionamento para a qual o provedor de identidade precisa retornar o usuário após a autenticação bem-sucedida.
    • Habilitar esse recurso por padrão também ativa o redirecionamento HTTP-to-HTTPS. Novamente, o nome do host de entrada é usado para gerar o local de redirecionamento.

Por que você pode ficar tentado a substituir o nome do host

Digamos que você crie um aplicativo Web no Serviço de Aplicativo que tenha um domínio padrão de contoso.azurewebsites.net. (Ou em outro serviço como o Azure Spring Apps.) Você não configurou um domínio personalizado no Serviço de Aplicativo. Para colocar um proxy reverso como o Application Gateway (ou qualquer serviço semelhante) na frente deste aplicativo, defina o registro DNS para contoso.com ser resolvido para o endereço IP do Application Gateway. Portanto, ele recebe a solicitação do contoso.com navegador e está configurado para encaminhar essa solicitação para o endereço IP que contoso.azurewebsites.net resolve para: este é o serviço back-end final para o host solicitado. Nesse caso, no entanto, o Serviço de Aplicativo não reconhece o contoso.com domínio personalizado e rejeita todas as solicitações de entrada para esse nome de host. Ele não pode determinar para onde encaminhar a solicitação.

Pode parecer que a maneira mais fácil de fazer essa configuração funcionar é substituir ou reescrever o Host cabeçalho da solicitação HTTP no Application Gateway e defini-lo com o valor de contoso.azurewebsites.net. Se você fizer isso, a solicitação de saída do Application Gateway fará parecer que a solicitação original foi realmente destinada a contoso.azurewebsites.net em vez de contoso.com:

Diagrama que ilustra uma configuração com o nome do host substituído.

Neste ponto, o Serviço de Aplicativo reconhece o nome do host e aceita a solicitação sem exigir que um nome de domínio personalizado seja configurado. Na verdade, o Application Gateway facilita a substituição do cabeçalho do host pelo host do pool de back-end. O Azure Front Door até faz isso por padrão.

O problema com essa solução, no entanto, é que ela pode resultar em vários problemas quando o aplicativo não vê o nome de host original.

Problemas potenciais

URLs absolutos incorretos

Se o nome de host original não for preservado e o servidor de aplicativos usar o nome de host de entrada para gerar URLs absolutas, o domínio back-end poderá ser divulgado para um usuário final. Essas URLs absolutas podem ser geradas pelo código do aplicativo ou, como observado anteriormente, por recursos da plataforma, como o suporte para redirecionamento HTTP para HTTPS no Serviço de Aplicativo e nos Aplicativos Azure Spring. Este diagrama ilustra o problema:

Diagrama que ilustra o problema de URLs absolutos incorretos.

  1. O navegador envia uma solicitação para contoso.com o proxy reverso.
  2. O proxy reverso regrava o nome do host na contoso.azurewebsites.net solicitação para o aplicativo Web back-end (ou para um domínio padrão semelhante para outro serviço).
  3. O aplicativo gera uma URL absoluta baseada no nome do host de entrada contoso.azurewebsites.net , por exemplo, https://contoso.azurewebsites.net/.
  4. O navegador segue essa URL, que vai diretamente para o serviço de back-end em vez de voltar para o proxy reverso em contoso.com.

Isso pode até representar um risco de segurança no caso comum em que o proxy reverso também serve como um firewall de aplicativo Web. O usuário recebe uma URL que vai direto para o aplicativo back-end e ignora o proxy reverso.

Importante

Devido a esse risco de segurança, você precisa garantir que o aplicativo Web back-end aceite diretamente o tráfego de rede do proxy reverso (por exemplo, usando restrições de acesso no Serviço de Aplicativo). Se você fizer isso, mesmo que um URL absoluto incorreto seja gerado, pelo menos ele não funciona e não pode ser usado por um usuário mal-intencionado para contornar o firewall.

URLs de redirecionamento incorretos

Um caso comum e mais específico do cenário anterior ocorre quando URLs de redirecionamento absoluto são geradas. Essas URLs são exigidas por serviços de identidade como o Microsoft Entra ID quando você usa protocolos de identidade baseados em navegador, como OpenID Connect, Open Authorization (OAuth) 2.0 ou Security Assertion Markup Language (SAML) 2.0. Essas URLs de redirecionamento podem ser geradas pelo próprio servidor de aplicativos ou middleware ou, como observado anteriormente, por recursos da plataforma, como os recursos de autenticação e autorização do serviço de aplicativo. Este diagrama ilustra o problema:

Diagrama que ilustra o problema de URLs de redirecionamento incorretas.

  1. O navegador envia uma solicitação para contoso.com o proxy reverso.
  2. O proxy reverso regrava o nome do host na contoso.azurewebsites.net solicitação para o aplicativo Web back-end (ou para um domínio padrão semelhante para outro serviço).
  3. O aplicativo gera uma URL de redirecionamento absoluta baseada no nome do host de entrada contoso.azurewebsites.net , por exemplo, https://contoso.azurewebsites.net/.
  4. O navegador vai para o provedor de identidade para autenticar o usuário. A solicitação inclui a URL de redirecionamento gerada para indicar onde retornar o usuário após a autenticação bem-sucedida.
  5. Os provedores de identidade normalmente exigem que as URLs de redirecionamento sejam registradas antecipadamente, portanto, neste momento, o provedor de identidade deve rejeitar a solicitação porque a URL de redirecionamento fornecida não está registrada. (Não era para ser usado.) Se, por algum motivo, a URL de redirecionamento estiver registrada, no entanto, o provedor de identidade redirecionará o navegador para a URL de redirecionamento especificada na solicitação de autenticação. Neste caso, o URL é https://contoso.azurewebsites.net/.
  6. O navegador segue essa URL, que vai diretamente para o serviço de back-end em vez de voltar para o proxy reverso.

Cookies quebrados

Uma incompatibilidade de nome de host também pode levar a problemas quando o servidor de aplicativos emite cookies e usa o nome de host de entrada para construir o Domain atributo do cookie. O atributo Domain garante que o cookie será usado apenas para esse domínio específico. Esses cookies podem ser gerados pelo código do aplicativo ou, como observado anteriormente, por recursos da plataforma, como a configuração de afinidade ARR do serviço de aplicativo. Este diagrama ilustra o problema:

Diagrama que ilustra um domínio de cookie incorreto.

  1. O navegador envia uma solicitação para contoso.com o proxy reverso.
  2. O proxy reverso reescreve o nome do host para estar contoso.azurewebsites.net na solicitação para o aplicativo Web back-end (ou para um domínio padrão semelhante para outro serviço).
  3. O aplicativo gera um cookie que usa um domínio com base no nome de host de entrada contoso.azurewebsites.net . O navegador armazena o cookie para este domínio específico em vez do contoso.com domínio que o usuário está realmente usando.
  4. O navegador não inclui o cookie em qualquer solicitação subsequente porque contoso.com o domínio do cookie contoso.azurewebsites.net não corresponde ao domínio da solicitação. A aplicação não recebe o cookie que emitiu anteriormente. Como consequência, o usuário pode perder o estado que deveria estar no cookie ou recursos como afinidade ARR não funcionam. Infelizmente, nenhum desses problemas gera um erro ou é diretamente visível para o usuário final. Isso dificulta a solução de problemas.

Diretrizes de implementação para serviços comuns do Azure

Para evitar os possíveis problemas discutidos aqui, recomendamos que você preserve o nome do host original na chamada entre o proxy reverso e o servidor de aplicativos back-end:

Diagrama que mostra uma configuração na qual o nome do host é preservado.

Configuração de back-end

Muitas plataformas de hospedagem na Web exigem que você configure explicitamente os nomes de host de entrada permitidos. As seções a seguir descrevem como implementar essa configuração para os serviços mais comuns do Azure. Outras plataformas geralmente fornecem métodos semelhantes para configurar domínios personalizados.

Se você hospedar seu aplicativo Web no Serviço de Aplicativo, poderá anexar um nome de domínio personalizado ao aplicativo Web e evitar usar o nome de host padrão azurewebsites.net no back-end. Não é necessário alterar a resolução DNS quando anexa um domínio personalizado à aplicação Web: pode verificar o domínio utilizando um TXT registo sem afetar os seus registos regulares CNAME ou A regulares. (Esses registros ainda serão resolvidos para o endereço IP do proxy reverso.) Se você precisar de TLS/SSL de ponta a ponta, poderá importar um certificado existente do Cofre da Chave ou usar um Certificado do Serviço de Aplicativo para seu domínio personalizado. (Note que o O certificado gerenciado do Serviço de Aplicativo não pode ser usado nesse caso, pois requer que o registro DNS do domínio seja resolvido diretamente para o Serviço de Aplicativo, não para o proxy reverso.)

Da mesma forma, se você estiver usando o Spring Apps, poderá usar um domínio personalizado para seu aplicativo para evitar o uso do nome do azuremicroservices.io host. Você pode importar um certificado existente ou autoassinado se precisar de TLS/SSL de ponta a ponta.

Se você tiver um proxy reverso na frente do Gerenciamento de API (que também atua como um proxy reverso), poderá configurar um domínio personalizado em sua instância de Gerenciamento de API para evitar o uso do nome do azure-api.net host. Você pode importar um certificado gerenciado existente ou gratuito se precisar de TLS/SSL de ponta a ponta. Como observado anteriormente, no entanto, as APIs são menos sensíveis aos problemas causados por incompatibilidades de nomes de host, portanto, essa configuração pode não ser tão importante.

Se você hospedar seus aplicativos em outras plataformas, como no Kubernetes ou diretamente em máquinas virtuais, não haverá funcionalidade interna que dependa do nome do host de entrada. Você é responsável por como o nome do host é usado no próprio servidor de aplicativos. A recomendação de preservar o nome do host normalmente ainda se aplica a quaisquer componentes em seu aplicativo que dependam dele, a menos que você especificamente torne seu aplicativo ciente de proxies reversos e respeite os forwarded cabeçalhos ou X-Forwarded-Host , por exemplo.

Configuração de proxy reverso

Ao definir os back-ends dentro do proxy reverso, você ainda pode usar o domínio padrão do serviço back-end, por exemplo, https://contoso.azurewebsites.net/. Essa URL é usada pelo proxy reverso para resolver o endereço IP correto para o serviço back-end. Se você usar o domínio padrão da plataforma, o endereço IP é sempre garantido como correto. Normalmente, você não pode usar o domínio voltado para o público, como contoso.com, porque ele deve ser resolvido para o endereço IP do próprio proxy reverso. (A menos que você use técnicas de resolução de DNS mais avançadas, como DNS de horizonte dividido).

Importante

Se você tiver um firewall de próxima geração, como o Firewall Premium do Azure, entre o proxy reverso e o back-end final, talvez seja necessário usar o DNS de horizonte dividido. Esse tipo de firewall pode verificar explicitamente se o cabeçalho HTTP Host é resolvido para o endereço IP de destino. Nesses casos, o nome de host original usado pelo navegador deve ser resolvido para o endereço IP do proxy reverso quando ele é acessado pela Internet pública. Do ponto de vista do firewall, no entanto, esse nome de host deve ser resolvido para o endereço IP do serviço back-end final. Para obter mais informações, consulte Rede de confiança zero para aplicativos Web com o Firewall do Azure e o Gateway de Aplicativos.

A maioria dos proxies reversos permite configurar qual nome de host é passado para o serviço back-end. As informações a seguir explicam como garantir, para os serviços mais comuns do Azure, que o nome de host original da solicitação de entrada seja usado.

Nota

Em todos os casos, você também pode optar por substituir o nome do host por um domínio personalizado explicitamente definido em vez de retirá-lo da solicitação de entrada. Se o aplicativo usa apenas um único domínio, essa abordagem pode funcionar bem. Se a mesma implantação de aplicativo aceitar solicitações de vários domínios (por exemplo, em cenários multilocatário), você não poderá definir estaticamente um único domínio. Você deve pegar o nome do host da solicitação de entrada (novamente, a menos que o aplicativo seja explicitamente codificado para levar em conta cabeçalhos HTTP adicionais). Portanto, a recomendação geral é que você não deve substituir o nome do host. Passe o nome do host de entrada sem modificações para o back-end.

Gateway de Aplicação

Se você usar o Gateway de Aplicativo como proxy reverso, poderá garantir que o nome do host original seja preservado desativando Substituir por novo nome de host na configuração HTTP de back-end. Isso desativa Escolher nome de host do endereço back-end e Substituir por nome de domínio específico. (Ambas as configurações substituem o nome do host.) Nas propriedades do Azure Resource Manager para o Gateway de Aplicativo, essa configuração corresponde à definição da hostName propriedade como null e pickHostNameFromBackendAddress para false.

Como os testes de integridade são enviados fora do contexto de uma solicitação de entrada, eles não podem determinar dinamicamente o nome de host correto. Em vez disso, você precisa criar uma investigação de integridade personalizada, desabilitar Escolher nome do host nas configurações HTTP de back-end e especificar explicitamente o nome do host. Para esse nome de host, você também deve usar um domínio personalizado apropriado, para consistência. (Você pode, no entanto, usar o domínio padrão da plataforma de hospedagem aqui, porque as sondas de integridade ignoram cookies incorretos ou redirecionam URLs na resposta.)

Azure Front Door

Se você usar o Azure Front Door, poderá evitar substituir o nome do host deixando o cabeçalho do host back-end em branco na definição do pool de back-ends. Na definição do Resource Manager do pool de back-end, essa configuração corresponde à configuração backendHostHeader de null.

Se você usar o Azure Front Door Standard ou Premium, poderá preservar o nome do host deixando o cabeçalho do host de origem em branco na definição de origem. Na definição de origem do Resource Manager, essa configuração corresponde à configuração originHostHeader de null.

Gestão de API

Por padrão, o Gerenciamento de API substitui o nome do host enviado para o back-end pelo componente de host da URL do serviço Web da API (que corresponde ao serviceUrl valor da definição do Gerenciador de Recursos da API).

Você pode forçar o Gerenciamento de API a usar o nome do host da solicitação de entrada adicionando uma inbound política de cabeçalho Definir HTTP, da seguinte maneira:

<inbound>
  <base />
  <set-header name="Host" exists-action="override">
    <value>@(context.Request.OriginalUrl.Host)</value>
  </set-header>
</inbound>

Como observado anteriormente, no entanto, as APIs são menos sensíveis aos problemas causados por incompatibilidades de nomes de host, portanto, essa configuração pode não ser tão importante.

Próximos passos