"La connessione sottostante è stata chiusa: si è verificato un errore imprevisto durante un invio." Con certificato SSL


120

Problema: ricevo questa eccezione "LA CONNESSIONE SOTTOSTANTE È STATA CHIUSA: SI È VERIFICATO UN ERRORE IMPREVISTO IN UN INVIO" nei miei log e sta interrompendo la nostra integrazione OEM con il nostro sistema di email marketing in tempi casuali che variano da [1 ora a 4 ore]

Il mio sito web è ospitato su un server Windows 2008 R2 con IIS 7.5.7600. Questo sito Web ha un gran numero di componenti OEM e un dashboard completo. Tutto funziona bene con tutti gli altri elementi del sito web tranne che con uno dei nostri componenti di email marketing che stiamo utilizzando come soluzione iframe all'interno della nostra dashboard. Il modo in cui funziona è che invio un httpWebRequestobject con tutte le credenziali e ricevo un URL che ho inserito in un iframe e funziona. Ma funziona solo per un po 'di tempo [1 ora - 4 ore] e poi ottengo l'eccezione seguente "LA CONNESSIONE SOTTOSTANTE È STATA CHIUSA: SI È VERIFICATO UN ERRORE IMPREVISTO IN UN INVIO" e anche se il sistema cerca di ottenere l'URL da httpWebRequest fallisce con la stessa eccezione. L'unico modo per farlo funzionare di nuovo è riciclare il pool di applicazioni o qualsiasi cosa venga modificata in web.config.

Opzione provata

Aggiunto esplicitamente, keep-alive = false

keep-alive = true

Aumentato il timeout: <httpRuntime maxRequestLength="2097151" executionTimeout="9999999" enable="true" requestValidationMode="2.0" />

Ho caricato questa pagina su un sito Web non SSL per verificare se il certificato SSL sul nostro server di produzione sta effettuando la connessione per interrompere in qualche modo.

Qualsiasi direzione verso la risoluzione è molto apprezzata.

