Impossible d'établir une relation d'approbation pour le canal sécurisé SSL / TLS - SOAP

326

J'ai un simple appel de service Web, généré par une application Windows .NET (C #) 2.0, via le proxy de service Web généré par Visual Studio, pour un service Web également écrit en C # (2.0). Cela fonctionne depuis plusieurs années et continue de le faire dans la douzaine d'endroits où il fonctionne.

Une nouvelle installation sur un nouveau site rencontre un problème. Lorsque vous essayez d'appeler le service Web, il échoue avec le message disant:

Impossible d'établir une relation d'approbation pour le canal sécurisé SSL / TLS

L'URL du service Web utilise SSL (https: //) - mais cela fonctionne depuis longtemps (et continue de le faire) à partir de nombreux autres emplacements.

Où est-ce que je regarde? Serait-ce un problème de sécurité entre Windows et .NET propre à cette installation? Si oui, où dois-je établir des relations de confiance? Je suis perdu!

Rob Schripsema
la source
Dans mon cas, cette erreur a été causée par le transfert d'adresse IP.
cja

Réponses:

166

Pensées (basées sur la douleur du passé):

  • avez-vous un DNS et une visibilité directe sur le serveur?
  • utilisez-vous le nom correct du certificat?
  • le certificat est-il toujours valide?
  • un équilibreur de charge mal configuré gâche-t-il les choses?
  • la nouvelle machine serveur a -t-elle l'horloge correctement réglée (c'est-à-dire pour que l'heure UTC soit correcte [ignorer l'heure locale, elle est largement hors de propos]) - cela est certainement important pour WCF, donc peut-il avoir un impact sur SOAP régulier?
  • y a-t-il un problème de chaîne d'approbation de certificat? si vous naviguez du serveur au service soap, pouvez-vous obtenir SSL?
  • liés à ce qui précède - le certificat a-t-il été installé au bon endroit? (vous pourriez avoir besoin d'une copie dans les autorités de certification racines de confiance)
  • le proxy au niveau machine du serveur est-il correctement défini? (différent du proxy de l'utilisateur); voir proxycfg pour XP / 2003 (pas sûr de Vista, etc.)
Marc Gravell
la source
2
1) Le service Web est sur le Web. Nous pouvons y accéder via un navigateur. 2) La nouvelle machine n'est pas un serveur - c'est un bureau exécutant mon application, qui recueille les informations de commande et les télécharge via le service SOAP 3) Oui, nous pouvons y accéder. 4) C'est nouveau pour moi: proxy au niveau de la machine?
Rob Schripsema
2
Oui; le code n'utilise pas les paramètres du proxy IE; il utilise un magasin séparé ... il est important que ce soit configuré (si vous utilisez un proxy). Sous XP, l'option la plus simple est (IIRC) "proxycfg -i" pour importer les paramètres IE.
Marc Gravell
11
Merci Marc. Cela m'a aidé et le problème était que le serveur avait un certificat signé par une autorité de certification tierce à laquelle je n'avais pas encore confiance. La solution consistait à ajouter cette autorité de certification à la liste des autorités de certification racines de confiance.
p.campbell
1
L'ordinateur qui rencontrait cette exception n'a pas pu synchroniser l'heure système à l'aide des serveurs de temps. J'ai dû entrer et synchroniser manuellement l'heure avant que cela fonctionne.
Chris - Haddox Technologies
4
Vous pouvez l'obtenir si vous avez utilisé Fiddler pour déboguer des appels de service et avez utilisé son mode d'interception de certificat. Supprimez simplement l'interception dans les options du violoniste et vous devriez être bon
Ruskin
363

Les extraits suivants résoudront le cas où quelque chose ne va pas avec le certificat SSL sur le serveur que vous appelez. Par exemple, il peut être auto-signé ou le nom d'hôte entre le certificat et le serveur peut ne pas correspondre.

