Vertrauensbeziehung für SSL / TLS Secure Channel - SOAP konnte nicht hergestellt werden


325

Ich habe einen einfachen Webdienstaufruf, der von einer .NET (C #) 2.0-Windows-App über den von Visual Studio generierten Webdienst-Proxy für einen ebenfalls in C # (2.0) geschriebenen Webdienst generiert wird. Dies funktioniert seit mehreren Jahren und wird auch weiterhin an etwa einem Dutzend Orten durchgeführt, an denen es ausgeführt wird.

Bei einer Neuinstallation an einem neuen Standort tritt ein Problem auf. Beim Versuch, den Webdienst aufzurufen, schlägt die folgende Meldung fehl:

Es konnte keine Vertrauensbeziehung für den sicheren SSL / TLS-Kanal hergestellt werden

Die URL des Webdienstes verwendet SSL (https: //) - dies funktioniert jedoch seit langem (und wird auch weiterhin) von vielen anderen Standorten aus.

Wo schaue ich Könnte dies ein Sicherheitsproblem zwischen Windows und .NET sein, das nur bei dieser Installation auftritt? Wenn ja, wo richte ich Vertrauensbeziehungen ein? Ich bin verloren!


In meinem Fall wurde dieser Fehler durch die Weiterleitung der IP-Adresse verursacht.
Cja

Antworten:


166

Gedanken (basierend auf Schmerzen in der Vergangenheit):

  • Haben Sie DNS und Sichtverbindung zum Server?
  • Verwenden Sie den richtigen Namen aus dem Zertifikat?
  • Ist das Zertifikat noch gültig?
  • Ist ein schlecht konfigurierter Load Balancer durcheinander?
  • Ist auf dem neuen Server die Uhr richtig eingestellt (dh die UTC-Zeit ist korrekt [Ortszeit ignorieren, sie spielt keine Rolle]) - dies ist sicherlich für WCF von Bedeutung und kann sich daher auf die reguläre SOAP auswirken.
  • Gibt es ein Problem mit der Zertifikatsvertrauenskette? Können Sie SSL erhalten, wenn Sie vom Server zum Seifendienst navigieren?
  • im Zusammenhang mit dem oben genannten - Wurde das Zertifikat am richtigen Ort installiert? (Möglicherweise benötigen Sie eine Kopie in Trusted Root Certification Authorities.)
  • Ist der Proxy auf Maschinenebene des Servers richtig eingestellt? (die sich vom Proxy des Benutzers unterscheiden); siehe proxycfg für XP / 2003 (nicht sicher über Vista usw.)

2
1) Der Webdienst ist im Web. Wir können über einen Browser darauf zugreifen. 2) Neue Maschine ist kein Server - es ist ein Desktop, auf dem meine App ausgeführt wird, der Bestellinformationen sammelt und über den SOAP-Dienst hochlädt. 3) Ja, wir können dorthin navigieren. 4) Das ist neu für mich: Proxy auf Maschinenebene?
Rob Schripsema

2
Ja; Code verwendet nicht die IE-Proxy-Einstellungen. Es wird ein separater Speicher verwendet. Es ist wichtig, dass dieser konfiguriert ist (wenn Sie einen Proxy verwenden). Unter XP ist (IIRC) "proxycfg -i" die einfachste Option, um die IE-Einstellungen zu importieren.
Marc Gravell

11
Danke Marc. Dies hat mir geholfen, und das Problem war, dass auf dem Server ein Zertifikat von einer Drittanbieter-Zertifizierungsstelle signiert war, der ich noch nicht vertraut hatte. Die Lösung bestand darin, diese Zertifizierungsstelle zur Liste der vertrauenswürdigen Stammzertifizierungsstellen hinzuzufügen.
p.campbell

1
Der Computer mit dieser Ausnahme konnte die Systemzeit nicht über die Zeitserver synchronisieren. Ich musste die Zeit, bevor es funktionierte, manuell synchronisieren.
Chris - Haddox Technologies

4
Möglicherweise erhalten Sie dies, wenn Sie Fiddler zum Debuggen von Dienstaufrufen verwendet und den Zertifikatabfangmodus verwendet haben. Entfernen Sie einfach das Abfangen in den Optionen des Geigers und Sie sollten gut sein
Ruskin

363

Die folgenden Snippets beheben den Fall, dass mit dem SSL-Zertifikat auf dem Server, den Sie anrufen, ein Fehler vorliegt. Beispielsweise kann es selbstsigniert sein oder der Hostname zwischen dem Zertifikat und dem Server stimmt möglicherweise nicht überein.

