没有明确的ServicePointManager.SecurityProtocol调用,在.NET 4.7中没有协商TLS 1.2

Jos*_*osh 31 .net c# httpwebrequest winforms tls1.2

我需要升级.NET应用程序以支持在仅支持TLS 1.2的网站上调用API.根据我的阅读,如果应用程序的目标是4.6或更高,那么默认情况下它将使用TLS 1.2.

为了测试我创建了一个面向4.7的Windows窗体应用程序.不幸的是,当我没有明确设置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;
       }
   }
}
Run Code Online (Sandbox Code Playgroud)

如果取消注释以下行:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
Run Code Online (Sandbox Code Playgroud)

有用.这不是一个好的解决方案,因为它硬编码要使用的TLS版本,因此将来不会使用TLS 1.3.

如果没有这条线,我还需要做些什么才能让它工作.我正在安装4.7的Window 10机器上进行测试.

更新

我尝试使用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;
      }
   }
Run Code Online (Sandbox Code Playgroud)

Gia*_*tti 16

从面向.NET Framework 4.7的应用程序开始,ServicePointManager.SecurityProtocol属性的默认值为SecurityProtocolType.SystemDefault.

此更改允许基于SslStream的 .NET Framework网络API (如FTP,HTTPS和SMTP)从操作系统继承默认安全协议,而不是使用.NET Framework定义的硬编码值.

这就是您遇到的新行为和新配置需求的原因:

<runtime>
   <AppContextSwitchOverrides value="Switch.System.ServiceModel.DisableUsingServicePointManagerSecurityProtocols=false;Switch.System.Net.DontEnableSchUseStrongCrypto=false" /> 
</runtime>
Run Code Online (Sandbox Code Playgroud)

看到这里这里


Mer*_*OWA 8

作为尼克Y答案的替代方法,我发现在使用.NET 4.7+的Windows 7上,我需要启用这些注册表设置,以便Microsoft安全通道(Schannel)程序包正确发送TLS1.1和TLS1.2。

这使.NET客户端可以继续System.Net.ServicePointManager.SecurityProtocol设置为SystemDefaultWindows 7计算机上的TLS 1.1和1.2 ,并获得它们。

使用该SystemDefault选项,.NET可以将协议的选择推迟到OS。这意味着,当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
Run Code Online (Sandbox Code Playgroud)

  • @osexpert号 如果设置“ DontEnableSystemDefaultTlsVersion = true”,则禁用操作系统的默认协议,仅在安装的.NET版本中启用默认协议。就我而言,如果操作系统已打补丁以启用新协议,则我希望启用它们。我不想仅为了启用新版本的TLS而更新应用程序的配置或.NET框架版本。 (2认同)
  • 微软建议与Merick达成协议,使用SystemDefault,并且启用更新版本的TLS应该是Windows Update / Hotfix的工作。 (2认同)

Jos*_*osh 6

我找到了一个解决方案.它没有回答为什么默认情况下在使用.NET 4.7的Win10上使用TLS 1.2的问题,但它确实允许我不必设置ServicePointManager.SecurityProtocol.

我的4.5.2和4.7测试应用程序的解决方案是将以下内容添加到app.config:

<AppContextSwitchOverrides value="Switch.System.Net.DontEnableSchUseStrongCrypto=false"/>
Run Code Online (Sandbox Code Playgroud)

这里整个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>
Run Code Online (Sandbox Code Playgroud)

  • 我在一个简单的控制台应用程序中尝试了此操作,该应用程序向仅TLS 1.2的Web服务发出“ HttpClient”请求,然后在Windows 7 SP1上运行了控制台程序。不幸的是,它的作用为零。投票失败。 (2认同)

小智 5

我在Windows 7和.NET 4.7.1上

另外两个答案中提到的使用Switch.System.ServiceModel.DisableUsingServicePointManagerSecurityProtocolsSwitch.System.Net.DontEnableSchUseStrongCrypto的建议在我的项目中不起作用,OP的代码也失败了。

查看ServicePointManagerLocalAppContextSwitches的源代码我遇到了另一个有效的配置设置

<runtime>
  <AppContextSwitchOverrides value="Switch.System.Net.DontEnableSystemDefaultTlsVersions=true" />
</runtime>
Run Code Online (Sandbox Code Playgroud)


sco*_*kel 5

我有一个针对4.7.2的旧版应用程序存在相同的问题(仅Windows 10和SSL3 / TLS ...不是系统默认值)。我的问题是,在过去几年的升级过程中,我们从未将> 元素添加targetFramework到(注意:它确实存在于> 元素中)。在采取更大的步骤之前,请确保您的system.web如下所示:system.webhttpRuntimesystem.webcompilation

<system.web>
    <compilation targetFramework="4.7.2"></compilation>
    <httpRuntime targetFramework="4.7.2" />
</system.web>
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,将4.7.2替换为当前使用的框架的任何版本,即> = 4.7。

  • 这正是我所拥有的。同样,我们将应用程序升级到 4.7.2 并忘记更改“httpRuntime”。 (2认同)
  • 谢谢,这解决了问题...任何人都可以告诉我为什么项目升级到 .Net 4.7 后 httpRuntime 没有自动设置为 4.7.2 吗? (2认同)