Partager via


Personnaliser l’indication du nom de serveur (SNI) dans les requêtes HTTP

Lorsqu’un client et un serveur négocient une connexion HTTPS, une connexion TLS doit d’abord être établie. Dans le cadre de l'établissement de la connexion TLS, le client envoie le nom de domaine du serveur auquel il se connecte dans l’une des extensions TLS. Lorsque plusieurs serveurs (virtuels) sont hébergés sur la même machine, cette fonctionnalité du protocole TLS permet aux clients de distinguer les serveurs auxquels ils se connectent et de configurer les paramètres TLS, tels que le certificat de serveur, en conséquence.

Lorsqu'une requête HTTP utilisant HttpClient est effectuée, l'implémentation sélectionne automatiquement une valeur pour l'extension d'indication de nom de serveur (SNI) en fonction de l'URL à laquelle le client se connecte. Pour les scénarios nécessitant un contrôle plus manuel de l’extension, vous pouvez utiliser l’une des approches suivantes.

En-tête d'hôte

L’en-tête HTTP hôte effectue une fonction similaire à l’extension SNI dans TLS. Il permet au serveur cible de distinguer les demandes de plusieurs noms d’hôtes sur une seule adresse IP. HttpClient remplit automatiquement l’en-tête Host en utilisant l’URI de la requête. Toutefois, vous pouvez également définir sa valeur manuellement et HttpClient utiliser la nouvelle valeur dans l’extension SNI. Vous pouvez utiliser l’un ou l’autre HttpRequestMessage.Headers.Host ou HttpClient.DefaultRequestHeaders.Host pour obtenir cet effet.

using HttpClient client = new();

client.DefaultRequestHeaders.Host = "www.microsoft.com";

using var response = await client.GetAsync("https://127.0.0.1:5001/");

System.Console.WriteLine(response);

Remarque

Cette méthode ne vous permet pas d’éviter d’envoyer complètement SNI lors de la connexion à une URL avec un nom d’hôte. Si l’en-tête est défini sur une chaîne vide, HttpClient utilise plutôt le nom d’hôte de l’URL.

Remarque

La personnalisation de l’en-tête hôte affecte la validation du certificat de serveur. Par défaut, le client s’attend à ce que le certificat de serveur corresponde au nom d’hôte dans l’en-tête de l’hôte.

Authentification manuelle de SslStream via ConnectCallback

Une option plus complexe, mais aussi plus puissante, consiste à utiliser le SocketsHttpHandler.ConnectCallback. Depuis .NET 7, il est possible de retourner une connexion authentifiée SslStream et ainsi personnaliser la façon dont la connexion TLS est établie. Dans la fonction de rappel, des options arbitraires SslClientAuthenticationOptions peuvent être utilisées pour effectuer l’authentification du côté client.

var handler = new SocketsHttpHandler
{
    ConnectCallback = async (context, cancellationToken) =>
    {
        var socket = new Socket(SocketType.Stream, ProtocolType.Tcp) { NoDelay = true };
        try
        {
            await socket.ConnectAsync(context.DnsEndPoint, cancellationToken);

            var sslStream = new SslStream(new NetworkStream(socket, ownsSocket: true));

            // When using HTTP/2, you must also keep in mind to set options like ApplicationProtocols
            await sslStream.AuthenticateAsClientAsync(new SslClientAuthenticationOptions
            {
                TargetHost = context.DnsEndPoint.Host,

            }, cancellationToken);

            return sslStream;
        }
        catch
        {
            socket.Dispose();
            throw;
        }
    }
};

using HttpClient client = new(handler);

using var response = await client.GetAsync("https://www.microsoft.com");

System.Console.WriteLine(response);