Dies ist gefährlich, wenn Sie einen Server außerhalb Ihrer direkten Kontrolle anrufen, da Sie nicht mehr so ​​sicher sein können, dass Sie mit dem Server sprechen, mit dem Sie verbunden sind. Wenn Sie jedoch mit internen Servern zu tun haben und es nicht praktikabel ist, ein "korrektes" Zertifikat zu erhalten, verwenden Sie die folgenden Anweisungen, um den Webdienst anzuweisen, die Zertifikatprobleme zu ignorieren und mutig zu arbeiten.

Die ersten beiden verwenden Lambda-Ausdrücke, die dritte verwendet regulären Code. Der erste akzeptiert jedes Zertifikat. Die letzten beiden überprüfen mindestens, ob der Hostname im Zertifikat der erwartete ist.
... hoffe du findest es hilfreich

//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;
}

6
Meine Erfahrung mit ServicePointManager. Jede Änderung würde sich auf die gesamte App-Domain auswirken. Obwohl die Antwort sehr klar erklärt wird, wie dies angewendet werden kann, möchte ich diesen Punkt ansprechen.
Amzath

Das Einstellen des Rückrufs funktioniert in .NET 4.5 für mich, aber nicht in .NET 4.6
RJB

@Amzath Irgendwelche Vorschläge, wie dies nach Abschluss einer bestimmten Anfrage zurückgesetzt werden kann? Möglicherweise muss eine Person eine Anfrage an einen nicht zertifizierten Server stellen und dann die Dinge wieder so einstellen, wie sie waren.
Isaac Lyman

1
@Isaac Lyman: ServicePointManager.ServerCertificateValidationCallback = null;sollte zum Standardverhalten zurückkehren.
Mike Chamberlain

1
@MikeChamberlain Das einzige Problem mit Ihrem Vorschlag ist, dass gleichzeitige Anforderungen möglicherweise unsicher werden, da Sie mit einer globalen App-Einstellung arbeiten.
Isaac Lyman

178

Die sehr einfache "catch all" -Lösung lautet:

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

Die Lösung von Sebastian-Castaldi ist etwas detaillierter.


21
Ich habe dies nur in eine #If CONFIG = "Debug"Anweisung eingefügt, damit es nur im Debug-Modus aktiviert wird. Es funktioniert super!
CJBarth

1
Details können gut sein, aber es gibt auch etwas zu sagen für eine schnelle, kurze und einfache Codezeile. Dieser Code ist kurz und macht den Trick.
Allen1

Wird dies nur auf die aktuelle Aktion angewendet (z. B. wird ASP MVC verwendet)? oder wird es als Standardverhalten für die ASP.NET-Anwendung festgelegt?
JeeShen Lee

2
Dies sollte nur zu Testzwecken verwendet werden. Diese Lösung vertraut jedem Zertifikat, auch ungültigen / abgelaufenen
Shenron

1
Wie in den obigen Kommentaren erläutert, wird dadurch nicht überprüft, ob die SSL-Verbindung mehr gültig ist. Daher kann die Verbindung zwischen Ihrem System und anderen Systemen beeinträchtigt werden. Es ist immer eine Frage, wofür Sie das brauchen.
Remy

35

Ich persönlich mag die folgende Lösung am meisten:

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

... bevor Sie den Fehler anfordern, gehen Sie wie folgt vor

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

Fand dies nach Rücksprache mit Luke's Solution


4
In der Antwort von Sebastian Castaldi finden Sie Sicherheitsvorkehrungen für diesen Ansatz.
Edward Brey

Was ist das Sicherheitsrisiko bei der Verwendung in der Produktion?
Amjad

@Amjad das Sicherheitsrisiko besteht darin, dass alle Vorteile der Verwendung von SSL / TLS vollständig umgangen werden. Der Server kann jedes beliebige Zertifikat vorlegen, und dieser Code ignoriert den Fehler
1800 INFORMATION

18

Wenn Sie Windows 2003 verwenden, können Sie Folgendes versuchen:

Öffnen Sie die Microsoft Management Console (Start -> Ausführen -> mmc.exe).

Wählen Sie "Datei" -> "Snap-In hinzufügen / entfernen".

Wählen Sie auf der Registerkarte "Standalone" die Option "Hinzufügen".

Wählen Sie das Zertifikat-Snap-In aus und klicken Sie auf Hinzufügen.

Wählen Sie im Assistenten das Computerkonto und dann Lokaler Computer. Drücken Sie Fertig stellen, um den Assistenten zu beenden.

Schließen Sie das Dialogfeld "Snap-In hinzufügen / entfernen".

Navigieren Sie zu Zertifikate (lokaler Computer) und wählen Sie ein Geschäft aus, das importiert werden soll:

