Подтвердить что ты не робот

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;
      }
   }
4b9b3361

Ответ 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.