Cela est dangereux si vous appelez un serveur hors de votre contrôle direct, car vous ne pouvez plus être sûr de parler au serveur auquel vous pensez être connecté. Cependant, si vous avez affaire à des serveurs internes et que l'obtention d'un certificat "correct" n'est pas pratique, utilisez ce qui suit pour dire au service Web d'ignorer les problèmes de certificat et bravement de continuer.

Les deux premiers utilisent des expressions lambda, le troisième utilise du code normal. Le premier accepte tout certificat. Les deux derniers au moins vérifient que le nom d'hôte dans le certificat est celui que vous attendez.
... j'espère que vous le trouverez utile

//Trust all certificates
System.Net.ServicePointManager.ServerCertificateValidationCallback =
    ((sender, certificate, chain, sslPolicyErrors) => true);

// trust sender
System.Net.ServicePointManager.ServerCertificateValidationCallback
                = ((sender, cert, chain, errors) => cert.Subject.Contains("YourServerName"));

// validate cert by calling a function
ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(ValidateRemoteCertificate);

// callback used to validate the certificate in an SSL conversation
private static bool ValidateRemoteCertificate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors policyErrors)
{
    bool result = cert.Subject.Contains("YourServerName");
    return result;
}
Sebastian Castaldi
la source
6
Mon expérience avec ServicePointManager. Toute modification de celui-ci affecterait l'intégralité du domaine d'application. Bien que la réponse soit expliquée très clairement comment cela peut être appliqué, j'aime jeter ce point.
Amzath
La définition du rappel fonctionne dans .NET 4.5 pour moi, mais pas .NET 4.6
RJB
@Amzath Avez-vous des suggestions sur la façon de réinitialiser cela une fois qu'une demande particulière est terminée? Une personne peut avoir besoin de faire une demande à un serveur non certifié, puis de remettre les choses telles qu'elles étaient.
Isaac Lyman
1
@Isaac Lyman: ServicePointManager.ServerCertificateValidationCallback = null;devrait revenir au comportement par défaut.
Mike Chamberlain
1
@MikeChamberlain Le seul problème avec votre suggestion est que les requêtes simultanées peuvent être rendues non sécurisées car vous avez affaire à un paramètre d'application global.
Isaac Lyman
178

La solution très simple "catch all" est la suivante:

System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

La solution de sebastian-castaldi est un peu plus détaillée.

Rémy
la source
21
Je viens de mettre cela dans une #If CONFIG = "Debug"déclaration afin qu'il ne soit activé qu'en mode débogage. Ça marche super!
cjbarth
1
Les détails peuvent être bons, mais il y a aussi quelque chose à dire pour une ligne de code rapide, courte et facile. Ce code est court et fait l'affaire.
allen1
cela n'agira-t-il que sur l'action actuelle (par exemple, ASP MVC est utilisé)? ou il définira le comportement par défaut de l'application ASP.NET?
JeeShen Lee
2
Cela ne doit être utilisé qu'à des fins de test, cette solution fait confiance à tout certificat, même invalide / expiré
Shenron
1
Comme expliqué dans les commentaires ci-dessus, cela ne vérifie plus si la connexion SSL est valide. La connexion entre votre système et d'autres systèmes peut donc être compromise. C'est toujours une question de savoir pourquoi vous en avez besoin.
Remy
35

Personnellement, j'aime le plus la solution suivante:

using System.Security.Cryptography.X509Certificates;
using System.Net.Security;

... puis avant de demander à obtenir l'erreur, procédez comme suit

System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };

Trouvé cela après avoir consulté la solution de Luke

cusman
la source
4
Voir la réponse de Sebastian Castaldi pour les mises en garde de sécurité à cette approche.
Edward Brey
Quel est le risque pour la sécurité de l’utiliser en production?
Amjad
@Amjad le risque de sécurité est qu'il élude complètement tous les avantages de l'utilisation de SSL / TLS. Le serveur peut présenter n'importe quel certificat qu'il souhaite, et ce code ignorera l'erreur
1800 INFORMATION
18