Wenn Sie über das Stammzertifizierungsstellenzertifikat für das Unternehmen verfügen, das das Zertifikat ausgestellt hat, wählen Sie Vertrauenswürdige Stammzertifizierungsstellen.

Wenn Sie das Zertifikat für den Server selbst haben, wählen Sie Andere Personen

Klicken Sie mit der rechten Maustaste auf das Geschäft und wählen Sie Alle Aufgaben -> Importieren

Folgen Sie dem Assistenten und geben Sie die Zertifikatdatei an, über die Sie verfügen.

Starten Sie danach einfach IIS neu und rufen Sie den Webdienst erneut auf.

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


2
Dies hat mich teilweise dazu gebracht, aber ich musste das Zertifikat im Abschnitt Vertrauenswürdige Stammzertifizierungsstellen haben, damit es funktioniert. Gemäß blogs.msdn.com/b/jpsanders/archive/2009/09/16/...
Jacob Ewald

17

Wenn Sie nicht jedem blind vertrauen und nur für bestimmte Hosts eine Vertrauensausnahme machen möchten, ist die folgende Lösung besser geeignet.

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;
      };
    }
}

Rufen Sie dann einfach Ssl.EnableTrustedHosts auf, wenn Ihre App gestartet wird.


@thelem Ja noch einmal lesen Ich denke, ich muss das erste Mal falsch gelesen haben
Shiv

Was ist das Sicherheitsrisiko, wenn Sie allen Zertifikaten in der Produktion vertrauen?
Amjad

@Amjad Das Sicherheitsrisiko besteht darin, dass sich jeder zwischen dem Client und dem Server mitten in die Kommunikation einfügen, sein eigenes SSL-Zertifikat verwenden und den gesamten Datenverkehr zwischen Client und Server lesen kann. Dadurch wird SSL effektiv ungültig.
Rob Prouse

Sollte es funktionieren, wenn ich ein WCF-Addon verwende, um Klassen aus wsdl zu generieren?
Kamil

7

Luke hat einen ziemlich guten Artikel darüber geschrieben. Ganz einfach. Probieren Sie es aus

Lukes Lösung

Grund (Zitat aus seinem Artikel (minus Fluchen)) ".. Das Problem mit dem obigen Code ist, dass es nicht funktioniert, wenn Ihr Zertifikat nicht gültig ist. Warum sollte ich auf einer Webseite mit und ungültigem SSL-Zertifikat posten? Weil Ich bin billig und hatte keine Lust, Verisign oder einen der anderen ** - * für ein Zertifikat an meine Testbox zu bezahlen, also habe ich es selbst unterschrieben. Als ich die Anfrage schickte, wurde mir eine schöne Ausnahme zugeworfen:

System.Net.WebException Die zugrunde liegende Verbindung wurde geschlossen. Es konnte keine Vertrauensbeziehung zum Remoteserver hergestellt werden.

Ich weiß nichts über dich, aber für mich sah diese Ausnahme wie etwas aus, das durch einen dummen Fehler in meinem Code verursacht wurde, der dazu führte, dass der POST fehlschlug. Also suchte ich weiter und optimierte und machte alle möglichen seltsamen Dinge. Erst nachdem ich das *** n-Ding gegoogelt hatte, stellte ich fest, dass das Standardverhalten nach dem Auftreten eines ungültigen SSL-Zertifikats darin besteht, genau diese Ausnahme auszulösen. .. "


1
Diese Lösung ist für .Net 4.5 veraltet. Wenn Sie nur alle Zertifikate akzeptieren möchten, lesen Sie Sebastian Castaldi oder meine Antwort weiter unten.
Remy


3

Ich bin gerade auf dieses Problem gestoßen. Mein Vorsatz war es, die Systemzeit durch manuelle Synchronisierung mit den Zeitservern zu aktualisieren. Dazu können Sie:

  • Klicken Sie mit der rechten Maustaste auf die Uhr in der Taskleiste
  • Wählen Adjust Date/Time
  • Wählen Sie die Internet TimeRegisterkarte
  • Klicken Change Settings
  • Wählen Update Now

In meinem Fall wurde dies falsch synchronisiert, sodass ich mehrmals darauf klicken musste, bevor es korrekt aktualisiert wurde. Wenn die Aktualisierung weiterhin nicht korrekt durchgeführt wird, können Sie sogar versuchen, einen anderen Zeitserver als das Server-Dropdown-Menü zu verwenden.


HEILIGER BIMBAM. Ich bin genau in diese Sache geraten. Danke für die einfache Lösung!
TheGerm

3

Versuche dies:

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

Beachten Sie, dass Sie mindestens mit 4.5 .NET Framework arbeiten müssen


