„Połączenie bazowe zostało zamknięte: wystąpił nieoczekiwany błąd podczas wysyłania”. Z certyfikatem SSL


120

Problem: w moich dziennikach pojawia się ten wyjątek „PODSTAWOWE POŁĄCZENIE ZOSTAŁO ZAMKNIĘTE: NIEOCZEKIWANY BŁĄD PRZY WYSYŁANIU” i powoduje to zerwanie naszej integracji OEM z naszym systemem marketingu e-mailowego w losowych odstępach czasu od [1–4 godziny]

Moja witryna jest hostowana na serwerze Windows 2008 R2 z usługami IIS 7.5.7600. Ta witryna zawiera dużą liczbę komponentów OEM i obszerny pulpit nawigacyjny. Wszystko działa dobrze ze wszystkimi innymi elementami witryny, z wyjątkiem jednego z naszych komponentów e-mail marketingu, którego używamy jako rozwiązanie iframe na naszym pulpicie nawigacyjnym. Sposób działania jest taki, że wysyłam obiekt httpWebRequestobject ze wszystkimi poświadczeniami i otrzymuję adres URL z powrotem, który umieszczam w ramce iframe i działa. Ale to działa tylko przez jakiś czas [1 godzina - 4 godziny], a potem pojawia się poniższy wyjątek „PODSTAWOWE POŁĄCZENIE ZOSTAŁO ZAMKNIĘTE: NIEOCZEKIWANY BŁĄD WYSTĄPIŁ PRZY WYSYŁANIU” i nawet jeśli system próbuje uzyskać adres URL z httpWebRequest kończy się niepowodzeniem z tym samym wyjątkiem. Jedynym sposobem na przywrócenie jej działania jest ponowne wykorzystanie puli aplikacji lub edytowanie czegokolwiek w pliku web.config.

Opcja wypróbowana

Wyraźnie dodane, keep-alive = false

keep-alive = true

Wydłużono limit czasu: <httpRuntime maxRequestLength="2097151" executionTimeout="9999999" enable="true" requestValidationMode="2.0" />

Przesłałem tę stronę do witryny bez SSL, aby sprawdzić, czy certyfikat SSL na naszym serwerze produkcyjnym nawiązuje połączenie, aby w jakiś sposób zrzucić to.

Każdy kierunek w kierunku rozwiązania jest bardzo cenny.