Si vous utilisez Windows 2003, vous pouvez essayer ceci:

Ouvrez Microsoft Management Console (Démarrer -> Exécuter -> mmc.exe);

Choisissez Fichier -> Ajouter / Supprimer un composant logiciel enfichable;

Dans l'onglet Autonome, choisissez Ajouter;

Choisissez le composant logiciel enfichable Certificats, puis cliquez sur Ajouter;

Dans l'assistant, choisissez le compte d'ordinateur, puis choisissez ordinateur local. Appuyez sur Terminer pour fermer l'assistant;

Fermez la boîte de dialogue Ajouter / Supprimer un composant logiciel enfichable;

Accédez à Certificats (ordinateur local) et choisissez un magasin à importer:

Si vous disposez du certificat d'autorité de certification racine pour la société qui a émis le certificat, choisissez Autorités de certification racines de confiance;

Si vous avez le certificat pour le serveur lui-même, choisissez Autres personnes

Cliquez avec le bouton droit sur le magasin et choisissez Toutes les tâches -> Importer

Suivez l'assistant et fournissez le fichier de certificat que vous avez;

Après cela, redémarrez simplement IIS et essayez à nouveau d'appeler le service Web.

Référence: http://www.outsystems.com/NetworkForums/ViewTopic.aspx?Topic=Web-Services:-Could-not-establish-trust-relationship-for-the-SSL/TLS- ...

Diogo
la source
2
Cela m'a permis de faire une partie du chemin, mais j'avais besoin d'avoir le certificat dans la section Autorités de certification racines de confiance pour le faire fonctionner. Selon blogs.msdn.com/b/jpsanders/archive/2009/09/16/…
Jacob Ewald
17

Si vous ne voulez pas faire confiance à tout le monde aveuglément et ne faire une exception de confiance que pour certains hôtes, la solution suivante est plus appropriée.

public static class Ssl
{
    private static readonly string[] TrustedHosts = new[] {
      "host1.domain.com", 
      "host2.domain.com"
    };

    public static void EnableTrustedHosts()
    {
      ServicePointManager.ServerCertificateValidationCallback = 
      (sender, certificate, chain, errors) =>
      {
        if (errors == SslPolicyErrors.None)
        {
          return true;
        }

        var request = sender as HttpWebRequest;
        if (request != null)
        {
          return TrustedHosts.Contains(request.RequestUri.Host);
        }

        return false;
      };
    }
}

Ensuite, appelez simplement Ssl.EnableTrustedHosts au démarrage de votre application.

Gregor Slavec
la source
@thelem Oui relecture Je pense que je dois avoir mal lu la première fois
Shiv
Quel est le risque pour la sécurité de faire confiance à tous les certificats en production?
Amjad
@Amjad le risque de sécurité est que toute personne entre le client et le serveur peut s'insérer au milieu des communications, utiliser son propre certificat SSL et lire tout le trafic entre le client et le serveur. Faire cela invalide efficacement SSL.
Rob Prouse
Doit-il fonctionner lorsque j'utilise l'addon WCF pour générer des classes à partir de wsdl?
Kamil
7

Luke a écrit un très bon article à ce sujet .. assez simple .. essayez-le

La solution de Luke

Raison (citation de son article (moins la malédiction)) ".. Le problème avec le code ci-dessus est qu'il ne fonctionne pas si votre certificat n'est pas valide. Pourquoi devrais-je publier sur une page Web avec un certificat SSL invalide? Parce que Je suis bon marché et je n'avais pas envie de payer Verisign ou l'un des autres ** - * s pour un certificat dans ma boîte de test, donc je l'ai signé moi-même. Lorsque j'ai envoyé la demande, j'ai reçu une belle exception:

System.Net.WebException La connexion sous-jacente a été fermée. Impossible d'établir une relation d'approbation avec le serveur distant.