3

Ich hatte ein ähnliches Problem in der .NETApp im Internet Explorer.

Ich habe das Problem beim Hinzufügen des Zertifikats (in meinem Fall VeriSign Class 3-Zertifikat) zu Zertifikaten vertrauenswürdiger Editoren gelöst.

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

Sie können das Zertifikat erhalten, wenn Sie es exportieren von:

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

Vielen Dank


1

Ich hatte diesen Fehler auf einem Webserver mit einer URL wie:

a.b.domain.com

Da es jedoch kein Zertifikat dafür gab, wurde ein DNS aufgerufen

a_b.domain.com

Ich möchte hier nur einen Hinweis auf diese Lösung geben, da dies in Google ganz oben stand.


In meinem Fall wurde die Website unter einem Wildcard-SSL-Zertifikat (* .abcd.com) konfiguriert. Bei der Konfiguration war die Website-Bindung wie bei xyz-abcd.com, was das Problem verursachte.
Sree

1

Für diejenigen, die dieses Problem über eine VS-Clientseite haben, nachdem sie erfolgreich eine Dienstreferenz hinzugefügt und versucht haben, den ersten Aufruf auszuführen, wurde die folgende Ausnahme angezeigt: "Die zugrunde liegende Verbindung wurde geschlossen: Es konnte keine Vertrauensbeziehung für den sicheren SSL / TLS-Kanal hergestellt werden." Wenn Sie (wie in meinem Fall) eine Endpunkt-URL mit der IP-Adresse verwenden und diese Ausnahme erhalten haben, müssen Sie wahrscheinlich die Dienstreferenz erneut hinzufügen, indem Sie die folgenden Schritte ausführen:

  • Öffnen Sie die Endpunkt-URL in Internet Explorer.
  • Klicken Sie auf den Zertifikatfehler (rotes Symbol in der Adressleiste)
  • Klicken Sie auf Zertifikate anzeigen.
  • Holen Sie sich den ausgegebenen Namen: "Name" und ersetzen Sie die IP-Adresse oder den von uns verwendeten Namen, um den Fehler für diesen "Namen" zu erhalten.

Versuch es noch einmal :). Vielen Dank


0

In meinem Fall habe ich versucht, SSL in meiner Visual Studio-Umgebung mit IIS 7 zu testen .

Folgendes habe ich getan, um es zum Laufen zu bringen:

  • Unter meiner Site im Abschnitt 'Bindungen ...' rechts in IIS musste ich die 'https'-Bindung zu Port 443 hinzufügen und "IIS Express-Entwicklungszertifikat" auswählen.

  • Unter meiner Website im Abschnitt "Erweiterte Einstellungen ..." auf der rechten Seite musste ich die "Aktivierten Protokolle" von "http" in "https" ändern.

  • Unter dem Symbol "SSL-Einstellungen" habe ich "Akzeptieren" für Client-Zertifikate ausgewählt.

  • Dann musste ich den App-Pool recyceln.

  • Ich musste auch das lokale Host-Zertifikat mit mmc.exe in meinen persönlichen Shop importieren.

Meine web.configDatei war bereits korrekt konfiguriert, und nachdem ich alle oben genannten Punkte erledigt hatte, konnte ich meine Tests fortsetzen.


Wie wurde Ihre web.config konfiguriert?
Chazt3n

@ Chazt3n Ich konnte Ihnen nicht sagen, dass dies eine Weile her ist, aber es wäre eine grundlegende Einrichtung für die http-Bindung gewesen. Normalerweise verwende ich svcutil, um Konfigurationsinformationen für Webdienst-Client-Informationen zu generieren.
Popo

0

Meine Lösung (VB.Net, die "Staging" (UAT) -Version dieser Anwendung muss mit dem "Staging" -Zertifikat arbeiten, aber keine Auswirkungen auf Anforderungen haben, sobald sie sich auf der Live-Site befinden):

    ...
        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

-3

Wenn nicht, funktioniert schlechtes Sertifikat, wenn ServerCertificateValidationCallback true zurückgibt; Mein ServerCertificateValidationCallback-Code:

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

Mein Code, den ServerCertificateValidationCallback verhindert hat:

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

OnValidateCertificateError-Funktion:

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);
}

Ich habe den CertificateValidation-Code deaktiviert und ServerCertificateValidationCallback läuft sehr gut


Sie sollten niemals eine Zertifikatvalidierung deaktivieren. Beheben Sie stattdessen das Problem, das die fehlgeschlagene Validierung verursacht.
Dan

Was ist das Sicherheitsrisiko bei der Verwendung in der Produktion?
Amjad
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.