TLS 1.2 未在 .NET 4.7 中协商,没有显式的 ServicePointManager.SecurityPr



我需要升级一个 .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。

在没有这条线的情况下,我还需要做什么才能让它工作。我正在从安装了 10 的 Window 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;
}
}

我遇到了同样的问题(仅限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)。

从面向 .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>

看这里和这里

更新(有用信息)

请记住,最佳安全实践建议更新 IIS 配置,禁用旧协议和密码密钥(例如 TLS 1.0、1.1)。请参阅 Windows 或 IIS 的安装程序 SSL 完全向前保密Microsoft 和 TLS 1.2 以获取非常有趣的信息。

如果您遵循这种做法,则无需设置上述配置(如MS建议的那样),因为您的Win服务器/IIS已经配置良好。

当然,只有当您可以通过适当的授权访问服务器时,这才有可能。

作为 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。

使用SystemDefault选项允许 .NET 将协议的选择推迟到操作系统。 这意味着,当Microsoft向操作系统发布修补程序以禁用不安全协议或在其本机 SCHANNEL 库中启用对新协议的支持时,运行的 .NET 框架应用将自动获得此新行为。

以下是注册表项:

[HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.1Client]
"DisabledByDefault"=dword:00000000
[HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.2Client]
"DisabledByDefault"=dword:00000000

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

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

<AppContextSwitchOverrides value="Switch.System.Net.DontEnableSchUseStrongCrypto=false"/>

这里是整个应用程序配置:

<?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>

我在Windows 7和.NET 4.7.1上

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

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

<runtime>
<AppContextSwitchOverrides value="Switch.System.Net.DontEnableSystemDefaultTlsVersions=true" />
</runtime>

对于最初使用 .NET Framework 4.5.2 开发然后升级到 4.7 的 Word VSTO 加载项项目,我遇到了同样的问题。尝试了这里的所有解决方案,但没有一个对我有用。终于找到了这篇文章。

对于那些在VSTO加载项项目方面遇到与我相同问题的人,请在ThisAddIn.cs类中添加这些代码,它对我有用。

AppContext.SetSwitch("Switch.System.ServiceModel.DisableUsingServicePointManagerSecurityProtocols", false);
AppContext.SetSwitch("Switch.System.Net.DontEnableSchUseStrongCrypto", false);

Windows 7默认禁用TLS1.2和TLS1.1。在 IE 中启用它对其他应用程序没有影响。

您应该通过注册表启用它: [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client] "默认禁用"=dword:00000000

非常有用的文章,脚本设置为仅TLS1.2

相关内容

最新更新