没有明确的ServicePointManager.SecurityProtocol调用,在.NET 4.7中没有协商TLS 1.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; } } } 

如果您取消注释以下行:

 ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; 

有用。 这不是一个好的解决方案,因为它硬编码要使用的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; } } 

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

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

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

    

看到这里和这里

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

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

  

这里整个app.config:

          

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

这允许.NET客户端继续将System.Net.ServicePointManager.SecurityProtocol设置为SystemDefault并在Windows 7计算机上获取TLS 1.1和1.2。

 [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 

我在Windows 7和.NET 4.7.1上

在其他两个答案中提到的使用Switch.System.ServiceModel.DisableUsingServicePointManagerSecurityProtocolsSwitch.System.Net.DontEnableSchUseStrongCrypto的建议在我的项目中没有用,OP的代码也失败了。

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