Kod :

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`

Czy kiedykolwiek to rozgryzłeś?
Brett G

12
tak, udało mi się go uruchomić z tym kodem ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls lub SecurityProtocolType.Ssl3
Arvind Morwal

Miałem umrzeć za ten sam problem. Kilka godzin zajęło mi zmaganie się z tym samym problemem. Dzięki za komentarze, uratowało mi to dzień.
Sameers Javed

2
@ user3458212 powinieneś dodać swój komentarz jako odpowiedź
icc97

2
W moim przypadku uruchomienie strony internetowej w Visual Studio 15 wszystko idzie dobrze, ale w końcu, ponieważ nie mogę zaktualizować frameworka na serwerze, a wymuszenie TLS 1.2 i wyłączenie funkcji keep-alive nie działają, musiałem skonfigurować pośredniego serwer WWW do proxy docelowego serwera WWW, który przerywa połączenie.
José Roberto García Chico

Odpowiedzi:


194

Dla mnie był to tls12:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

42
Pamiętaj, że musisz zachować ostrożność, ponieważ ta zmiana jest globalna dla Twojej domeny AppDomain i spowoduje niepowodzenie wywołań dowolnej witryny, która nie oferuje protokołu TLS 1.2 (co może być preferowane, jeśli dane do przesłania są naprawdę poufne). Aby preferować TLS 1.2, ale nadal zezwalać na 1.1 i 1.0, musisz je LUB:ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
Dusty

to samo tutaj, uratowałeś mi życie, spędziłeś tyle czasu, aby dowiedzieć się, co jest nie tak z RestSharp
darul75

To rozwiązanie działa również dla tych, którzy nie używają RestSharp, a także dla tych, którzy nie używają ServicePointManager. Po prostu skopiuj i wklej powyższy wiersz przed wywołaniem WebRequest lub czymkolwiek innym, czego używasz do złożenia żądania. Z powyższych powodów początkowo zignorowałem to rozwiązanie.
goku_da_master

lub po prostu dodaj to do tego, co już tam jest ... System.Net.ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
uosjead

8
Aby to zrobić w PowerShell, „binarnie” lub „razem”, na przykład:[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls
Adam S

64

Jeśli utkniesz z .Net 4.0, a witryna docelowa korzysta z protokołu TLS 1.2, potrzebujesz zamiast tego następującego wiersza. ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;

źródło: Obsługa TLS 1.2 i .NET: jak uniknąć błędów połączenia


5
Niesamowite! Dodam tylko, że (SecurityProtocolType)768można go użyć dla „Tls11” (tj. TLS 1.1).
Solomon Rutzky

2
To naprawdę pomaga. To uratowało mi dzień. Muszę się trzymać .Net 2.0.
Hao Nguyen

24

Poniższy kod rozwiązał problem

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls Or SecurityProtocolType.Ssl3

6
To zadziała, jednak pamiętaj, że ServicePointManager.SecurityProtocoljest to obiekt statyczny, co oznacza, że ​​zmiana tej wartości wpłynie na wszystkie sekwencje podrzędne WebRequestlub WebClientwywołania. Możesz utworzyć osobne, AppDomainjeśli chcesz ServicePointManagermieć inne ustawienia. Więcej szczegółów znajdziesz na stackoverflow.com/questions/3791629/… .
stack247

1
Pomocna dodatkowa lektura, aby zrozumieć, co robi ten kod: stackoverflow.com/questions/26389899/…
Jon Schneider

@Marnee Umieściłem go w katalogu głównym kompozycji mojej aplikacji, więc jest ustawiony przed jakimkolwiek I / O kiedykolwiek występującym
JG w SD

@Marnee Umieść go w konstruktorze statycznym, aby był wykonywany dokładnie raz, przy pierwszym dostępie do klasy. Musiałem jednak włączyć wszystkie protokoły, aby objąć wszystkie przypadki.
Nyerguds

14

Od kilku dni mam ten sam problem z integracją, która również „działała wcześniej”.

Po prostu spróbowałem z czystej depresji

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

To rozwiązało problem ... nawet jeśli integracja wykorzystuje wyłącznie SSLv3.

Uświadomiłem sobie, że coś jest nie tak, odkąd Fiddler poinformował, że istnieje „pusty szyfr negocjacyjny TLS” lub coś w tym stylu.

Mam nadzieję, że to działa!


Zauważ, że nawet jeśli twój kod nie potrzebuje TLS, jeśli serwer, z którym komunikuje się DOES, spróbuje negocjować z TLS i zawiedzie, jeśli nie może. Pusty szyfr negocjacyjny TLS był gniazdem, które oczekiwało wymiany protokołu TLS, którą ostatecznie podałeś. Prawdopodobnie „działało wcześniej”, ponieważ administrator serwera prawdopodobnie właśnie włączył TLS na serwerze, z którym komunikowała się Twoja aplikacja.
vapcguy

13

W moim przypadku witryna, z którą się łączę, została zaktualizowana do TLS 1.2. W rezultacie musiałem zainstalować .net 4.5.2 na swoim serwerze WWW, aby go obsługiwać.


Czy można to zrobić na poziomie rejestru na komputerze? Wyłączyłem wszystkie protokoły SSL, pozostawiając TLS 1.0, 1.1, 1.2, jednak rozumiem, że wszystko poniżej TLS 1.2 powinno zostać wkrótce usunięte, aby było zgodne z PCI.
brendo234

13

Przejdź do swojego web.config / App.config, aby sprawdzić, którego środowiska uruchomieniowego .net używasz

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

Oto rozwiązanie:

  1. .NET 4.6 i nowsze. Nie musisz wykonywać żadnej dodatkowej pracy, aby obsługiwać protokół TLS 1.2, jest on domyślnie obsługiwany.

  2. .NET 4.5. Obsługiwany jest protokół TLS 1.2, ale nie jest to protokół domyślny. Aby z niej korzystać, musisz wyrazić zgodę. Poniższy kod ustawi TLS 1.2 jako domyślny, upewnij się, że wykonałeś go przed nawiązaniem połączenia z zabezpieczonym zasobem:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12

  1. .NET 4.0. TLS 1.2 nie jest obsługiwany, ale jeśli masz .NET 4.5 (lub nowszy) zainstalowany w systemie, nadal możesz zdecydować się na TLS 1.2, nawet jeśli twoja struktura aplikacji go nie obsługuje. Jedynym problemem jest to, że SecurityProtocolType w .NET 4.0 nie ma wpisu dla TLS1.2, więc musielibyśmy użyć numerycznej reprezentacji tej wartości wyliczenia:

ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;

  1. .NET 3.5 lub starszy. TLS 1.2 nie jest obsługiwany (*) i nie ma obejścia. Zaktualizuj swoją aplikację do nowszej wersji platformy.

6

Odkryłem, że to znak, że serwer, na którym wdrażasz kod, ma zainstalowaną starą platformę .NET, która nie obsługuje TLS 1.1 ani TLS 1.2. Kroki do naprawienia:

  1. Instalowanie najnowszego środowiska .NET Runtime na serwerach produkcyjnych (IIS i SQL)
  2. Instalowanie najnowszego pakietu .NET Developer Pack na komputerach deweloperskich.
  3. Zmień ustawienia „Platforma docelowa” w projektach programu Visual Studio na najnowszą platformę .NET.

Najnowszy pakiet deweloperski i środowisko wykonawcze .NET można pobrać z tego adresu URL: http://getdotnet.azurewebsites.net/target-dotnet-platforms.html


Zmieniono docelowy framework z 4.5.2 na 4.6.1 i zacząłem działać, dziękuję Patrick.
Vivek Sharma

4

Wystąpił problem, w wyniku którego witryna, która uzyskiwała dostęp do naszego interfejsu API, otrzymywała komunikat „Połączenie podstawowe zostało zamknięte: podczas wysyłania wystąpił nieoczekiwany błąd”. wiadomość.

Ich kod był mieszanką .NET 3.x i 2.2, co, jak rozumiem, oznacza, że ​​używają TLS 1.0.

Poniższa odpowiedź może pomóc w zdiagnozowaniu problemu, włączając protokoły TLS 1.0, SSL 2 i SSL3, ale dla jasności: nie chcesz tego robić na dłuższą metę, ponieważ wszystkie trzy z tych protokołów są uważane za niezabezpieczone i nie powinny być dłużej używany :

Aby nasze usługi IIS odpowiadały na ich wywołania API, musieliśmy dodać ustawienia rejestru na serwerze IIS, aby jawnie włączyć wersje TLS - UWAGA: Po wprowadzeniu tych zmian należy ponownie uruchomić serwer Windows (nie tylko usługę IIS):

[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

Jeśli to nie wystarczy, możesz również poeksperymentować z dodaniem wpisu dla 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

Żeby było jasne, nie jest to przyjemne rozwiązanie , a właściwym rozwiązaniem jest skłonienie dzwoniącego do korzystania z TLS 1.2, ale powyższe może pomóc zdiagnozować, że to jest problem.

Możesz przyspieszyć dodawanie tych wpisów reg za pomocą tego skryptu 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

To zmodyfikowana wersja skryptu ze strony pomocy firmy Microsoft dotyczącej konfiguracji TLS dla VMM . Ten artykuł w basics.net był stroną, która pierwotnie podsunęła mi pomysł, aby przyjrzeć się tym ustawieniom.


Nasz problem dotyczył procesu wydawania za pośrednictwem Team City, który nagle się zatrzymał, gdy zmieniliśmy certyfikat serwera na żywo. Zmieniliśmy już serwer, aby korzystał tylko z TLS1.2, a nasz potok Team City przestał działać ... Działał jak sen ... dodaliśmy wpisy reg i zrestartowaliśmy serwer ... BUM !!! Dzięki tomRedox !!
Gwasshoppa

@Gwasshoppa, tylko po to, aby powtórzyć, że powyższe jest tylko chwilową próbą zdiagnozowania problemu. Teraz wiesz, że jest to problem z wersją TLS, rozwiązaniem jest zmiana potoku wydania, aby mógł współpracować z TLS1.2, a następnie ponowne wyłączenie TLS <1,2 i SSL 2 i 3. Zaktualizowałem nieco powyższą odpowiedź, aby to również podkreślić.
tomRedox


2

Jeśli komuś pomogło, u nas był problem z brakującym certyfikatem. Środowisko to Windows Server 2016 Standard z .Net 4.6.

Istnieje identyfikator URI https usługi WCF hostowany samodzielnie, dla którego usługa Service.Open () byłaby wykonywana bez błędów. Inny wątek będzie miał dostęp do https: // OurIp: 443 / OurService? Wsdl, aby upewnić się, że usługa jest dostępna. Dostęp do WSDL, który się nie udał z:

Połączenie bazowe zostało zamknięte: podczas wysyłania wystąpił nieoczekiwany błąd.

Korzystanie z ServicePointManager.SecurityProtocol z odpowiednimi ustawieniami nie działa. Nie pomogła też zabawa z rolami i funkcjami serwera. Następnie wkroczył Jaise George , SE, rozwiązując problem w ciągu kilku minut. Jaise zainstalował certyfikat z podpisem własnym w usługach IIS, eliminując problem. Oto, co zrobił, aby rozwiązać ten problem:

(1) Otwórz menedżera IIS (inetmgr) (2) Kliknij węzeł serwera w lewym panelu i dwukrotnie kliknij „Certyfikaty serwera”. (3) Kliknij „Utwórz certyfikat z podpisem własnym” w prawym panelu i wpisz dowolną nazwę, aby uzyskać przyjazną nazwę. (4) Kliknij „Domyślna witryna internetowa” w lewym panelu, kliknij „Powiązania” w prawym panelu, kliknij „Dodaj”, wybierz „https”, wybierz właśnie utworzony certyfikat i kliknij „OK” (5) Dostęp adres URL https, powinien być dostępny.


Można by pomyśleć, że administrator serwera dodałby certyfikat SSL! D'oh! lol :) Widzę, że to się dzieje - lub wygasły certyfikat, który wymaga odnowienia, byłby prawdopodobnie bardziej odpowiednim scenariuszem.
vapcguy

2

Po prostu zmień wersję aplikacji, np. 4.0 na 4.6 i opublikuj ten kod.

Dodaj również poniższe linie kodu:

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

1

Użycie serwera proxy do debugowania HTTP może to spowodować - na przykład Fiddler.

Ładowałem certyfikat PFX z pliku lokalnego (uwierzytelnianie do Apple.com) i nie powiodło się, ponieważ Fiddler nie mógł przekazać tego certyfikatu dalej.

Spróbuj wyłączyć Fiddlera, aby sprawdzić, a jeśli to jest rozwiązanie, prawdopodobnie musisz zainstalować certyfikat na swoim komputerze lub w inny sposób, aby Fiddler mógł go używać.


0

Poniższy kod rozwiązał mój problem:

request.ProtocolVersion = HttpVersion.Version10; // THIS DOES THE TRICK
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.