"Die zugrunde liegende Verbindung wurde geschlossen: Beim Senden ist ein unerwarteter Fehler aufgetreten." Mit SSL-Zertifikat

119

Problem: Ich erhalte die Ausnahme "Die zugrunde liegende Verbindung wurde geschlossen: Ein unerwarteter Fehler trat bei einem Versand auf" in meinen Protokollen und es bricht unsere OEM-Integration in unser E-Mail-Marketing-System zu zufälligen Zeiten zwischen [1 Stunde - 4 Stunden].

Meine Website wird auf einem Windows Server 2008 R2 mit IIS 7.5.7600 gehostet. Diese Website enthält eine große Anzahl von OEM-Komponenten und ein umfassendes Dashboard. Mit allen anderen Elementen der Website funktioniert alles einwandfrei, mit Ausnahme einer unserer E-Mail-Marketing-Komponenten, die wir als Iframe-Lösung in unserem Dashboard verwenden. Die Art und Weise, wie es funktioniert, ist, ich sende ein httpWebRequestobject mit allen Anmeldeinformationen und ich bekomme eine URL zurück, die ich in einen Iframe eingefügt habe und es funktioniert. Aber es funktioniert nur für einige Zeit [1 Stunde - 4 Stunden] und dann erhalte ich die folgende Ausnahme: "Die zugrunde liegende Verbindung wurde geschlossen: Ein unerwarteter Fehler trat beim Senden auf" und selbst wenn das System versucht, die URL von httpWebRequest abzurufen schlägt mit der gleichen Ausnahme fehl. Die einzige Möglichkeit, es wieder zum Laufen zu bringen, besteht darin, den Anwendungspool zu recyceln oder irgendetwas in web.config zu bearbeiten.

Option ausprobiert

Explizit hinzugefügt, keep-alive = false

keep-alive = true

Erhöhte die Auszeit: <httpRuntime maxRequestLength="2097151" executionTimeout="9999999" enable="true" requestValidationMode="2.0" />

Ich habe diese Seite auf eine Nicht-SSL-Website hochgeladen, um zu überprüfen, ob das SSL-Zertifikat auf unserem Produktionsserver die Verbindung herstellt, um einige Schritte zu trennen.

Jede Richtung zur Auflösung wird sehr geschätzt.

Code:

Public Function CreateHttpRequestJson(ByVal url) As String
    Try
        Dim result As String = String.Empty
        Dim httpWebRequest = DirectCast(WebRequest.Create("https://api.xxxxxxxxxxx.com/api/v3/externalsession.json"), HttpWebRequest)
        httpWebRequest.ContentType = "text/json"
        httpWebRequest.Method = "PUT"
        httpWebRequest.ContentType = "application/x-www-form-urlencoded"
        httpWebRequest.KeepAlive = False
        'ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3

        'TODO change the integratorID to the serviceproviders account Id, useremail 
        Using streamWriter = New StreamWriter(httpWebRequest.GetRequestStream())
            Dim json As String = New JavaScriptSerializer().Serialize(New With { _
            Key .Email = useremail, _
            Key .Chrome = "None", _
            Key .Url = url, _
            Key .IntegratorID = userIntegratorID, _
            Key .ClientID = clientIdGlobal _
            })

            'TODO move it to the web.config, Following API Key is holonis accounts API Key
            SetBasicAuthHeader(httpWebRequest, holonisApiKey, "")
            streamWriter.Write(json)
            streamWriter.Flush()
            streamWriter.Close()

            Dim httpResponse = DirectCast(httpWebRequest.GetResponse(), HttpWebResponse)
            Using streamReader = New StreamReader(httpResponse.GetResponseStream())
                result = streamReader.ReadToEnd()
                result = result.Split(New [Char]() {":"})(2)
                result = "https:" & result.Substring(0, result.Length - 2)
            End Using
        End Using
        Me.midFrame.Attributes("src") = result
    Catch ex As Exception
        objLog.WriteLog("Error:" & ex.Message)
        If (ex.Message.ToString().Contains("Invalid Email")) Then
            'TODO Show message on UI
        ElseIf (ex.Message.ToString().Contains("Email Taken")) Then
            'TODO Show message on UI
        ElseIf (ex.Message.ToString().Contains("Invalid Access Level")) Then
            'TODO Show message on UI
        ElseIf (ex.Message.ToString().Contains("Unsafe Password")) Then
            'TODO Show message on UI
        ElseIf (ex.Message.ToString().Contains("Invalid Password")) Then
            'TODO Show message on UI
        ElseIf (ex.Message.ToString().Contains("Empty Person Name")) Then
            'TODO Show message on UI
        End If
    End Try
