Édition

Conserver le nom d’hôte HTTP d’origine entre un proxy inverse et son application web de back-end

Gestion des API Azure
Azure App Service
Azure Application Gateway
Azure Front Door
Azure Spring Apps

Nous vous recommandons de conserver le nom d’hôte HTTP d’origine quand vous utilisez un proxy inverse devant une application web. Si le nom d’hôte au niveau du proxy inverse est différent de celui fourni au serveur d’applications de back-end, les cookies ou les URL de redirection risquent de ne pas fonctionner correctement. Par exemple, l’état de session peut être perdu, l’authentification peut échouer ou les URL de back-end peuvent être exposées par inadvertance aux utilisateurs finaux. Vous pouvez éviter ces problèmes en conservant le nom d’hôte de la demande initiale pour que le serveur d’applications puisse voir le même domaine que le navigateur web.

Ce guide s’applique particulièrement aux applications hébergées dans des offres PaaS (platform as a service) comme Azure App Service et Azure Spring Apps. Cet article fournit des recommandations d’implémentation spécifiques pour Azure Application Gateway, Azure Front Dooret Gestion des API Azure, qui sont couramment utilisés par les services de proxy inverse.

Notes

Les API web sont généralement moins sensibles aux problèmes liés aux incompatibilités de nom d’hôte. En général, elles ne dépendent pas des cookies, sauf si vous utilisez des cookies pour sécuriser les communications entre une application monopage et son API de back-end, par exemple, dans le modèle Back-ends pour front-ends. Souvent, les API web ne se renvoient pas à elle-mêmes des URL absolues, sauf dans certains styles d’API, comme OData et HATEOAS. Si votre implémentation d’API dépend de cookies ou génère des URL absolues, les recommandations fournies dans cet article s’appliquent.

Si vous avez besoin d’une connexion TLS/SSL de bout en bout (la connexion entre le proxy inverse et le service de back-end utilise HTTPS), le service de back-end a également besoin d’un certificat TLS correspondant pour le nom d’hôte d’origine. Cette exigence ajoute une complexité opérationnelle quand vous déployez et renouvelez des certificats, mais de nombreux services PaaS offrent des certificats TLS gratuits entièrement managés.

Context

L’hôte d’une requête HTTP

Dans de nombreux cas, le serveur d’applications ou un composant du pipeline de demandes a besoin du nom de domaine Internet que le navigateur a utilisé pour y accéder. Il s’agit de l’hôte de la demande. Ce peut être une adresse IP, mais il s’agit généralement d’un nom comme contoso.com (que le navigateur résout ensuite en adresse IP en utilisant DNS). La valeur de l’hôte est généralement déterminée à partir du composant hôte de l’URI de demande, que le navigateur envoie à l’application sous forme d’en-tête HTTP Host.

Important

N’utilisez jamais la valeur de l’hôte dans un mécanisme de sécurité. La valeur est fournie par le navigateur ou un autre agent utilisateur, et peut facilement être manipulée par un utilisateur final.

Dans certains scénarios, en particulier quand un proxy inverse HTTP se trouve dans la chaîne de demande, l’en-tête d’origine de l’hôte peut être changé avant d’atteindre le serveur d’applications. Un proxy inverse ferme la session réseau cliente et configure une nouvelle connexion au back end. Dans cette nouvelle session, il peut porter le nom d’hôte d’origine de la session cliente ou en définir un nouveau. Dans ce dernier cas, le proxy envoie souvent la valeur d’origine de l’hôte dans d’autres en-têtes HTTP, comme Forwarded ou X-Forwarded-Host. Cette valeur permet aux applications de déterminer le nom d’hôte d’origine, mais uniquement si elles sont codées pour lire ces en-têtes.

Pourquoi les plateformes web utilisent le nom d’hôte

Les services PaaS multilocataires nécessitent souvent un nom d’hôte inscrit et validé pour router une demande entrante vers le serveur de back-end du locataire approprié. C’est parce qu’il y a généralement un pool partagé d’équilibreurs de charge qui acceptent les demandes entrantes pour tous les locataires. Les locataires utilisent couramment le nom d’hôte entrant pour rechercher le back-end correspondant au locataire client.

Pour faciliter le démarrage, ces plateformes fournissent généralement un domaine par défaut qui est préconfiguré pour router le trafic vers votre instance déployée. Pour App Service, ce domaine par défaut est azurewebsites.net. Chaque application web que vous créez obtient son propre sous-domaine, par exemple, contoso.azurewebsites.net. De même, le domaine par défaut est azuremicroservices.io pour Spring Apps et azure-api.net pour Gestion des API.

