«Базовое соединение было закрыто: при отправке произошла непредвиденная ошибка». С сертификатом SSL

120

Проблема: в моих журналах появляется это исключение «БЫЛО ЗАКРЫТО ПОДКЛЮЧЕНИЕ: НЕОЖИДАННАЯ ОШИБКА ПРИ ОТПРАВКЕ», и это нарушает интеграцию OEM-производителя с нашей системой электронного маркетинга в случайные моменты времени, варьирующиеся от [1 час - 4 часа]

Мой веб-сайт размещен на сервере Windows Server 2008 R2 с IIS 7.5.7600. На этом веб-сайте есть большое количество OEM-компонентов и обширная информационная панель. Все отлично работает со всеми другими элементами веб-сайта, за исключением одного из наших компонентов электронного маркетинга, который мы используем в качестве решения iframe на нашей панели инструментов. Это работает так: я отправляю объект httpWebRequestobject со всеми учетными данными и получаю обратно URL-адрес, который я вставляю в iframe, и он работает. Но он работает только в течение некоторого времени [1 час - 4 часа], а затем я получаю следующее исключение: «БЫЛО ЗАКРЫТО ПОДКЛЮЧЕНИЕ: НЕОЖИДАННАЯ ОШИБКА ПРИ ОТПРАВКЕ», и даже если система пытается получить URL-адрес из httpWebRequest, он не работает с тем же исключением. Единственный способ заставить его снова работать - это переработать пул приложений или что-то отредактировать в web.config.

Вариант пробовал

Явно добавлено, keep-alive = false

keep-alive = true

Увеличено время ожидания: <httpRuntime maxRequestLength="2097151" executionTimeout="9999999" enable="true" requestValidationMode="2.0" />

Я загрузил эту страницу на веб-сайт без SSL, чтобы проверить, устанавливает ли SSL-сертификат на нашем производственном сервере соединение, чтобы каким-то образом разорвать соединение.

Приветствуется любое направление к разрешению.