Codice :

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`

L'hai mai capito?
Brett G

12
sì, sono riuscito a farlo funzionare con questo codice ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls o SecurityProtocolType.Ssl3
Arvind Morwal

Stavo per morire per lo stesso problema. Mi ci sono volute diverse ore per affrontare lo stesso problema. Grazie per i tuoi commenti, mi ha salvato la giornata.
Sameers Javed

2
@ user3458212 dovresti aggiungere il tuo commento come risposta
icc97

2
Nel mio caso, eseguendo il sito web in Visual Studio 15 tutto va bene, ma alla fine, poiché non riesco ad aggiornare il framework nel server e forzando TLS 1.2 e disabilitando keep-alive non funziona, ho dovuto impostare un intermedio server Web per eseguire il proxy del server Web di destinazione che interrompe la connessione.
José Roberto García Chico

Risposte:


194

Per me è stato tls12:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

42
Tieni presente che devi fare attenzione perché questa modifica è globale per il tuo AppDomain e causerà il fallimento delle chiamate a qualsiasi sito che non offre TLS 1.2 (cosa che potresti preferire se i dati da trasportare sono veramente sensibili). Per preferire TLS 1.2 ma consentire comunque 1.1 e 1.0, devi OR loro:ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
Dusty

lo stesso qui, mi hai salvato la vita, hai speso così tanto tempo per capire cosa c'era di sbagliato in RestSharp
darul75

Questa soluzione funziona anche per coloro che non utilizzano RestSharp e per coloro che non utilizzano ServicePointManager. Basta copiare e incollare la riga sopra prima della chiamata WebRequest o qualsiasi altra cosa tu stia utilizzando per effettuare la richiesta. Inizialmente ho ignorato questa soluzione per i motivi di cui sopra.
goku_da_master

o semplicemente aggiungilo a quello che c'è già ... System.Net.ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
uosjead

8
Per farlo in PowerShell, "binario o" insieme in questo modo:[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls
Adam S


24

Il codice seguente ha risolto il problema

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls Or SecurityProtocolType.Ssl3

6
Ciò funzionerebbe, tuttavia, tieni presente che ServicePointManager.SecurityProtocolè un oggetto statico, il che significa che la modifica di questo valore influenzerà tutte le sotto-sequenze WebRequesto le WebClientchiamate. Puoi crearne uno separato AppDomainse vuoi ServicePointManageravere impostazioni differenti. Vedi stackoverflow.com/questions/3791629/… per maggiori dettagli.
stack247

1
Utili letture aggiuntive per capire cosa sta facendo questo codice: stackoverflow.com/questions/26389899/…
Jon Schneider

@Marnee l'ho inserito nella root di composizione della mia applicazione, quindi è impostato prima di qualsiasi I / O che si verifichi
JG in SD

@Marnee Inseriscilo in un costruttore statico, quindi viene eseguito esattamente una volta, la prima volta che si accede alla classe. Tuttavia, ho dovuto abilitare tutti i protocolli per coprire tutti i casi.
Nyerguds

14

Ho avuto lo stesso problema per giorni ormai con un'integrazione che anche "prima funzionava".

Per pura depressione, ho appena provato

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

Questo ha risolto il problema per me ... anche se l'integrazione fa uso esclusivamente di SSLv3.

Mi sono reso conto che qualcosa non andava da quando Fiddler ha riferito di aver detto che esiste un "codice di negoziazione TLS vuoto" o qualcosa del genere.

Si spera che funzioni!


Nota che, anche se il tuo codice non necessita di TLS, se il server sta comunicando con DOES, proverà a negoziare con TLS e fallirà se non può. Il codice di negoziazione TLS vuoto era lo slot che si aspettava lo scambio di protocollo TLS che alla fine hai fornito. Probabilmente "funzionava prima" perché probabilmente l'amministratore del server aveva appena abilitato TLS sul server con cui comunicava l'applicazione.
vapcguy

13

Nel mio caso il sito a cui mi sto collegando è stato aggiornato a TLS 1.2. Di conseguenza ho dovuto installare .net 4.5.2 sul mio server web per supportarlo.


È possibile eseguire questa operazione a livello di registro sulla macchina? Ho disabilitato tutti i protocolli SSL, lasciando TLS 1.0, 1.1, 1.2, tuttavia mi risulta che qualcosa di meno di TLS 1.2 dovrebbe essere rimosso presto per essere conforme allo standard PCI.
brendo234

13

Vai al tuo web.config / App.config per verificare quale runtime .net stai utilizzando

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

Ecco la soluzione:

  1. .NET 4.6 e versioni successive. Non è necessario eseguire alcun lavoro aggiuntivo per supportare TLS 1.2, è supportato per impostazione predefinita.

  2. .NET 4.5. TLS 1.2 è supportato, ma non è un protocollo predefinito. Devi accettare di usarlo. Il codice seguente renderà TLS 1.2 predefinito, assicurati di eseguirlo prima di effettuare una connessione a una risorsa protetta:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12

  1. .NET 4.0. TLS 1.2 non è supportato, ma se sul sistema è installato .NET 4.5 (o successivo), puoi comunque optare per TLS 1.2 anche se il framework dell'applicazione non lo supporta. L'unico problema è che SecurityProtocolType in .NET 4.0 non ha una voce per TLS1.2, quindi dovremmo usare una rappresentazione numerica di questo valore enum:

ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;

  1. .NET 3.5 o inferiore. TLS 1.2 non è supportato (*) e non sono disponibili soluzioni alternative. Aggiorna la tua applicazione alla versione più recente del framework.

6

Ho scoperto che questo è un segno che il server in cui stai distribuendo il codice ha un vecchio framework .NET installato che non supporta TLS 1.1 o TLS 1.2. Passaggi per risolvere:

  1. Installazione dell'ultima versione di .NET Runtime sui server di produzione (IIS e SQL)
  2. Installazione dell'ultimo .NET Developer Pack sulle macchine di sviluppo.
  3. Modificare le impostazioni "Framework di destinazione" nei progetti di Visual Studio nell'ultimo framework .NET.

È possibile ottenere l'ultimo .NET Developer Pack e Runtime da questo URL: http://getdotnet.azurewebsites.net/target-dotnet-platforms.html


Cambiato il framework di destinazione da 4.5.2 a 4.6.1 e ho iniziato a lavorare, grazie Patrick.
Vivek Sharma

4

Abbiamo riscontrato questo problema per cui un sito Web che stava accedendo alla nostra API riceveva il messaggio "La connessione sottostante è stata chiusa: si è verificato un errore imprevisto durante un invio". Messaggio.

Il loro codice era un mix di .NET 3.x e 2.2, che da quanto ho capito significa che stanno usando TLS 1.0.

La risposta di seguito può aiutarti a diagnosticare il problema abilitando TLS 1.0, SSL 2 e SSL3, ma per essere molto chiari, non vuoi farlo a lungo termine poiché tutti e tre questi protocolli sono considerati non sicuri e non dovrebbero più essere usato :

Per fare in modo che il nostro IIS rispondesse alle loro chiamate API, abbiamo dovuto aggiungere le impostazioni del registro sul server IIS per abilitare esplicitamente le versioni di TLS - NOTA: è necessario riavviare il server Windows (non solo il servizio IIS) dopo aver apportato queste modifiche:

[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

In caso contrario, potresti anche provare ad aggiungere la voce per SSL 2.0:

[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

Per essere chiari, questa non è una buona soluzione e la soluzione giusta è convincere il chiamante a utilizzare TLS 1.2, ma quanto sopra può aiutare a diagnosticare che questo è il problema.

Puoi velocizzare l'aggiunta di quelle voci di registro con questo script PowerShell:

$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

Questa è una versione modificata dello script dalla pagina della guida di Microsoft per la configurazione di TLS per VMM . Questo articolo di basics.net era la pagina che originariamente mi ha dato l'idea di esaminare queste impostazioni.


Il nostro problema riguardava una pipeline di rilascio tramite Team City che si è interrotta improvvisamente quando abbiamo modificato il certificato per il tuo server live. Avevamo già cambiato il server per usare solo TLS1.2 e la nostra pipeline di Team City ha smesso di funzionare ... Ha funzionato come un sogno ... aggiunto le voci di registro e riavviato il server ... BOOM !!! Grazie tomRedox !!
Gwasshoppa

@ Gwasshoppa, giusto per ribadire che quanto sopra è solo un ripiego per diagnosticare il problema. Ora sai che si tratta di un problema di versione TLS, la soluzione è modificare la pipeline di rilascio in modo che possa funzionare con TLS1.2 e quindi disattivare nuovamente TLS <1.2 e SSL 2 e 3. Ho aggiornato leggermente la risposta sopra per sottolineare anche questo.
tomRedox,

4

Basta aggiungere:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;


1
Si prega di fornire una spiegazione con la risposta.
Word Rearranger

4
Anche questa risposta non aggiunge nulla a quelle precedenti.
Arvindh Mani

2

Se aiuta qualcuno, il nostro era un problema con il certificato mancante. L'ambiente è Windows Server 2016 Standard con .Net 4.6.

Esiste un URI https del servizio WCF self-hosted, per il quale Service.Open () verrebbe eseguito senza errori. Un altro thread continuerebbe ad accedere a https: // OurIp: 443 / OurService? Wsdl per assicurarsi che il servizio fosse disponibile. Accesso al WSDL utilizzato per fallire con:

La connessione sottostante è stata chiusa: si è verificato un errore imprevisto durante un invio.

L'utilizzo di ServicePointManager.SecurityProtocol con le impostazioni applicabili non ha funzionato. Anche giocare con i ruoli e le funzionalità del server non ha aiutato. Quindi intervenne Jaise George , SE, risolvendo il problema in un paio di minuti. Jaise ha installato un certificato autofirmato nell'IIS, risolvendo il problema. Questo è ciò che ha fatto per affrontare il problema:

(1) Aprire il gestore IIS (inetmgr) (2) Fare clic sul nodo del server nel pannello di sinistra e fare doppio clic su "Certificati del server". (3) Fare clic su "Crea certificato autofirmato" nel pannello di destra e digitare tutto ciò che si desidera per il nome descrittivo. (4) Fare clic su "Sito Web predefinito" nel pannello di sinistra, fare clic su "Associazioni" nel pannello di destra, fare clic su "Aggiungi", selezionare "https", selezionare il certificato appena creato e fare clic su "OK" (5) Accesso l'URL https, dovrebbe essere accessibile.


Tuttavia, avresti pensato che l'amministratore del server avrebbe aggiunto il certificato SSL! D'oh! lol :) Posso vedere che sta accadendo, però - o un certificato scaduto che deve essere rinnovato sarebbe probabilmente lo scenario più applicabile.
vapcguy

2

Devi solo modificare la versione dell'applicazione come 4.0 in 4.6 e pubblicare il codice.

Aggiungi anche le seguenti righe di codice:

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

1

L'utilizzo di un proxy di debug HTTP può causare ciò, ad esempio Fiddler.

Stavo caricando un certificato PFX da un file locale (autenticazione su Apple.com) e non è riuscito perché Fiddler non è stato in grado di trasmettere questo certificato.

Prova a disabilitare Fiddler per controllare e se questa è la soluzione, probabilmente devi installare il certificato sulla tua macchina o in qualche modo che Fiddler possa usarlo.


0

Il codice seguente ha risolto il mio problema:

request.ProtocolVersion = HttpVersion.Version10; // THIS DOES THE TRICK
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.