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

Gerenciamento de API do Azure
Serviço de aplicativo do Azure
Gateway de Aplicativo do Azure
Porta da frente do Azure
Azure Spring Apps

É recomendável preservar o nome do host HTTP original ao usar um proxy reverso na frente de um aplicativo Web. Se o nome do host do proxy reverso for diferente daquele informado ao servidor de aplicativo de back-end, talvez os cookies ou os URLs de redirecionamento não funcionem corretamente. Por exemplo, o estado da sessão poderá ser perdido, a autenticação poderá falhar ou as URLs de back-end poderão ser expostas inadvertidamente aos usuários finais. Para evitar esses problemas, preserve o nome do host da solicitação inicial para que o servidor de aplicativo veja o mesmo domínio que o navegador da Web.

Essas diretrizes se aplicam especialmente a aplicativos hospedados em ofertas de plataforma como serviço (PaaS), como o Serviço de Aplicativo do Azure e os Aplicativos Spring do Azure. Este artigo contém diretrizes de implementação específicas para o Gateway de Aplicativo do Azure, o Azure Front Door e o Gerenciamento de API do Azure, que são serviços de proxy reverso muito usados.

Observação

As APIs Web geralmente são menos sensíveis aos problemas causados por incompatibilidades de nome de host. Elas 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 back-ends para front-ends. As APIs Web geralmente não retornam URLs absolutas para si mesmas, exceto em determinados estilos de API como OData e HATEOAS. As diretrizes deste artigo também se aplicam a implementações de API que dependem de cookies ou que geram URLs absolutas.

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

Contexto

O host de uma solicitação HTTP

Em muitos casos, o servidor de aplicativo ou algum componente no pipeline de solicitação precisa do nome de domínio que o navegador usou para acessá-lo. Esse é o host da solicitação. 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 com base no componente host do URI de solicitação, que o navegador envia ao aplicativo como o cabeçalho HTTP Host.

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, é possível que o cabeçalho do host original seja alterado antes de chegar ao servidor de aplicativo. Um proxy reverso fecha a sessão de rede do cliente e configura uma nova conexão com o back-end. Na nova sessão, ele pode carregar o nome do host original da sessão do cliente ou definir um novo. No último caso, o proxy geralmente ainda envia o valor do host original em outros cabeçalhos HTTP, como Forwarded ou X-Forwarded-Host. Com esse valor, os aplicativos podem determinar o nome do host original, mas somente caso estejam codificados para ler esses cabeçalhos.

Por que as plataformas Web usam o nome do host

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

Para facilitar a introdução, as plataformas normalmente incluem um domínio padrão pré-configurado para rotear o tráfego à instância implantada. No Serviço de Aplicativo, o domínio padrão é azurewebsites.net. Cada aplicativo Web criado obtém seu próprio subdomínio, por exemplo, contoso.azurewebsites.net. Da mesma forma, o domínio padrão é azuremicroservices.io para os Aplicativos Spring 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ê usa seu próprio domínio de acordo com a marca da organização ou do aplicativo. Por exemplo, nos bastidores, contoso.com poderia estar associado ao aplicativo Web contoso.azurewebsites.net no Serviço de Aplicativo, mas os usuários finais que visitam o site não deveriam ver esse domínio. No entanto, é necessário registrar o nome de host personalizado contoso.com no serviço PaaS, para que a plataforma possa identificar o servidor de back-end que deve responder à solicitação.

Diagram that illustrates host-based routing in App Service.

Por que os aplicativos usam o nome do host

Dois motivos comuns pelos quais um servidor de aplicativo precisa do nome do host são criar URLs absolutas e emitir cookies para um domínio específico. Por exemplo, quando o código do aplicativo precisa fazer o seguinte:

  • Retornar uma URL absoluta em vez de relativa na resposta HTTP (embora geralmente sites costumem renderizar links relativos quando possível).
  • Gerar uma URL a ser usada fora da resposta HTTP em que URLs relativas não podem ser usadas, como para enviar o link do site a um usuário por email.
  • Gerar uma URL de redirecionamento absoluta para um serviço externo. Por exemplo, para um serviço de autenticação como o Microsoft Entra ID para indicar para 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 Domain do cookie.

Para cumprir todos esses requisitos, é possível adicionar o nome do host esperado à configuração do aplicativo e usar esse valor estático em vez do nome do host recebido 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 atender a vários hosts. Por exemplo, um único aplicativo Web pode ser usado para vários locatários 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 no middleware no servidor de aplicativo, sobre o qual você não tem controle total. Estes são alguns exemplos:

  • No Serviço de Aplicativo, você pode exigir HTTPS para o aplicativo Web. Com isso, as solicitações HTTP que não são seguras são redirecionadas para HTTPS. Nesse caso, o nome do host de entrada é usado para gerar a URL absoluta do cabeçalho Location do redirecionamento HTTP.
  • Os Aplicativos Spring usam 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 permanentes, para que as solicitações da mesma instância do navegador sejam sempre atendidas pelo mesmo servidor back-end. Isso é executado pelos front-ends do Serviço de Aplicativo, que adicionam um cookie à resposta HTTP. O cookie Domain é definido como o host de entrada.
  • O Serviço de Aplicativo oferece recursos de autenticação e autorização para que os usuários entrem e acessem dados em APIs facilmente.

