"Базовое соединение было закрыто: при отправке произошла непредвиденная ошибка". С сертификатом SSL
Проблема: я получаю это исключение "ПОДКЛЮЧЕНО ПОДКЛЮЧЕНИЕ: НЕОЖИДАННАЯ ОШИБКА, ПОВЛЕННАЯ В ОТПРАВЛЕНИИ" в моих журналах, и это нарушает нашу интеграцию 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`
16 ответов
Для меня это был tls12:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
Если вы застряли в.Net 4.0, а целевой сайт использует TLS 1.2, вам нужна следующая строка.ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;
Источник: TLS 1.2 и.NET Поддержка: как избежать ошибок подключения
Перейдите к web.config/App.config, чтобы проверить, какую среду.net вы используете.
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
Вот решение:
.NET 4.6 и выше. Вам не нужно выполнять дополнительную работу для поддержки TLS 1.2, она поддерживается по умолчанию.
.NET 4.5. TLS 1.2 поддерживается, но это не протокол по умолчанию. Вы должны зарегистрироваться, чтобы использовать его. Следующий код установит TLS 1.2 по умолчанию, обязательно выполните его перед установлением соединения с защищенным ресурсом:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
- .NET 4.0. TLS 1.2 не поддерживается, но если в вашей системе установлен.NET 4.5 (или выше), вы все равно можете выбрать TLS 1.2, даже если ваша прикладная среда не поддерживает его. Единственная проблема заключается в том, что SecurityProtocolType в.NET 4.0 не имеет записи для TLS1.2, поэтому нам пришлось бы использовать числовое представление этого значения перечисления:
ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;
- .NET 3.5 или ниже. TLS 1.2 не поддерживается (*) и обходного пути нет. Обновите ваше приложение до более новой версии фреймворка.
Код ниже решил проблему
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls Or SecurityProtocolType.Ssl3
У меня была такая же проблема в течение нескольких дней с интеграцией, которая также просто "раньше работала".
Из чистой депрессии я только что попробовал
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Ssl3;
Это решило это для меня.. даже если интеграция строго использует только SSLv3.
Я пришел к выводу, что что-то в выключенном состоянии, так как Fiddler сообщил, что существует "пустой шифр согласования TLS" или что-то подобное.
Надеюсь, это работает!
В моем случае сайт, к которому я подключаюсь, обновился до TLS 1.2. В результате мне пришлось установить.net 4.5.2 на мой веб-сервер, чтобы поддерживать его.
Just add:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
Я нашел Решение, обновив web.config приведенным ниже кодом.
Мой .Net Framwork был установлен на 4.0, и после обновления протокола TLS на уровне организации я внезапно столкнулся с этой проблемой. Итак, я упомянул выше ответ «Гу Хуанга» и обновил targetFramework, и он сработал.
<system.web>
<compilation debug="true" targetFramework="4.7.2" />
<httpRuntime targetFramework="4.7.2" maxRequestLength="102400" executionTimeout="3600"/>
</system.web>
Я обнаружил, что это признак того, что на сервере, на котором вы развертываете код, установлена старая платформа.NET, которая не поддерживает TLS 1.1 или TLS 1.2. Шаги, чтобы исправить:
- Установка последней версии.NET Runtime на ваших производственных серверах (IIS & SQL)
- Установка последней версии.NET Developer Pack на ваших машинах разработки.
- Измените настройки "Целевой фреймворк" в ваших проектах Visual Studio на последнюю.NET Framework.
Вы можете получить последнюю версию.NET Developer Pack и Runtime с этого URL: http://getdotnet.azurewebsites.net/target-dotnet-platforms.html
У нас возникла проблема, из-за которой веб-сайт, который обращался к нашему API, получал сообщение "Базовое соединение было закрыто: при отправке произошла непредвиденная ошибка".
Их код представлял собой смесь.NET 3.x и 2.2, что, как я понимаю, означает, что они используют TLS 1.0.
Чтобы заставить 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, но приведенное выше может помочь диагностировать, что это проблема.
Вы можете ускорить добавление этих записей reg с помощью этого сценария 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 была страницей, которая изначально дала мне идею взглянуть на эти настройки.
Вы просто меняете версию своего приложения, например с 4.0 на 4.6, и публикуете этот код.
Также добавьте строки кода ниже:
httpRequest.ProtocolVersion = HttpVersion.Version10;
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
Если кому-то поможет, у нас возникла проблема с отсутствующим сертификатом. Среда является Windows Server 2016 Standard с.Net 4.6.
Существует самодостаточный URI https службы WCF, для которого Service.Open() будет выполняться без ошибок. Другой поток будет продолжать обращаться к https://ourip/OurService?wsdl, чтобы обеспечить доступность службы. Доступ к WSDL, используемый для сбоя с:
Основное соединение было закрыто: при отправке произошла непредвиденная ошибка.
Использование ServicePointManager.SecurityProtocol с применимыми настройками не работало. Игра с серверными ролями и функциями также не помогла. Затем зашёл в Jaise George, SE, решив проблему за пару минут. Jaise установил самозаверяющий сертификат в IIS, устраняя проблему. Вот что он сделал, чтобы решить проблему:
(1) Откройте диспетчер IIS (inetmgr). (2) Нажмите на узел сервера в левой панели и дважды щелкните "Сертификаты сервера". (3) Нажмите "Создать самоподписанный сертификат" на правой панели и введите желаемое имя. (4) Нажмите "Веб-сайт по умолчанию" на левой панели, нажмите "Привязки" на правой панели, нажмите "Добавить", выберите "https", выберите сертификат, который вы только что создали, и нажмите "OK" (5) Доступ URL-адрес https, он должен быть доступен.
Использование прокси-сервера отладки HTTP может вызвать это - например, Fiddler.
Я загружал сертификат PFX из локального файла (аутентификация на Apple.com), и он не удался, потому что Fiddler не смог передать этот сертификат.
Попробуйте отключить Fiddler, чтобы проверить, и если это решение, то вам, вероятно, нужно установить сертификат на свой компьютер или каким-то образом Fiddler может его использовать.
В моем случае ничего из вышеперечисленного не сработало. Пока кто-то не указал мне на следующий веб-сайт. Проверьте, включен ли TLS 1.2.
Оказалось, что на сервере были записи в реестре только для SSL 2.0 и SSL 3.0. После добавления записей для протоколов TLS проблема исчезла.
Либо нет общей настройки TLS, либо нет общего шифра между вашим доменом приложения (клиентом) и сайтом (сервером). Каждый домен приложения (например, powershell, cmd, ваше приложение и т. д.) выбирает настройки клиента хоста по умолчанию (или переопределяет их), поэтому у вас может быть, например, рабочая оболочка cmd, но сбой powershell и т. д.
Вы можете проверить целевой URL-адрес, например, https://www.ssllabs.com/ssltest/analyze.html?d=api.nuget.org .
и вы можете проверить настройки своих доменов приложений, например,
[Net.ServicePointManager]::SecurityProtocol
and
Get-TlsCipherSuite | Format-Table Name
Ослабление настроек TLS, например, для разрешения ssl3, может сработать в краткосрочной перспективе, но мне кажется плохой идеей.
Приведенный ниже код решил мою проблему:
request.ProtocolVersion = HttpVersion.Version10; // THIS DOES THE TRICK
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;