Код:

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`
Арвинд Морвал
источник
Вы когда-нибудь понимали это?
Brett G
12
да, мне удалось заставить его работать с этим кодом ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls или SecurityProtocolType.Ssl3
Арвинд Морвал 02
Я собирался умереть из-за той же проблемы. У меня ушло несколько часов на борьбу с той же проблемой. Спасибо за комментарии, это спасло мне день.
Самиерс Джавед
2
@ user3458212, вы должны добавить свой комментарий в качестве ответа
icc97 07
2
В моем случае при запуске веб-сайта в Visual Studio 15 все идет нормально, но в конце, поскольку я не могу обновить фреймворк на сервере, а принудительное использование TLS 1.2 и отключение keep-alive не работают, мне пришлось настроить промежуточный веб-сервер для прокси-сервера целевого веб-сервера, который разрывает соединение.
Хосе Роберто Гарсия Чико

Ответы:

194

Для меня это был tls12:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
Lanklaas
источник
42
Обратите внимание, что вы должны быть осторожны, потому что это изменение является глобальным для вашего AppDomain и приведет к сбою вызовов любого сайта, который не предлагает TLS 1.2 (что вы можете предпочесть, если данные, которые необходимо транспортировать, действительно конфиденциальны). Чтобы предпочесть TLS 1.2, но при этом разрешить 1.1 и 1.0, вы должны ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
Dusty
то же самое здесь, вы спасли мне жизнь, потратили столько времени, чтобы выяснить, что не так с RestSharp
darul75
Это решение также работает для тех, кто не использует RestSharp, а также для тех, кто не использует ServicePointManager. Просто скопируйте и вставьте указанную выше строку перед вызовом WebRequest или чем-то еще, что вы используете для запроса. Я изначально проигнорировал это решение по указанным выше причинам.
goku_da_master
или просто добавьте это к тому, что уже есть ... System.Net.ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
uosjead
8
Чтобы сделать это в PowerShell, «двоичный» или их вместе, например:[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls
Adam S
64

Если вы застряли с .Net 4.0, а целевой сайт использует TLS 1.2, вам понадобится следующая строка. ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;

источник: Поддержка TLS 1.2 и .NET: как избежать ошибок подключения

Точи
источник
5
Потрясающие! Я бы просто добавил, что (SecurityProtocolType)768может использоваться для «Tls11» (т.е. TLS 1.1).
Соломон Рутцки 02
2
Это действительно помогает. Это спасло мне день. Я должен придерживаться .Net 2.0.
Hao Nguyen
24

Приведенный ниже код решил проблему.

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls Or SecurityProtocolType.Ssl3
Арвинд Морвал
источник
6
Это сработает, однако имейте в виду, что ServicePointManager.SecurityProtocolэто статический объект, что означает, что изменение этого значения повлияет на все подпоследовательности WebRequestили WebClientвызовы. Вы можете создать отдельный, AppDomainесли хотите ServicePointManagerиметь разные настройки. См. Stackoverflow.com/questions/3791629/… для получения дополнительных сведений.
stack247
1
Полезное дополнительное чтение, чтобы понять, что делает этот код: stackoverflow.com/questions/26389899/…
Джон Шнайдер,
@Marnee Я поместил его в корень композиции моего приложения, поэтому он устанавливается до любого ввода-вывода, когда-либо происходящего
JG в SD
@Marnee Поместите его в статический конструктор, чтобы он выполнялся ровно один раз при первом обращении к классу. Однако мне пришлось включить все протоколы, чтобы охватить все случаи.
Nyerguds 01
14

У меня уже несколько дней возникает такая же проблема с интеграцией, которая также «раньше работала».

Из-за депрессии я просто попробовал

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

Это решило проблему для меня… хотя интеграция строго использует только SSLv3.

Я пришел к выводу, что что-то не работает, потому что Fiddler сообщил, что есть «пустой шифр согласования TLS» или что-то в этом роде.

Надеюсь, это сработает!

Medismal
источник
Обратите внимание, что даже если вашему коду не нужен TLS, если сервер, с которым он взаимодействует, ДЕЙСТВУЕТ, он попытается согласовать с TLS и потерпит неудачу, если не сможет. Пустой шифр согласования TLS был слотом, который ожидал обмена протоколом TLS, который вы в конечном итоге предоставили. Скорее всего, он «работал раньше», потому что администратор сервера, вероятно, только что включил TLS на сервере, с которым общалось ваше приложение.
vapcguy
13

В моем случае сайт, к которому я подключаюсь, обновлен до TLS 1.2. В результате мне пришлось установить .net 4.5.2 на свой веб-сервер, чтобы поддерживать его.

aboy021
источник
Можно ли это сделать на уровне реестра на машине? Я отключил все протоколы SSL, оставив TLS 1.0, 1.1, 1.2, однако я понимаю, что все, что меньше TLS 1.2, должно быть скоро удалено, чтобы соответствовать требованиям PCI.
brendo234
13

Перейдите в свой web.config / App.config, чтобы проверить, какую среду выполнения .net вы используете.

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

Вот решение:

  1. .NET 4.6 и выше. Для поддержки TLS 1.2 не нужно выполнять никаких дополнительных действий, он поддерживается по умолчанию.

  2. .NET 4.5. TLS 1.2 поддерживается, но это не протокол по умолчанию. Вам необходимо зарегистрироваться, чтобы использовать его. Следующий код сделает TLS 1.2 по умолчанию, обязательно выполните его перед подключением к защищенному ресурсу:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12

  1. .NET 4.0. TLS 1.2 не поддерживается, но если в системе установлен .NET 4.5 (или выше), вы все равно можете выбрать TLS 1.2, даже если ваша платформа приложения не поддерживает его. Единственная проблема заключается в том, что SecurityProtocolType в .NET 4.0 не имеет записи для TLS1.2, поэтому нам пришлось бы использовать числовое представление этого значения перечисления:

ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;

  1. .NET 3.5 или ниже. TLS 1.2 не поддерживается (*), и обходного пути нет. Обновите свое приложение до более новой версии фреймворка.
Го Хуан
источник
6

Я обнаружил, что это признак того, что на сервере, на котором вы развертываете код, установлена ​​старая платформа .NET, которая не поддерживает TLS 1.1 или TLS 1.2. Шаги по исправлению:

  1. Установка последней версии .NET Runtime на ваши производственные серверы (IIS и SQL)
  2. Установка последней версии .NET Developer Pack на машины для разработки.
  3. Измените настройки «Целевая платформа» в ваших проектах Visual Studio на последнюю версию .NET framework.

Вы можете получить последнюю версию .NET Developer Pack и Runtime по этому URL-адресу: http://getdotnet.azurewebsites.net/target-dotnet-platforms.html

Патрик
источник
Изменил целевой фреймворк с 4.5.2 на 4.6.1 и начал работать, спасибо, Патрик.
Вивек Шарма
4

У нас была эта проблема, из-за которой веб-сайт, обращающийся к нашему API, получал сообщение «Базовое соединение было закрыто: при отправке произошла непредвиденная ошибка». сообщение.

Их код представлял собой смесь .NET 3.x и 2.2, что, как я понимаю, означает, что они используют TLS 1.0.

Приведенный ниже ответ может помочь вам диагностировать проблему, включив TLS 1.0, SSL 2 и SSL3, но, чтобы быть предельно ясным, вы не хотите делать это в долгосрочной перспективе, поскольку все три этих протокола считаются небезопасными и больше не должны быть используется :

Чтобы наш IIS отвечал на их вызовы API, нам пришлось добавить параметры реестра на сервере IIS для явного включения версий TLS - ПРИМЕЧАНИЕ. После внесения этих изменений необходимо перезапустить сервер Windows (а не только службу 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

Если этого не произойдет, вы также можете поэкспериментировать с добавлением записи для 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

Чтобы было ясно, это не лучшее решение , и правильное решение - заставить вызывающего абонента использовать TLS 1.2, но приведенное выше может помочь диагностировать, что это проблема.

Вы можете ускорить добавление этих записей реестра с помощью этого сценария 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

Это измененная версия сценария со страницы справки Microsoft по настройке TLS для VMM . Эта статья на basics.net была страницей, которая изначально натолкнула меня на идею взглянуть на эти настройки.

tomRedox
источник
Наша проблема была связана с конвейером выпуска через Team City, который внезапно остановился, когда мы изменили сертификат для вашего живого сервера. Мы уже изменили сервер, чтобы использовать только TLS1.2, и наш конвейер Team City перестал работать ... Работал как мечта ... добавили записи reg и перезапустили сервер ... БУМ !!! Спасибо tomRedox !!
Gwasshoppa
@Gwasshoppa, просто хочу повторить, что вышеизложенное является лишь временной мерой для диагностики проблемы. Теперь вы знаете, что это проблема с версией TLS. Решение состоит в том, чтобы изменить конвейер выпуска, чтобы он мог работать с TLS1.2, а затем снова отключить TLS <1.2 и SSL 2 и 3. Я немного обновил ответ выше, чтобы это тоже подчеркнуть.
tomRedox
4

Просто добавь:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

M.Qudah
источник
1
Пожалуйста, объясните свой ответ.
Word Rearranger
4
Этот ответ тоже ничего не добавляет к предыдущим.
Arvindh Mani
2

Это, если кому-то поможет, у нас проблема с отсутствующим сертификатом. Среда - это стандарт Windows Server 2016 с .Net 4.6.

Существует https URI-адрес службы WCF, для которого Service.Open () будет выполняться без ошибок. Другой поток будет продолжать обращаться к https: // OurIp: 443 / OurService? Wsdl, чтобы гарантировать доступность службы. Доступ к WSDL, использованный для сбоя:

Базовое соединение было закрыто: при отправке произошла непредвиденная ошибка.

Использование ServicePointManager.SecurityProtocol с применимыми настройками не помогло. Игра с ролями и функциями сервера тоже не помогла. Затем вмешался Jaise George , SE, решивший проблему за пару минут. Джейс установил самоподписанный сертификат в IIS, устраняя проблему. Вот что он сделал для решения проблемы:

(1) Откройте диспетчер IIS (inetmgr) (2) Щелкните узел сервера на левой панели и дважды щелкните «Сертификаты сервера». (3) Нажмите «Создать самоподписанный сертификат» на правой панели и введите все, что хотите, в качестве понятного имени. (4) Нажмите «Веб-сайт по умолчанию» на левой панели, нажмите «Привязки» на правой панели, нажмите «Добавить», выберите «https», выберите только что созданный сертификат и нажмите «ОК» (5) Доступ https URL, он должен быть доступен.

DiligentKarma
источник
Однако вы могли подумать, что администратор сервера добавил бы сертификат SSL! D'о! lol :) Я вижу, что это происходит - или сертификат с истекшим сроком действия, который требует обновления, вероятно, будет более подходящим сценарием.
vapcguy
2

Вы просто меняете версию своего приложения, например с 4.0 на 4.6, и публикуете этот код.

Также добавьте строки кода ниже:

httpRequest.ProtocolVersion = HttpVersion.Version10; 
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
Viresh
источник
1

Это может быть вызвано использованием прокси-сервера отладки HTTP, например Fiddler.

Я загружал сертификат PFX из локального файла (аутентификация на Apple.com), и это не удалось, потому что Fiddler не смог передать этот сертификат.

Попробуйте отключить Fiddler, чтобы проверить, и если это решение, вам, вероятно, нужно установить сертификат на свой компьютер или каким-либо образом, чтобы Fiddler мог его использовать.

Simon_Weaver
источник
0

Приведенный ниже код решил мою проблему:

request.ProtocolVersion = HttpVersion.Version10; // THIS DOES THE TRICK
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
Полковник Программное обеспечение
источник