Pour les déploiements de production, vous n’utilisez pas ces domaines par défaut. À la place, vous fournissez votre propre domaine pour qu’il corresponde à la marque de votre organisation ou de votre application. Par exemple, contoso.com peut résoudre en arrière-plan l’application web contoso.azurewebsites.net sur App Service, mais ce domaine ne doit pas être visible par un utilisateur final visitant le site web. Ce nom d’hôte contoso.com personnalisé doit toutefois être inscrit sur le service PaaS afin que la plateforme puisse identifier le serveur de back-end qui doit répondre à la demande.

Diagram that illustrates host-based routing in App Service.

Pourquoi les applications utilisent le nom d’hôte

Un serveur d’applications a besoin du nom d’hôte pour deux raisons courantes : construire des URL absolues et envoyer des cookies pour un domaine spécifique. Par exemple, quand le code d’application doit :

  • Retourner une URL absolue plutôt qu’une URL relative dans sa réponse HTTP (même si les sites web ont généralement tendance à restituer des liens relatifs quand cela est possible).
  • Générer une URL à utiliser en dehors de sa réponse HTTP là où les URL relatives ne peuvent pas être utilisées, par exemple pour envoyer par e-mail à un utilisateur un lien vers le site web.
  • Générer une URL de redirection absolue pour un service externe. Par exemple, à un service d'authentification tel que Microsoft Entra ID pour indiquer où il doit renvoyer l'utilisateur après une authentification réussie.
  • Envoyer des cookies HTTP qui sont limités à un certain hôte, comme défini dans l’attribut Domain du cookie.

Vous pouvez répondre à toutes ces exigences en ajoutant le nom d’hôte attendu dans la configuration de l’application, et en utilisant cette valeur définie de manière statique au lieu du nom d’hôte entrant de la demande. Toutefois, cette approche complique le développement et le déploiement d’applications. Par ailleurs, une seule installation de l’application peut servir plusieurs hôtes. Par exemple, une même application web peut être utilisée pour plusieurs locataires d’application qui ont tous leur propre nom d’hôte unique (comme tenant1.contoso.com et tenant2.contoso.com).

Parfois également, le nom d’hôte entrant est utilisé par des composants situés en dehors du code d’application ou dans un intergiciel sur le serveur d’applications, sur lesquels vous n’avez pas le contrôle total. Voici quelques exemples :

  • Dans App Service, vous pouvez appliquer HTTPS pour votre application web. Cela entraîne la redirection de toutes les requêtes HTTP qui ne peuvent pas être redirigées vers HTTPS de manière sécurisée. Dans ce cas, le nom d’hôte entrant est utilisé pour générer l’URL absolue de l’en-tête Location de la redirection HTTP.
  • Spring Apps utilise une fonctionnalité similaire pour appliquer HTTPS. Il utilise également l’hôte entrant pour générer l’URL HTTPS.
  • App Service a un paramètre d’affinité ARR pour activer les sessions persistantes, afin que les demandes de la même instance de navigateur soient toujours servies par le même serveur de back-end. Cette opération est effectuée par les front-ends App Service, qui ajoutent un cookie à la réponse HTTP. Le Domain du cookie est défini sur l’hôte entrant.
  • App Service fournit des fonctionnalités d’authentification et d’autorisation pour permettre aux utilisateurs de se connecter et d’accéder facilement aux données dans les API.

Pourquoi vous pouvez être tenté de remplacer le nom d’hôte

Imaginons que vous créez une application web dans App Service, dont le domaine par défaut est contoso.azurewebsites.net. (Ou dans un autre service comme Spring Apps.) Vous n’avez pas configuré de domaine personnalisé sur App Service. Pour placer un proxy inverse comme Application Gateway (ou un autre service similaire) devant cette application, vous devez définir l’enregistrement DNS de contoso.com afin de le résoudre en adresse IP d’Application Gateway. Elle reçoit donc la demande de contoso.com à partir du navigateur et est configurée pour transférer cette demande à l’adresse IP correspondant à contoso.azurewebsites.net : il s’agit du service de back-end final pour l’hôte demandé. Dans ce cas, toutefois, App Service ne reconnaît pas le domaine personnalisé contoso.com et rejette toutes les demandes entrantes pour ce nom d’hôte. Il ne peut pas déterminer où router la demande.

Il peut sembler que le moyen le plus simple pour que cette configuration fonctionne soit de remplacer ou réécrire l’en-tête Host de la requête HTTP dans Application Gateway et de le définir sur la valeur contoso.azurewebsites.net. Si vous le faites, la demande sortante d’Application Gateway fait croire que la demande d’origine était vraiment prévue pour contoso.azurewebsites.net et non pour contoso.com :

