87 votes

Utilisation d'un certificat auto-signé avec HttpWebRequest/Response de .NET

J'essaie de me connecter à une API qui utilise un certificat SSL auto-signé. Pour ce faire, j'utilise les objets HttpWebRequest et HttpWebResponse de .NET. Et j'obtiens une exception qui :

La connexion sous-jacente a été fermée : Impossible d'établir une relation de confiance pour le canal sécurisé SSL/TLS.

Je comprends ce que cela signifie. Et je comprends pourquoi .NET estime qu'il devrait m'avertir et fermer la connexion. Mais dans ce cas, j'aimerais tout de même me connecter à l'API, sans craindre les attaques de type "man-in-the-middle".

Alors, comment dois-je procéder pour ajouter une exception pour ce certificat auto-signé ? Ou est-ce que l'approche consiste à dire à HttpWebRequest/Response de ne pas valider le certificat du tout ? Comment dois-je m'y prendre ?

100voto

Domster Points 1404

Il s'avère que si vous souhaitez simplement désactiver la validation du certificat, vous pouvez modifier le ServerCertificateValidationCallback du ServicePointManager, comme suit :

ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

Cela validera tous les certificats (y compris les certificats invalides, expirés ou auto-signés).

1 votes

C'est intelligent et ça m'a fait rire. +1

2 votes

Parfait pour des tests rapides sur des machines de développement. Merci.

2 votes

Quelle portée cela affecte-t-il - tout ce qui se trouve dans le domaine des applications ? tout ce qui se trouve dans le pool d'applications ? tout ce qui se trouve sur la machine ?

81voto

devstuff Points 5881

@Domster : cela fonctionne, mais vous pourriez vouloir renforcer un peu la sécurité en vérifiant si le hachage du certificat correspond à ce que vous attendez. Une version étendue ressemble donc un peu à ceci (basé sur un code réel que nous utilisons) :

static readonly byte[] apiCertHash = { 0xZZ, 0xYY, ....};

/// <summary>
/// Somewhere in your application's startup/init sequence...
/// </summary>
void InitPhase()
{
    // Override automatic validation of SSL server certificates.
    ServicePointManager.ServerCertificateValidationCallback =
           ValidateServerCertficate;
}

/// <summary>
/// Validates the SSL server certificate.
/// </summary>
/// <param name="sender">An object that contains state information for this
/// validation.</param>
/// <param name="cert">The certificate used to authenticate the remote party.</param>
/// <param name="chain">The chain of certificate authorities associated with the
/// remote certificate.</param>
/// <param name="sslPolicyErrors">One or more errors associated with the remote
/// certificate.</param>
/// <returns>Returns a boolean value that determines whether the specified
/// certificate is accepted for authentication; true to accept or false to
/// reject.</returns>
private static bool ValidateServerCertficate(
        object sender,
        X509Certificate cert,
        X509Chain chain,
        SslPolicyErrors sslPolicyErrors)
{
    if (sslPolicyErrors == SslPolicyErrors.None)
    {
        // Good certificate.
        return true;
    }

    log.DebugFormat("SSL certificate error: {0}", sslPolicyErrors);

    bool certMatch = false; // Assume failure
    byte[] certHash = cert.GetCertHash();
    if (certHash.Length == apiCertHash.Length)
    {
        certMatch = true; // Now assume success.
        for (int idx = 0; idx < certHash.Length; idx++)
        {
            if (certHash[idx] != apiCertHash[idx])
            {
                certMatch = false; // No match
                break;
            }
        }
    }

    // Return true => allow unauthenticated server,
    //        false => disallow unauthenticated server.
    return certMatch;
}

0 votes

Probablement quelqu'un qui a préféré la bonne méthode ci-dessous. Quoi qu'il en soit, ce hack fonctionne à la rigueur, mais vous ne devriez probablement pas coder ce genre d'exceptions... soit vous désactivez tout simplement la vérification (via la suggestion ci-dessous), soit vous demandez à votre ordinateur de faire confiance au certificat...

4 votes