Je ne sais pas pour vous, mais pour moi, cette exception ressemblait à quelque chose qui serait causé par une erreur stupide dans mon code qui provoquait l'échec du POST. J'ai donc continué à chercher, à peaufiner et à faire toutes sortes de choses étranges. Ce n'est qu'après avoir googlé la chose *** n que j'ai découvert que le comportement par défaut après avoir rencontré un certificat SSL non valide consiste à lever cette exception. .. "

Hans
la source
1
Cette solution est obsolète pour .Net 4.5. Si vous voulez simplement accepter tous les certificats, consultez Sebastian Castaldi ou ma réponse ci-dessous.
Remy
7

L' outil de diagnostic SSL de Microsoft peut être en mesure d'identifier le problème.

MISE À JOUR le lien a été corrigé maintenant.

sipwiz
la source
7
À ce jour (août 2012), ce lien est désormais rompu.
ashes999
Recherche dans le répertoire de téléchargement et aucun outil de diagnostic SSL n'est plus disponible. :(
SASS_Shooter
2
Fixons le lien. Corrigez-moi si je me trompe iis.net/downloads/community/2009/09/…
Amzath
3

Je viens de rencontrer ce problème. Ma résolution était de mettre à jour l'heure du système en effectuant une synchronisation manuelle avec les serveurs de temps. Pour ce faire, vous pouvez:

  • Cliquez avec le bouton droit sur l'horloge dans la barre des tâches
  • Sélectionner Adjust Date/Time
  • Sélectionnez l' Internet Timeonglet
  • Cliquez sur Change Settings
  • Sélectionner Update Now

Dans mon cas, la synchronisation était incorrecte, j'ai donc dû cliquer plusieurs fois avant de la mettre à jour correctement. S'il continue de se mettre à jour de manière incorrecte, vous pouvez même essayer d'utiliser un serveur de temps différent du menu déroulant du serveur.

Chris - Technologies Haddox
la source
VACHE SAINTE. Ran a frappé dans cette chose exacte. Merci pour la solution facile!
TheGerm
3

Essaye ça:

System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;

Notez que vous devez travailler au moins avec le framework 4.5 .NET

Manuel Roldan
la source
3

J'ai eu un problème similaire .NET application dans Internet Explorer.

J'ai résolu le problème d'ajout du certificat (certificat VeriSign Class 3 dans mon cas) aux certificats des éditeurs de confiance.

Go to Internet Options-> Content -> Publishers and import it

Vous pouvez obtenir le certificat si vous l'exportez de:

Internet Options-> Content -> Certificates -> Intermediate Certification Authorities -> VeriSign Class 3 Public Primary Certification Authority - G5

Merci

debiasej
la source
1

J'ai eu cette erreur en cours d'exécution sur un serveur Web avec une URL comme:

a.b.domain.com

mais il n'y avait pas de certificat pour ça, donc j'ai eu un DNS appelé

a_b.domain.com

Il suffit de donner un indice à cette solution ici, car elle est arrivée en tête dans Google.

Thomas Koelle
la source
Dans mon cas, le site Web a été configuré sous un certificat SSL générique (* .abcd.com). Une fois configurée, la liaison du site Web était comme xyz-abcd.com, ce qui causait le problème.
Sree
1

Pour ceux qui rencontrent ce problème via un côté client VS, une fois la référence de service ajoutée avec succès et la tentative d'exécution du premier appel, cette exception a été obtenue: «La connexion sous-jacente a été fermée: impossible d'établir une relation de confiance pour le canal sécurisé SSL / TLS» si vous utilisez (comme dans mon cas) une URL de point de terminaison avec l'adresse IP et avez obtenu cette exception, vous devrez probablement ajouter à nouveau la référence de service en procédant comme suit:

  • Ouvrez l'URL du point de terminaison sur Internet Explorer.
  • Cliquez sur l'erreur de certificat (icône rouge dans la barre d'adresse)
  • Cliquez sur Afficher les certificats.
  • Saisissez le délivré à: "nom" et remplacez l'adresse IP ou le nom que nous utilisions et obtenez l'erreur pour ce "nom".