Diagram that illustrates a configuration with the host name overridden.

À ce stade, App Service reconnaît le nom d’hôte et accepte la demande sans qu’un nom de domaine personnalisé soit configuré. En fait, Application Gateway permet de remplacer facilement l’en-tête de l’hôte par l’hôte du pool de back-ends. Azure Front Door fait la même chose par défaut.

Le problème avec cette solution, toutefois, est qu’elle peut entraîner divers problèmes quand l’application ne voit pas le nom d’hôte d’origine.

Problèmes potentiels

URL absolues incorrectes

Si le nom d’hôte d’origine n’est pas conservé et que le serveur d’applications utilise le nom d’hôte entrant pour générer des URL absolues, le domaine de back-end peut être divulgué à un utilisateur final. Ces URL absolues peuvent être générées par le code d’application ou, comme indiqué précédemment, par des fonctionnalités de plateforme comme la prise en charge de la redirection HTTP vers HTTPS dans App Service et Spring Apps. Ce diagramme illustre le problème :

Diagram that illustrates the problem of incorrect absolute URLs.

  1. Le navigateur envoie une demande pour contoso.com au proxy inverse.
  2. Le proxy inverse réécrit le nom d’hôte en contoso.azurewebsites.net dans la demande envoyée à l’application web de back-end (ou à un domaine par défaut similaire pour un autre service).
  3. L’application génère une URL absolue basée sur le nom d’hôte contoso.azurewebsites.net entrant, par exemple, https://contoso.azurewebsites.net/.
  4. Le navigateur suit cette URL, qui accède directement au service de back-end au lieu de retourner au proxy inverse sur contoso.com.

Cela peut même poser un risque de sécurité dans le cas courant où le proxy inverse sert également de pare-feu d’applications web. L’utilisateur reçoit une URL qui accède directement à l’application de back-end et contourne le proxy inverse.

Important

En raison de ce risque de sécurité, vous devez faire en sorte que l’application web de back-end accepte uniquement le trafic réseau directement à partir du proxy inverse (par exemple, en utilisant des restrictions d’accès dans App Service). Dans ce cas, même si une URL absolue incorrecte est générée, elle ne fonctionne pas et ne peut pas être utilisée par un utilisateur malveillant pour contourner le pare-feu.

URL de redirection incorrectes

Un cas commun et plus spécifique du scénario précédent se produit quand des URL de redirection absolues sont générées. Ces URL sont requises par les services d'identité tels que Microsoft Entra ID lorsque vous utilisez des protocoles d'identité basés sur un navigateur tels qu'OpenID Connect, OAuth 2.0 ou SAML 2.0. Ces URL de redirection peuvent être générées par le serveur d’applications ou l’intergiciel lui-même, ou, comme indiqué précédemment, par des fonctionnalités de plateforme comme les fonctionnalités d’authentification et d’autorisation d’App Service. Ce diagramme illustre le problème :

Diagram that illustrates the problem of incorrect redirect URLs.

  1. Le navigateur envoie une demande pour contoso.com au proxy inverse.
  2. Le proxy inverse réécrit le nom d’hôte en contoso.azurewebsites.net dans la demande envoyée à l’application web de back-end (ou à un domaine par défaut similaire pour un autre service).
  3. L’application génère une URL de redirection absolue basée sur le nom d’hôte contoso.azurewebsites.net entrant, par exemple, https://contoso.azurewebsites.net/.
  4. Le navigateur accède au fournisseur d’identité pour authentifier l’utilisateur. La demande comprend l’URL de redirection générée pour indiquer où renvoyer l’utilisateur après une authentification réussie.
  5. Les fournisseurs d’identité demandent généralement que les URL de redirection soient inscrites en amont. À ce stade, le fournisseur d’identité doit rejeter la demande, car l’URL de redirection fournie n’est pas inscrite. (Son utilisation n’était pas prévue). Toutefois, si pour une raison quelconque l’URL de redirection est inscrite, le fournisseur d’identité redirige le navigateur vers l’URL de redirection spécifiée dans la demande d’authentification. Dans ce cas, l’URL est https://contoso.azurewebsites.net/.
  6. Le navigateur suit cette URL, qui accède directement au service de back-end au lieu de retourner au proxy inverse.

Cookies rompus

Une incompatibilité de nom d’hôte peut également entraîner des problèmes quand le serveur d’applications envoie des cookies et utilise le nom d’hôte entrant pour construire l’attribut Domain du cookie. L’attribut Domain garantit que le cookie est utilisé uniquement pour ce domaine spécifique. Ces cookies peuvent être générés par le code d’application ou, comme indiqué précédemment, par des fonctionnalités de plateforme comme le paramètre d’affinité ARR d’App Service. Ce diagramme illustre le problème :