@BrainSlugs83 : La désactivation est certainement une option aussi, mais l'ajout de la cert au magasin des autorités racine au niveau de la machine ne peut être fait que par les administrateurs. Ma solution fonctionne dans les deux cas.

0 votes

Et je comprends parfaitement cela, mais vous avez demandé, et c'est toujours mon avis sur la raison pour laquelle quelqu'un a noté votre réponse. Et même si elle demande plus de travail, la réponse de wgthom ci-dessous est toujours la plus correcte.

51voto

user2117074 Points 101

Notez que dans .NET 4.5, vous pouvez remplacer la validation SSL par HttpWebRequest lui-même (et non par un délégué global qui affecte toutes les requêtes) :

http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.servercertificatevalidationcallback.aspx

1 votes

S'il vous plaît upvotez ceci ; cela vaut la peine de passer en 4.5 pour cela !

1 votes

@FlorianWinter Oui, vous devez adopter la logique de l'utilisateur devstuff

47voto

wgthom Points 234

Ajoutez le certificat auto-signé aux autorités de certification racine de confiance de l'ordinateur local.

Vous pouvez importer le certificat en exécutant la MMC en tant qu'administrateur.

Comment : Afficher les certificats à l'aide du module instantané MMC

5 votes

À mon avis, c'est la façon la plus correcte de procéder ; les gens sont simplement trop paresseux pour coder des exceptions spéciales pour des choses qu'ils ne devraient probablement pas faire.

4 votes

Cette méthode fonctionne-t-elle pour Windows Mobile 6.5 ? Et pour 7 ? Dans mon cas, je ne voulais pas avoir à ajouter un certificat local à chaque appareil mobile sur lequel je prévoyais d'exécuter une version de développement. Une bonne exception, dans ce cas, facilite grandement le déploiement. Paresse ou efficacité, à vous de me le dire.

3 votes

@domster Vous utilisez les certificats SSL pour une raison - pour vérifier les points de terminaison. Si vous développez un code qui contourne spécifiquement ce problème, vous ne le testez pas correctement et vous risquez de laisser échapper ce code dans un environnement réel. Si l'installation d'un certificat sur le client représente vraiment trop de travail, pourquoi ne pas payer un certificat auprès d'un émetteur auquel tous les appareils font confiance ?

36voto

Nathan Baulch Points 7994

La portée du rappel de validation utilisé dans La réponse de Domster peut être limitée à une demande spécifique en utilisant le paramètre d'expéditeur de la fonction ServerCertificateValidationCallback délégué. La classe scope simple suivante utilise cette technique pour mettre en place temporairement un rappel de validation qui ne s'exécute que pour un objet de demande donné.

public class ServerCertificateValidationScope : IDisposable
{
    private readonly RemoteCertificateValidationCallback _callback;

    public ServerCertificateValidationScope(object request,
        RemoteCertificateValidationCallback callback)
    {
        var previous = ServicePointManager.ServerCertificateValidationCallback;
        _callback = (sender, certificate, chain, errors) =>
            {
                if (sender == request)
                {
                    return callback(sender, certificate, chain, errors);
                }
                if (previous != null)
                {
                    return previous(sender, certificate, chain, errors);
                }
                return errors == SslPolicyErrors.None;
            };
        ServicePointManager.ServerCertificateValidationCallback += _callback;
    }

    public void Dispose()
    {
        ServicePointManager.ServerCertificateValidationCallback -= _callback;
    }
}

La classe ci-dessus peut être utilisée pour ignorer toutes les erreurs de certificat pour une demande spécifique comme suit :

var request = WebRequest.Create(uri);
using (new ServerCertificateValidationScope(request, delegate { return true; }))
{
    request.GetResponse();
}

6 votes

Cette réponse a besoin de plus de votes positifs :) C'est la réponse la plus raisonnable pour sauter la validation du certificat pour une seule requête utilisant un objet HttpWebRequest.

0 votes

J'ai ajouté ceci et j'obtiens toujours The request was aborted : Impossible de créer un canal sécurisé SSL/TLS.

8 votes

Cela ne résout pas vraiment le problème dans un environnement multithread.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X