Motivos para você querer substituir o nome do host

Digamos que você crie um aplicativo Web no Serviço de Aplicativo com o domínio padrão contoso.azurewebsites.net. (Ou em outro serviço, como os Aplicativos Spring.) Você não configurou um domínio personalizado no Serviço de Aplicativo. Para colocar um proxy reverso como Gateway de Aplicativo (ou qualquer serviço semelhante) na frente desse aplicativo, você define o registro DNS de contoso.com para resolver para o endereço IP do Gateway de Aplicativo. Portanto, ele recebe a solicitação contoso.com do navegador e está configurado para encaminhá-la ao endereço IP associado a contoso.azurewebsites.net: esse é o serviço de back-end final para o host solicitado. Nesse caso, no entanto, o Serviço de Aplicativo não reconhece o domínio personalizado contoso.com e rejeita todas as solicitações de entrada para esse nome de host. Ele não consegue determinar para onde rotear a solicitação.

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

Diagram that illustrates a configuration with the host name overridden.

Nesse 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 Gateway de Aplicativo facilita a substituição do cabeçalho do host pelo host do pool de back-end. O Azure Front Door 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 do host original.

Possíveis problemas

URLs absolutas incorretas

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

Diagram that illustrates the problem of incorrect absolute URLs.

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

Importante

Devido a esse risco de segurança, você precisa garantir que o aplicativo Web de back-end aceite diretamente tráfego de rede apenas do proxy reverso (por exemplo, com restrições de acesso no Serviço de Aplicativo). Se você fizer isso, mesmo que uma URL absoluta incorreta seja gerada, pelo menos ela não funcionará e não poderá ser usada por um usuário mal-intencionado para ignorar o firewall.

URLs de redirecionamento incorretas

Um caso comum e mais específico do cenário anterior ocorre quando URLs absolutas de redirecionamento 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, OAuth 2.0 ou SAML 2.0. Essas URLs de redirecionamento podem ser geradas pelo próprio servidor de aplicativos ou middleware ou, conforme 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:

Diagram that illustrates the problem of incorrect redirect URLs.

  1. O navegador envia uma solicitação de contoso.com ao proxy reverso.
  2. O proxy reverso reescreve o nome do host para contoso.azurewebsites.net na solicitação ao aplicativo Web de back-end (ou a um domínio padrão semelhante para outro serviço).
  3. O aplicativo gera uma URL absoluta de redirecionamento baseada no nome do host recebido contoso.azurewebsites.net, por exemplo, https://contoso.azurewebsites.net/.
  4. O navegador entra em contato com o provedor de identidade para autenticar o usuário. A solicitação inclui a URL de redirecionamento gerada para indicar aonde retornar o usuário após a conclusão da autenticação.
  5. Geralmente, os provedores de identidade exigem o registro antecipado de URLs de redirecionamento, portanto, nesse momento, o provedor deve rejeitar a solicitação porque a URL informada não está registrada. Não era para ela ser usada. Mas se, por algum motivo, a URL de redirecionamento estiver registrada, o provedor de identidade redirecionará o navegador para a URL de redirecionamento especificada na solicitação de autenticação. Nesse caso, a URL é https://contoso.azurewebsites.net/.
  6. O navegador segue essa URL, que vai diretamente ao serviço de back-end em vez de voltar ao proxy reverso.

Cookies desfeitos

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