Diagram that illustrates an incorrect cookie domain.

  1. Le navigateur envoie une demande pour contoso.com au proxy inverse.
  2. Le proxy inverse réécrit le nom d’hôte en contoso.azurewebsites.net dans la demande envoyée à l’application web de back-end (ou à un domaine par défaut similaire pour un autre service).
  3. L’application génère un cookie qui utilise un domaine basé sur le nom d’hôte entrant contoso.azurewebsites.net. Le navigateur stocke le cookie pour ce domaine spécifique plutôt que pour le domaine contoso.com que l’utilisateur utilise réellement.
  4. Le navigateur n’ajoute pas le cookie dans les demandes suivantes pour contoso.com, car le domaine contoso.azurewebsites.net du cookie ne correspond pas au domaine de la demande. L’application ne reçoit pas le cookie qu’elle a émis précédemment. Par conséquent, l’utilisateur peut perdre l’état supposé être dans le cookie, ou des fonctionnalités comme l’affinité ARR peuvent ne pas fonctionner. Malheureusement, aucun de ces problèmes ne génère d’erreur ou n’est directement visible par l’utilisateur final. Cela complique la résolution des problèmes.

Recommandations d’implémentation pour les services Azure courants

Pour éviter les problèmes potentiels décrits ici, nous vous recommandons de conserver le nom d’hôte d’origine dans l’appel entre le proxy inverse et le serveur d’applications de back-end :

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

Configuration du back-end

De nombreuses plateformes d’hébergement web nécessitent que vous configuriez explicitement les noms d’hôte entrants autorisés. Les sections suivantes décrivent comment implémenter cette configuration pour les services Azure les plus courants. D’autres plateformes fournissent généralement des méthodes similaires pour configurer les domaines personnalisés.

Si vous hébergez votre application web dans App Service, vous pouvez attacher un nom de domaine personnalisé à l’application web pour ne pas utiliser le nom d’hôte par défaut azurewebsites.net vers le back-end. Vous n’avez pas besoin de changer votre résolution DNS quand vous attachez un domaine personnalisé à l’application web : vous pouvez vérifier le domaine en utilisant un enregistrement TXT sans affecter vos enregistrements CNAME ou A normaux. (Ces enregistrements sont toujours résolus en adresse IP du proxy inverse.) Si vous avez besoin de TLS/SSL de bout en bout, vous pouvez importer un certificat existant à partir de Key Vault ou utiliser un App Service Certificate pour votre domaine personnalisé. (Notez que le certificat managé App Service gratuit ne peut pas être utilisé dans ce cas, car il nécessite que l’enregistrement DNS du domaine soit résolu directement en App Service, et non sur le proxy inverse.)

De même, si vous utilisez Spring Apps, vous pouvez utiliser un domaine personnalisé pour votre application afin d’éviter d’utiliser le nom d’hôte azuremicroservices.io. Vous pouvez importer un certificat existant ou autosigné si vous avez besoin d’une connexion TLS/SSL de bout en bout.

Si vous avez un proxy inverse devant Gestion des API (qui agit également comme un proxy inverse), vous pouvez configurer un domaine personnalisé sur votre instance Gestion des API pour éviter d’utiliser le nom d’hôte azure-api.net. Vous pouvez importer un certificat existant ou un certificat managé gratuit si vous avez besoin d’une connexion TLS/SSL de bout en bout. Toutefois, comme indiqué précédemment, les API sont moins sensibles aux problèmes liés aux incompatibilités de nom d’hôte et, par conséquent, cette configuration peut ne pas être aussi importante.

Si vous hébergez vos applications sur d’autres plateformes, comme sur Kubernetes ou directement sur des machines virtuelles, aucune fonctionnalité intégrée ne dépend du nom d’hôte entrant. Vous décidez de la façon dont le nom d’hôte est utilisé dans le serveur d’applications lui-même. La conservation du nom d’hôte est généralement recommandée pour tous les composants de votre application qui en dépendent, sauf si vous faites en sorte que votre application reconnaisse spécifiquement les proxys inverses et respecte les en-têtes forwarded ou X-Forwarded-Host, par exemple.

Configuration de proxy inverse