Réessayer :). Merci

Ernest
la source
0

Dans mon cas, j'essayais de tester SSL dans mon environnement Visual Studio à l'aide d'IIS 7.

Voici ce que j'ai fini par faire pour que ça marche:

  • Sous mon site dans la section "Liaisons ..." à droite dans IIS, j'ai dû ajouter la liaison "https" au port 443 et sélectionner "IIS Express Developement Certificate".

  • Sous mon site dans la section "Paramètres avancés ..." à droite, j'ai dû changer les "protocoles activés" de "http" en "https".

  • Sous l'icône «Paramètres SSL», j'ai sélectionné «Accepter» pour les certificats clients.

  • Ensuite, j'ai dû recycler le pool d'applications.

  • J'ai également dû importer le certificat d'hôte local dans ma boutique personnelle à l'aide de mmc.exe.

Mon web.configfichier était déjà configuré correctement, donc après avoir trié tout ce qui précède, j'ai pu continuer mes tests.

Popo
la source
comment votre web.config a-t-il été configuré?
Chazt3n
@ Chazt3n Je ne pourrais pas vous le dire, c'était il y a quelque temps, mais cela aurait été une configuration de base de liaison http, j'utilise généralement svcutil pour générer des informations de configuration pour les informations du client de service Web.
Popo
0

Ma solution (VB.Net, la version "staging" (UAT) de cette application doit fonctionner avec le certificat "staging" mais ne pas affecter les requêtes une fois qu'elles sont sur le site live):

    ...
        Dim url As String = ConfigurationManager.AppSettings("APIURL") & "token"
        If url.ToLower().Contains("staging") Then
           System.Net.ServicePointManager.ServerCertificateValidationCallback = AddressOf AcceptAllCertifications
        End If
    ...

    Private  Function AcceptAllCertifications(ByVal sender As Object, ByVal certification As System.Security.Cryptography.X509Certificates.X509Certificate, ByVal chain As System.Security.Cryptography.X509Certificates.X509Chain, ByVal sslPolicyErrors As System.Net.Security.SslPolicyErrors) As Boolean
        Return True
    End Function
GreenRock
la source
-3

Si cela ne fonctionne pas, mauvais sertificate, lorsque ServerCertificateValidationCallback renvoie true; Mon code ServerCertificateValidationCallback:

ServicePointManager.ServerCertificateValidationCallback += delegate
{
    LogWriter.LogInfo("Проверка сертификата отключена, на уровне ServerCertificateValidationCallback");
    return true;
};

Mon code qui l'empêchait d'exécuter ServerCertificateValidationCallback:

     if (!(ServicePointManager.CertificatePolicy is CertificateValidation))
    {
        CertificateValidation certValidate = new CertificateValidation();
        certValidate.ValidatingError += new CertificateValidation.ValidateCertificateEventHandler(this.OnValidateCertificateError);
        ServicePointManager.CertificatePolicy = certValidate;
    }

Fonction OnValidateCertificateError:

private void OnValidateCertificateError(object sender, CertificateValidationEventArgs e)
{
    string msg = string.Format(Strings.OnValidateCertificateError, e.Request.RequestUri, e.Certificate.GetName(), e.Problem, new Win32Exception(e.Problem).Message);
    LogWriter.LogError(msg);
    //Message.ShowError(msg);
}

J'ai désactivé le code CertificateValidation et ServerCertificateValidationCallback fonctionnant très bien

Roberto Gata
la source
Vous ne devez jamais désactiver aucune validation de certificat. Au lieu de cela, corrigez le problème à l'origine de l'échec de la validation.
Dan
Quel est le risque pour la sécurité de l’utiliser en production?
Amjad