Diagram that illustrates an incorrect cookie domain.

  1. O navegador envia uma solicitação de contoso.com ao proxy reverso.
  2. O proxy reverso reescreve o nome do host para contoso.azurewebsites.net na solicitação ao aplicativo Web de back-end (ou a 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 do host recebido contoso.azurewebsites.net. O navegador armazena o cookie desse domínio, em vez do domínio contoso.com que o usuário está realmente usando.
  4. O navegador não inclui o cookie em nenhuma solicitação subsequente de contoso.com porque o domínio contoso.azurewebsites.net do cookie não corresponde ao domínio da solicitação. O aplicativo não recebe o cookie emitido anteriormente. Por isso, o usuário pode perder o estado que deveria estar no cookie, ou recursos como a afinidade ARR não funcionam. Infelizmente, nenhum desses problemas gera um erro ou fica diretamente visível para o usuário final. Isso os torna difíceis de solucionar.

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

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

Diagram that shows a configuration in which the host name is preserved.

Configuração de back-end

Muitas plataformas de hospedagem da Web exigem a configuração explícita dos nomes de host de entrada permitidos. Nas seções a seguir, descrevemos como implementar essa configuração para os serviços mais comuns do Azure. Outras plataformas geralmente oferecem métodos semelhantes para configurar domínios personalizados.

Quando o aplicativo Web está hospedado no Serviço de Aplicativo, é possível anexar um nome de domínio personalizado ao aplicativo e não usar o nome de host padrão azurewebsites.net para o back-end. Não é preciso alterar a resolução DNS ao anexar um domínio personalizado ao aplicativo Web: você pode verificar o domínio usando um registro TXT sem afetar os registros 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 Key Vault ou usar um Certificado do Serviço de Aplicativo para seu domínio personalizado. (Observe que o Certificado do Serviço de Aplicativo gerenciado gratuito 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 os Aplicativos Spring, poderá usar um domínio personalizado para seu aplicativo para evitar o uso do nome do host azuremicroservices.io. Você pode importar um certificado existente ou autoassinado caso precise de TLS/SSL de ponta a ponta.

Caso haja um proxy reverso na frente do Gerenciamento de API (que também atua como um proxy reverso), é possível configurar um domínio personalizado na instância do Gerenciamento de API para evitar o uso do nome do host azure-api.net. Você pode importar um certificado existente ou gerenciado gratuito caso precise 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 nome de host, portanto, essa configuração pode não ser tão importante.

Para aplicativos hospedados em outras plataformas, como o Kubernetes ou diretamente em máquinas virtuais, não há funcionalidade interna que dependa do nome do host recebido. Você é responsável pela forma como o nome do host é usado no próprio servidor de aplicativo. A recomendação para preservar o nome do host normalmente ainda se aplica a todos os componentes do aplicativo que dependem dele, a menos que você configure especificamente o aplicativo para proxies reversos e respeite os cabeçalhos forwarded ou X-Forwarded-Host, por exemplo.

Configuração de proxy reverso

Quando você define os back-ends dentro do proxy reverso, ainda pode usar o domínio padrão do serviço de back-end, por exemplo, https://contoso.azurewebsites.net/. Essa URL é usada pelo proxy reverso para resolver o endereço IP correto do serviço de back-end. Se você usar o domínio padrão da plataforma, o endereço IP sempre estará 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 DNS mais avançadas, como DNS de horizonte dividido.

Importante

Se houver um firewall de última geração entre o proxy reverso e o back-end final, como o Firewall do Azure Premium, 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 do host original usado pelo navegador deve ser resolvido para o endereço IP do proxy reverso quando ele é acessado pela Internet pública. No entanto, do ponto de vista do firewall, esse nome de host deve ser resolvido para o endereço IP do serviço de back-end final. Para ver mais informações, confira Rede de confiança zero para aplicativos Web com o Firewall do Azure e o Gateway de Aplicativo.

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

Observação

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 tirá-lo da solicitação recebida. Se o aplicativo usar apenas um único domínio, essa abordagem poderá funcionar bem. Se a mesma implantação de aplicativo aceitar solicitações de vários domínios (por exemplo, em cenários multilocatários), você não poderá definir estaticamente um único domínio. Você deve obter o nome do host na solicitação recebida (novamente, a menos que o aplicativo seja explicitamente programado para levar em conta cabeçalhos HTTP adicionais). Portanto, a recomendação geral é não substituir o nome do host. Passe o nome do host recebido não modificado ao back-end.

Gateway de Aplicativo

Com o Gateway de Aplicativo como proxy reverso, é possível desabilitar Substituir por um novo nome do host na configuração HTTP de back-end para preservar o nome do host original. Isso desabilita as opções Escolher o nome de host do endereço de back-end e Substituir por um nome de domínio específico. Ambas essas configurações substituem o nome do host. Nas propriedades do Azure Resource Manager para Gateway de Aplicativo, essa configuração corresponde a definir a propriedade hostName como null e pickHostNameFromBackendAddress como false.

Como as investigações de integridade são enviadas fora do contexto da solicitação recebida, elas não podem determinar dinamicamente o nome correto do host. Em vez disso, você precisa criar uma investigação de integridade personalizada, desabilitar Escolher o nome do host das configurações de 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. No entanto, você pode usar o domínio padrão da plataforma de hospedagem aqui, pois as investigações de integridade ignoram cookies incorretos ou URLs de redirecionamento na resposta.

Porta da frente do Azure

Se você usa o Azure Front Door, pode deixar o cabeçalho do host de back-end em branco na definição do pool de back-end para evitar a substituição do nome do host. Na definição do pool de back-end no Resource Manager, essa configuração corresponde a definir backendHostHeader como null.

Se você usa o Azure Front Door Standard ou Premium: para preservar o nome do host, deixe o cabeçalho do host de origem em branco na definição de origem. Na definição da origem no Resource Manager, essa configuração corresponde a definir originHostHeader como null.

Gerenciamento da API

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

Para forçar o Gerenciamento de API a usar o nome do host da solicitação recebida, adicione uma política de inboundcabeçalho SET 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 nome de host, portanto, essa configuração pode não ser tão importante.

Próximas etapas