End Function


Public Sub SetBasicAuthHeader(ByVal request As WebRequest, ByVal userName As [String], ByVal userPassword As [String])
    Dim authInfo As String = Convert.ToString(userName) & ":" & Convert.ToString(userPassword)
    authInfo = Convert.ToBase64String(Encoding.[Default].GetBytes(authInfo))
    request.Headers("Authorization") = "Basic " & authInfo
End Sub`
Arvind Morwal
quelle
Hast du das jemals herausgefunden?
Brett G
11
Ja, ich konnte es mit diesem Code zum
Laufen bringen.
Ich wollte für das gleiche Problem sterben. Ich habe mehrere Stunden gebraucht, um mit dem gleichen Problem zu kämpfen. Vielen Dank für Ihre Kommentare, es hat meinen Tag gerettet.
Sameers Javed
2
@ user3458212 Sie sollten Ihren Kommentar als Antwort
hinzufügen
2
In meinem Fall funktioniert beim Ausführen der Website in Visual Studio 15 alles einwandfrei. Am Ende musste ich jedoch ein Intermediate einrichten, da ich das Framework auf dem Server nicht aktualisieren kann und das Erzwingen von TLS 1.2 und das Deaktivieren von Keep-Alive nicht funktioniert Webserver zum Proxy des Zielwebservers, der die Verbindung trennt.
José Roberto García Chico

Antworten:

193

Für mich war es tls12:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
Lanklaas
quelle
42
Beachten Sie, dass Sie vorsichtig sein müssen, da diese Änderung für Ihre AppDomain global ist und dazu führt, dass Anrufe an Websites, die kein TLS 1.2 anbieten, fehlschlagen (was Sie möglicherweise bevorzugen, wenn die zu transportierenden Daten wirklich vertraulich sind). Bevorzugen TLS 1.2 , aber immer noch erlauben , 1.1 und 1.0, müssen Sie ODER sie:ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
Dusty
Gleich hier hast du mein Leben gerettet und so viel Zeit damit verbracht herauszufinden, was mit RestSharp los war
darul75
Diese Lösung funktioniert auch für Benutzer, die RestSharp nicht verwenden, sowie für Benutzer, die ServicePointManager nicht verwenden. Kopieren Sie einfach die obige Zeile und fügen Sie sie vor Ihrem WebRequest-Aufruf oder was auch immer Sie für die Anforderung verwenden, ein. Ich habe diese Lösung aus den oben genannten Gründen zunächst ignoriert.
goku_da_master
oder fügen Sie es einfach zu dem hinzu, was bereits vorhanden ist ... System.Net.ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
uosjead
8
Um dies in PowerShell zu tun, "binär" oder "zusammen" wie [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls
Adam S
62

Wenn Sie mit .Net 4.0 nicht weiterkommen und die Zielwebsite TLS 1.2 verwendet, benötigen Sie stattdessen die folgende Zeile. ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;

Quelle: TLS 1.2- und .NET-Unterstützung: So vermeiden Sie Verbindungsfehler

Tochi
quelle
5
Genial! Ich würde nur hinzufügen, dass (SecurityProtocolType)768für "Tls11" (dh TLS 1.1) verwendet werden kann.
Solomon Rutzky
2
Das hilft wirklich. Es hat meinen Tag gerettet. Ich muss mich an .Net 2.0 halten.
Hao Nguyen
22

Der folgende Code hat das Problem behoben

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls Or SecurityProtocolType.Ssl3
Arvind Morwal
quelle
5
Dies würde jedoch funktionieren. Beachten Sie jedoch, dass ServicePointManager.SecurityProtocoles sich um ein statisches Objekt handelt. Dies bedeutet, dass das Ändern dieses Werts alle Teilsequenzen WebRequestoder WebClientAufrufe beeinflusst. Sie können separate Einstellungen vornehmen , AppDomainwenn Sie ServicePointManagerandere Einstellungen vornehmen möchten . Weitere Informationen finden Sie unter stackoverflow.com/questions/3791629/… .
stack247
1
Hilfreiche zusätzliche Lektüre, um zu verstehen, was dieser Code tut: stackoverflow.com/questions/26389899/…
Jon Schneider
@Marnee Ich habe es in das Kompositionsstammverzeichnis meiner Anwendung eingefügt, damit es festgelegt wird, bevor jemals eine E / A auftritt
JG in SD
@Marnee Fügen Sie es in einen statischen Konstruktor ein, damit es beim ersten Zugriff auf die Klasse genau einmal ausgeführt wird. Ich musste jedoch alle Protokolle aktivieren, um alle Fälle abzudecken.
Nyerguds
14

Ich habe seit Tagen das gleiche Problem mit einer Integration, die auch "früher nur funktioniert hat".

Aus purer Depression habe ich es einfach versucht

 ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Ssl3;

Dies löste es für mich. Auch wenn die Integration ausschließlich SSLv3 verwendet.

Ich kam zu der Erkenntnis, dass etwas nicht stimmt, seit Fiddler berichtet hat, dass es eine "leere TLS-Verhandlungs-Chiffre" oder ähnliches gibt.

Hoffentlich funktioniert es!

Medismal
quelle
Beachten Sie, dass Ihr Code, selbst wenn er keinen TLS benötigt, auf dem Server, mit dem er kommuniziert, versucht, mit TLS zu verhandeln, und fehlschlägt, wenn dies nicht möglich ist. Die leere TLS-Verhandlungsverschlüsselung war der Steckplatz, der den TLS-Protokollaustausch erwartete, den Sie schließlich bereitgestellt haben. Es hat wahrscheinlich "früher funktioniert", weil der Serveradministrator wahrscheinlich gerade TLS auf dem Server aktiviert hat, mit dem Ihre Anwendung kommuniziert hat.
vapcguy
13

In meinem Fall wurde die Site, zu der ich eine Verbindung herstelle, auf TLS 1.2 aktualisiert. Infolgedessen musste ich .net 4.5.2 auf meinem Webserver installieren, um dies zu unterstützen.

aboy021
quelle
Kann dies auf Registrierungsebene auf dem Computer durchgeführt werden? Ich habe alle SSL-Protokolle deaktiviert und TLS 1.0, 1.1, 1.2 verlassen. Ich verstehe jedoch, dass weniger als TLS 1.2 bald entfernt werden sollte, um PCI-kompatibel zu sein.
Brendo234
12

Gehen Sie zu Ihrer web.config / App.config, um zu überprüfen, welche .net-Laufzeit Sie verwenden

  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
  </startup>

Hier ist die Lösung:

  1. .NET 4.6 und höher. Sie müssen keine zusätzlichen Arbeiten ausführen, um TLS 1.2 zu unterstützen. Es wird standardmäßig unterstützt.

  2. .NET 4.5. TLS 1.2 wird unterstützt, ist jedoch kein Standardprotokoll. Sie müssen sich anmelden, um es zu verwenden. Der folgende Code macht TLS 1.2 zum Standard. Stellen Sie sicher, dass Sie es ausführen, bevor Sie eine Verbindung zu einer gesicherten Ressource herstellen:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12

  1. .NET 4.0. TLS 1.2 wird nicht unterstützt. Wenn Sie jedoch .NET 4.5 (oder höher) auf dem System installiert haben, können Sie sich weiterhin für TLS 1.2 entscheiden, auch wenn Ihr Anwendungsframework dies nicht unterstützt. Das einzige Problem ist, dass SecurityProtocolType in .NET 4.0 keinen Eintrag für TLS1.2 hat. Daher müssten wir eine numerische Darstellung dieses Aufzählungswerts verwenden:

ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;

  1. .NET 3.5 oder niedriger. TLS 1.2 wird nicht unterstützt (*) und es gibt keine Problemumgehung. Aktualisieren Sie Ihre Anwendung auf eine neuere Version des Frameworks.
Guo Huang
quelle
6

Ich habe festgestellt, dass dies ein Zeichen dafür ist, dass auf dem Server, auf dem Sie Code bereitstellen, ein altes .NET-Framework installiert ist, das TLS 1.1 oder TLS 1.2 nicht unterstützt. Zu behebende Schritte:

  1. Installieren der neuesten .NET- Laufzeit auf Ihren Produktionsservern (IIS & SQL)
  2. Installieren des neuesten .NET Developer Pack auf Ihren Entwicklungscomputern.
  3. Ändern Sie die Einstellungen für "Zielframework" in Ihren Visual Studio-Projekten in das neueste .NET-Framework.

Sie können das neueste .NET Developer Pack und Runtime unter folgender URL herunterladen : http://getdotnet.azurewebsites.net/target-dotnet-platforms.html

Patrick
quelle
Das Ziel-Framework wurde von 4.5.2 auf 4.6.1 geändert und die Arbeit aufgenommen. Vielen Dank, Patrick.
Vivek Sharma
4

Wir hatten dieses Problem, bei dem eine Website, die auf unsere API zugegriffen hat, die Meldung "Die zugrunde liegende Verbindung wurde geschlossen: Beim Senden ist ein unerwarteter Fehler aufgetreten." Botschaft.

Ihr Code war eine Mischung aus .NET 3.x und 2.2, was meines Wissens bedeutet, dass sie TLS 1.0 verwenden.

Die folgende Antwort kann Ihnen bei der Diagnose des Problems helfen, indem Sie TLS 1.0, SSL 2 und SSL3 aktivieren. Um jedoch ganz klar zu sein, möchten Sie dies nicht langfristig tun, da alle drei dieser Protokolle als unsicher angesehen werden und nicht länger gelten sollten verwendet :

Damit unser IIS auf seine API-Aufrufe reagiert, mussten wir Registrierungseinstellungen auf dem IIS-Server hinzufügen, um Versionen von TLS explizit zu aktivieren. HINWEIS: Sie müssen den Windows-Server (nicht nur den IIS-Dienst) neu starten, nachdem Sie diese Änderungen vorgenommen haben:

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS
1.0\Client] "DisabledByDefault"=dword:00000000 "Enabled"=dword:00000001

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS
1.0\Server] "DisabledByDefault"=dword:00000000 "Enabled"=dword:00000001

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS
1.1\Client] "DisabledByDefault"=dword:00000000 "Enabled"=dword:00000001

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS
1.1\Server] "DisabledByDefault"=dword:00000000 "Enabled"=dword:00000001

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS
1.2\Client] "DisabledByDefault"=dword:00000000 "Enabled"=dword:00000001

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS
1.2\Server] "DisabledByDefault"=dword:00000000 "Enabled"=dword:00000001

Wenn dies nicht der Fall ist, können Sie auch mit dem Hinzufügen des Eintrags für SSL 2.0 experimentieren:

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Client]
"DisabledByDefault"=dword:00000000
"Enabled"=dword:00000001

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Server]
"DisabledByDefault"=dword:00000000
"Enabled"=dword:00000001

Um es klar auszudrücken, ist dies keine gute Lösung , und die richtige Lösung besteht darin, den Anrufer dazu zu bringen, TLS 1.2 zu verwenden. Das oben Gesagte kann jedoch bei der Diagnose helfen, dass dies das Problem ist.

Mit diesem Powershell-Skript können Sie das Hinzufügen dieser Registrierungseinträge beschleunigen:

$ProtocolList       = @("SSL 2.0","SSL 3.0","TLS 1.0", "TLS 1.1", "TLS 1.2")
$ProtocolSubKeyList = @("Client", "Server")
$DisabledByDefault = "DisabledByDefault"
$Enabled = "Enabled"
$registryPath = "HKLM:\\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\"

foreach($Protocol in $ProtocolList)
{
    Write-Host " In 1st For loop"
        foreach($key in $ProtocolSubKeyList)
        {         
            $currentRegPath = $registryPath + $Protocol + "\" + $key
            Write-Host " Current Registry Path $currentRegPath"
            if(!(Test-Path $currentRegPath))
            {
                Write-Host "creating the registry"
                    New-Item -Path $currentRegPath -Force | out-Null             
            }
            Write-Host "Adding protocol"
                New-ItemProperty -Path $currentRegPath -Name $DisabledByDefault -Value "0" -PropertyType DWORD -Force | Out-Null
                New-ItemProperty -Path $currentRegPath -Name $Enabled -Value "1" -PropertyType DWORD -Force | Out-Null    
    }
}
 
Exit 0

Dies ist eine modifizierte Version des Skripts auf der Microsoft-Hilfeseite zum Einrichten von TLS für VMM . Dieser Basics.net-Artikel war die Seite, auf der ich ursprünglich auf die Idee gekommen bin , mir diese Einstellungen anzusehen.

tomRedox
quelle
Unser Problem betraf eine Release-Pipeline über Team City, die plötzlich gestoppt wurde, als wir das Zertifikat für Ihren Live-Server geändert haben. Wir hatten den Server bereits so geändert, dass nur TLS1.2 verwendet wird, und unsere Team City-Pipeline funktionierte nicht mehr ... Arbeitete wie ein Traum ... fügte die Registrierungseinträge hinzu und startete den Server neu ... BOOM !!! Danke tomRedox !!
Gwasshoppa
@Gwasshoppa, nur um zu wiederholen, dass das oben Genannte nur eine Notlösung ist, um das Problem zu diagnostizieren. Jetzt wissen Sie, dass es sich um ein Problem mit der TLS-Version handelt. Die Lösung besteht darin, die Release-Pipeline so zu ändern, dass sie mit TLS1.2 funktioniert, und dann TLS <1.2 und SSL 2 und 3 wieder auszuschalten. Ich habe die Antwort oben leicht aktualisiert, um dies ebenfalls zu betonen.
TomRedox
4

Einfach hinzufügen:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

M. Qudah
quelle
1
Bitte geben Sie eine Erklärung mit Ihrer Antwort.
Word Rearranger
4
Diese Antwort fügt auch den vorherigen nichts hinzu.
Arvindh Mani
2

Wenn es jemandem hilft, war unser Problem mit dem fehlenden Zertifikat. Die Umgebung ist Windows Server 2016 Standard mit .Net 4.6.

Es gibt einen selbst gehosteten WCF-Dienst https URI, für den Service.Open () fehlerfrei ausgeführt wird. Ein anderer Thread würde weiterhin auf https: // OurIp: 443 / OurService? Wsdl zugreifen, um sicherzustellen, dass der Dienst verfügbar ist. Der Zugriff auf die WSDL schlug fehl mit:

Die zugrunde liegende Verbindung wurde geschlossen: Beim Senden ist ein unerwarteter Fehler aufgetreten.

Die Verwendung von ServicePointManager.SecurityProtocol mit den entsprechenden Einstellungen hat nicht funktioniert. Das Spielen mit Serverrollen und -funktionen hat ebenfalls nicht geholfen. Dann trat Jaise George , die SE, ein und löste das Problem in ein paar Minuten. Jaise installierte ein selbstsigniertes Zertifikat im IIS, um das Problem zu beheben. Dies ist, was er getan hat, um das Problem anzugehen:

(1) Öffnen Sie den IIS-Manager (inetmgr). (2) Klicken Sie im linken Bereich auf den Serverknoten und doppelklicken Sie auf "Serverzertifikate". (3) Klicken Sie im rechten Bereich auf "Selbstsigniertes Zertifikat erstellen" und geben Sie den gewünschten Anzeigenamen ein. (4) Klicken Sie im linken Bereich auf "Standardwebsite", im rechten Bereich auf "Bindungen", klicken Sie auf "Hinzufügen", wählen Sie "https", wählen Sie das soeben erstellte Zertifikat aus und klicken Sie auf "OK". (5) Zugriff Über die https-URL sollte darauf zugegriffen werden können.

DiligentKarma
quelle
Sie hätten gedacht, der Serveradministrator hätte das SSL-Zertifikat hinzugefügt! D'oh! lol :) Ich kann jedoch sehen, dass dies geschieht - oder ein abgelaufenes Zertifikat, das erneuert werden muss, ist wahrscheinlich das geeignetere Szenario.
vapcguy
2

Sie ändern einfach Ihre Anwendungsversion wie 4.0 auf 4.6 und veröffentlichen diesen Code.

Fügen Sie auch die folgenden Codezeilen hinzu:

httpRequest.ProtocolVersion = HttpVersion.Version10; 
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
Viresh
quelle
1

Die Verwendung eines HTTP-Debugging-Proxys kann dies verursachen - beispielsweise Fiddler.

Ich habe ein PFX-Zertifikat aus einer lokalen Datei geladen (Authentifizierung bei Apple.com) und es ist fehlgeschlagen, weil Fiddler dieses Zertifikat nicht weitergeben konnte.

Versuchen Sie, Fiddler zu deaktivieren, um zu überprüfen, ob dies die Lösung ist. Dann müssen Sie wahrscheinlich das Zertifikat auf Ihrem Computer installieren oder auf eine Weise, die Fiddler verwenden kann.

Simon_Weaver
quelle
0

Der folgende Code hat mein Problem gelöst:

request.ProtocolVersion = HttpVersion.Version10; // THIS DOES THE TRICK
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
Oberst Software
quelle