Quand vous définissez les back-ends dans le proxy inverse, vous pouvez toujours utiliser le domaine par défaut du service de back-end, par exemple, https://contoso.azurewebsites.net/. Cette URL est utilisée par le proxy inverse pour résoudre l’adresse IP appropriée du service de back-end. Si vous utilisez le domaine par défaut de la plateforme, l’adresse IP est toujours correcte. En général, vous ne pouvez pas utiliser le domaine public, comme contoso.com, car il doit correspondre à l’adresse IP du proxy inverse lui-même. (Sauf si vous utilisez des techniques de résolution DNS plus avancées, comme le DNS de découpage d’horizon.)

Important

Si vous avez un pare-feu de nouvelle génération, comme un Pare-feu Azure Premium, entre le proxy inverse et le back-end final, vous devez peut-être utiliser le DNS de découpage d’horizon. Ce type de pare-feu peut vérifier explicitement si l’en-tête Host HTTP est résolu en adresse IP cible. Dans ce cas, le nom d’hôte d’origine utilisé par le navigateur doit être résolu en adresse IP du proxy inverse quand il est accessible à partir de l’Internet public. Du point de vue du pare-feu, toutefois, ce nom d’hôte doit être résolu en adresse IP du service de back-end final. Pour plus d’informations, consultez Réseau Confiance Zéro pour les applications web avec le Pare-feu Azure et Application Gateway.

La plupart des proxys inverses vous permettent de configurer le nom d’hôte qui est transmis au service de back-end. Les informations suivantes expliquent comment garantir, pour les services Azure les plus courants, l’utilisation du nom d’hôte d’origine de la demande entrante.

Notes

Dans tous les cas, vous pouvez également choisir de remplacer le nom d’hôte par un domaine personnalisé défini explicitement au lieu de le supprimer dans la demande entrante. Si l’application utilise un seul domaine, cette approche peut très bien fonctionner. Si le même déploiement d’application accepte les demandes de plusieurs domaines (par exemple, dans les scénarios multilocataires), vous ne pouvez pas définir de manière statique un seul domaine. Vous devez prendre le nom d’hôte de la demande entrante (là encore, sauf si l’application est explicitement codée pour prendre en compte des en-têtes HTTP supplémentaires). Par conséquent, la recommandation générale est de ne pas remplacer le nom d’hôte du tout. Passez le nom d’hôte entrant non modifié au back-end.

Application Gateway

Si vous utilisez Application Gateway comme proxy inverse, vous pouvez faire en sorte que le nom d’hôte d’origine soit conservé en désactivant Remplacer par le nouveau nom d’hôte dans le paramètre HTTP du back-end. Cela désactive à la fois Récupérer le nom d’hôte dans l’adresse du back-end et Remplacer par un nom de domaine spécifique. Dans les propriétés Azure Resource Manager pour Application Gateway, cette configuration revient à définir la propriété hostName sur null et pickHostNameFromBackendAddress sur false.

Comme les sondes d’intégrité sont envoyées en dehors du contexte d’une demande entrante, elles ne peuvent pas déterminer dynamiquement le nom d’hôte approprié. À la place, vous devez créer une sonde d’intégrité personnalisée, désactiver dans les paramètres HTTP Récupérer le nom d’hôte dans l’adresse du back-end, et spécifier explicitement le nom d’hôte. Pour ce nom d’hôte, vous devez également utiliser un domaine personnalisé approprié, pour assurer la cohérence. (Toutefois, vous pouvez ici utiliser le domaine par défaut de la plateforme d’hébergement, car les sondes d’intégrité ignorent les cookies ou les URL de redirection incorrects dans la réponse.)

Azure Front Door

Si vous utilisez Azure Front Door, vous pouvez éviter de remplacer le nom d’hôte en laissant vide l’en-tête de l’hôte de back-end dans la définition du pool de back-ends. Dans la définition Resource Manager du pool de back-ends, cette configuration revient à définir backendHostHeader sur null.

Si vous utilisez Azure Front Door Standard ou Premium, vous pouvez conserver le nom d’hôte en laissant vide l’en-tête de l’hôte d’origine dans la définition d’origine. Dans la définition Resource Manager de l’origine, cette configuration revient à définir originHostHeader sur null.

Gestion des API

Par défaut, Gestion des API remplace le nom d’hôte qui est envoyé au back-end par le composant hôte de l’URL du service web de l’API (qui correspond à la valeur serviceUrl de la définition Resource Manager de l’API).

Vous pouvez forcer Gestion des API à utiliser à la place le nom d’hôte de la demande entrante en ajoutant une stratégie inboundDéfinir l’en-tête HTTP, de la façon suivante :

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

Toutefois, comme indiqué précédemment, les API sont moins sensibles aux problèmes liés aux incompatibilités de nom d’hôte et, par conséquent, cette configuration peut ne pas être aussi importante.

Étapes suivantes