TLS 1.2 не согласован в .NET 4.7 без явного вызова ServicePointManager.SecurityProtocol
Мне нужно обновить приложение .NET для поддержки вызова API на веб-сайте, который поддерживает только TLS 1.2. Из того, что я прочитал, если приложение нацелено на 4.6 или выше, оно будет использовать TLS 1.2 по умолчанию.
Для тестирования я создал приложение Windows Forms, цель которого 4.7. К сожалению, это ошибки, когда я не устанавливаю явно ServicePointManager.SecurityProtocol. Вот код:
HttpClient _client = new HttpClient();
var msg = new StringBuilder();
// If I uncomment the next line it works, but fails even with 4.7
// ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var httpWebRequest = (HttpWebRequest)WebRequest.Create("https://sandbox.authorize.net");
httpWebRequest.KeepAlive = false;
try
{
var httpWebResponse = (HttpWebResponse) httpWebRequest.GetResponse();
msg.AppendLine("The HTTP request Headers for the first request are: ");
foreach (var header in httpWebRequest.Headers)
{
msg.AppendLine(header.ToString());
}
ResponseTextBox.Text = msg.ToString();
}
catch (Exception exception)
{
ResponseTextBox.Text = exception.Message;
if (exception.InnerException != null)
{
ResponseTextBox.Text += Environment.NewLine + @" ->" + exception.InnerException.Message;
if (exception.InnerException.InnerException != null)
{
ResponseTextBox.Text += Environment.NewLine + @" ->" + exception.InnerException.InnerException.Message;
}
}
}
Если вы раскомментируете следующую строку:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
он работает. Это нехорошее решение, поскольку он жестко кодирует версию TLS, поэтому в будущем он не будет использовать TLS 1.3.
Что еще мне нужно сделать, чтобы заставить его работать без этой строки. Я тестирую машину Window 10 с установленным 4.7.
Обновление
Я попробовал тест с HttpClient и имел те же результаты, я должен был явно установить SecurityProtocol.
Код:
var msg = new StringBuilder();
// Need to uncomment code below for TLS 1.2 to be used
// ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
try
{
var response = await _client.GetAsync(@"https://sandbox.authorize.net");
msg.AppendLine("response.IsSuccessStatusCode : " + response.IsSuccessStatusCode);
msg.AppendLine(await response.Content.ReadAsStringAsync());
textBox.Text = msg.ToString();
}
catch (Exception exception)
{
textBox.Text = exception.Message;
if (exception.InnerException != null)
{
textBox.Text += Environment.NewLine + @" ->" + exception.InnerException.Message;
}
}
Ответы
Ответ 1
Я нашел одно решение. Он не отвечает на вопрос о том, почему TLS 1.2 не используется по умолчанию для Win10 с .NET 4.7, но это не позволяет мне устанавливать ServicePointManager.SecurityProtocol.
Решение, которое работало как с моими тестовыми приложениями 4.5.2, так и 4.7, заключается в добавлении следующего в app.config:
<AppContextSwitchOverrides value="Switch.System.Net.DontEnableSchUseStrongCrypto=false"/>
Здесь весь файл app.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7"/>
</startup>
<runtime>
<AppContextSwitchOverrides value="Switch.System.Net.DontEnableSchUseStrongCrypto=false"/>
</runtime>
</configuration>
Ответ 2
Начиная с приложений, предназначенных для .NET Framework 4.7, значением по умолчанию свойства ServicePointManager.SecurityProtocol является SecurityProtocolType.SystemDefault.
Это изменение позволяет сетевым API-интерфейсам .NET Framework на основе SslStream (таким как FTP, HTTPS и SMTP) наследовать протоколы безопасности по умолчанию от операционной системы вместо использования жестко заданных значений, определенных .NET Framework.
Вот причина нового поведения, которое вы испытали, и необходимость новой конфигурации:
<runtime>
<AppContextSwitchOverrides value="Switch.System.ServiceModel.DisableUsingServicePointManagerSecurityProtocols=false;Switch.System.Net.DontEnableSchUseStrongCrypto=false" />
</runtime>
Смотрите здесь и здесь
Ответ 3
В качестве альтернативы ответа Nick Y я обнаружил, что в Windows 7 с использованием .NET 4. 7+ мне нужно было включить эти параметры реестра, чтобы пакет безопасного канала Microsoft (Schannel) правильно отправлял TLS1.1 и TLS1. 2.
Это позволяет клиенту .NET по-прежнему иметь для System.Net.ServicePointManager.SecurityProtocol
значение SystemDefault
и получать TLS 1.1 и 1.2 на компьютере под управлением Windows 7.
Использование опции SystemDefault
позволяет .NET отложить выбор протоколов для ОС. Это означает, что когда Microsoft выпускает исправления в ОС для отключения небезопасных протоколов или включает поддержку новых в своей собственной библиотеке SCHANNEL, приложения .NET Framework автоматически получат это новое поведение.
Вот записи реестра:
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Client]
"DisabledByDefault"=dword:00000000
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client]
"DisabledByDefault"=dword:00000000
Ответ 4
Я на Windows 7 и .NET 4.7.1
Рекомендация по использованию Switch.System.ServiceModel.DisableUsingServicePointManagerSecurityProtocols и Switch.System.Net.DontEnableSchUseStrongCrypto, упомянутая в двух других ответах, не работала в моем проекте, и код OP также не выполнялся.
Просматривая исходный код для ServicePointManager и LocalAppContextSwitches, я натолкнулся на другой параметр конфигурации, который работал.
<runtime>
<AppContextSwitchOverrides value="Switch.System.Net.DontEnableSystemDefaultTlsVersions=true" />
</runtime>
Ответ 5
У меня была та же проблема (только для Windows 10 и SSL3/TLS... не по умолчанию в системе) с устаревшим приложением, предназначенным для 4.7.2. Моя проблема заключалась в том, что на протяжении многих лет в процессе обновления мы никогда не добавляли targetFramework
в элемент system.web
> httpRuntime
(примечание: он существовал в system.web
> compilation
). Прежде чем предпринимать большие шаги, убедитесь, что ваш system.web выглядит примерно так:
<system.web>
<compilation targetFramework="4.7.2"></compilation>
<httpRuntime targetFramework="4.7.2" />
</system.web>
В приведенном выше примере, поменяйте местами 4.7.2 для любой версии используемой в настоящее время платформы, которая>> 4.7.