安装 .net Framework 4.7.2 时,4.5.1 应用程序中的 TLS1.2 协商失败

Posted

技术标签:

【中文标题】安装 .net Framework 4.7.2 时,4.5.1 应用程序中的 TLS1.2 协商失败【英文标题】:TLS1.2 negotiation fails within a 4.5.1 application when .net Framework 4.7.2 is installed 【发布时间】:2018-12-18 02:21:25 【问题描述】:

我们目前在使用基于 Web 的应用程序时遇到问题。它可以在任何操作系统 win2k12 R2 和 IIS 上运行良好。该应用程序是针对 .net Framework 4.5.1 编译的。虽然我们知道较新的 .NET Framework 版本,但由于一些不方便的 3rd 方依赖项,我们在更新方面遇到了困难。

最近,微软发布了隐式安装 .NET Framework 4.7.2 的 KB。安装了这些更新的客户现在面临着一个重大问题。

以下代码虽然过于简单,但包含所有必要信息。

private HttpWebResponse GetResponse(HttpWebRequest httpWebRequest)

            lock (Statics._lockObject)
            

                HttpWebResponse httpResponse = null;
                SecurityProtocolType tempProtocol = ServicePointManager.SecurityProtocol;

                //ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;

                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;   // Magic Number equals SecurityProtocolType.Tls1.2 
                ServicePointManager.ServerCertificateValidationCallback = CheckSSL;
                try
                
                    httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
                
                catch (Exception ex) 
                
                    System.Diagnostics.Debug.WriteLine(ex.Message + Environment.NewLine + ex.StackTrace);
                
                finally
                
                    ServicePointManager.SecurityProtocol = tempProtocol;
                    ServicePointManager.ServerCertificateValidationCallback = null;
                
                return httpResponse;
            
        

在安装了 .NET Framework 4.7.2 的系统上执行此操作时,我们在 GetResponse()call 中收到以下错误:

“底层连接已关闭:发送时发生意外错误。”

 at System.Net.HttpWebRequest.GetResponse()

和内部异常:

“验证失败,因为远程方关闭了传输流。”

at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest) at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest) at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest) at System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest) at System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Net.TlsStream.ProcessAuthentication(LazyAsyncResult result) at System.Net.TlsStream.Write(Byte[] buffer, Int32 offset, Int32 size) at System.Net.ConnectStream.WriteHeaders(Boolean async)

卸载上述 KB 并因此卸载 .NET Framework 4.7.2 确实有帮助,但对我们的客户群来说是没有选择的。

到目前为止,我们尝试的其他选项是:

如下设置注册表项: [HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\.NETFramework\v4.0.30319] "SystemDefaultTlsVersions"=dword:00000001 "SchUseStrongCrypto"=dword:00000001

同时在 ServicePointManager.SecurityProtocol 属性中注释掉 tls 1.2 的显式设置 (来源:https://docs.microsoft.com/en-us/dotnet/framework/network-programming/tls#schusestrongcrypto)

设置应用上下文开关:

Switch.System.ServiceModel.DontEnableSystemDefaultTlsVersions Switch.System.ServiceModel.DisableUsingServicePointManagerSecurityProtocols

(来源:https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/runtime/appcontextswitchoverrides-element)

到目前为止,我们无法对抛出的异常进行任何更改。 谁能指出我们正确的方向?

非常感谢您!

更新:

由于cmets的推荐,我们做了几个wireshark traces。

没有框架 4.7.2 安装,我们的应用程序协商 - 正如我们的代码示例所建议的 - tls 1.2 与服务器应用程序成功协商:

之后,我们将代码更改为专门设置 tls 1.1,只是为了确认设置 ServicePointManager.SecurityProtocol 会产生影响,我们看到,毫不奇怪,应用程序无法协商 tls 1.1:

现在有趣的部分,我们再次安装了.NET Framework 4.7.2,重新设置了代码来具体说

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

并再次跟踪呼叫。现在,令我们惊讶的是,该应用程序尝试协商 tls 1.0,这当然失败了:

之后,我们通过以下方式专门禁用了操作系统上的 tls 1.0:

`HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Client

"Enabled"=dword:0000000
"DisabledByDefault"=dword:00000001 `

再次查看 Wireshark,应用程序尝试协商 ssl3.0。回到注册表并专门禁用该注册表,Wireshark 中不再显示 ClientHello,并且异常说,找不到相互算法来连接到服务器。

【问题讨论】:

这听起来像是一个奇怪的问题,但您尝试过哪些客户端?我唯一的想法是更新可能会引入一个新的 TLS Ciper 套件,它可能无法与浏览器/客户端 PC 一起使用。例如,Chrome 使用自己的 TLS 逻辑,而 IE 和 .NET 代码匹配 Windows 的设置。我很想知道它们是否会在您的错误中产生不同的结果。进行网络捕获/wireshark 还可以提供一些关于正在协商哪些协议的见解。比较好与坏的协商可能表明握手的哪一部分导致它失败。 是不是服务器不支持TLS1.2?这将解释错误。另一种选择是查看 Wireshark 跟踪以查看失败的详细信息... 谢谢,伙计们!我已经用我们的wireshark跟踪更新了这个问题。 在您的服务器上安装 IIsCrypto 以检查您的服务器上启用了哪些 TLS 版本,从哪个应用程序运行,确保远程方(Web 服务或 DB 服务器)也实现 TLS 1.2 @ABDmaverick 谢谢你的提示; IISCrypto 告诉我运行应用程序的计算机的出厂默认设置(Win 10)。我摆弄了一下,设置了“最佳实践”选项,它只启用了 TLS 1.0 - 1.2,仍然尝试协商 TLS 1.0,我将协议限制为仅 TLS 1.2,除了我计算机上几乎所有应用程序崩溃之外,我的应用程序没有协商任何东西,抛出的异常表明没有相互算法可以使用......从不同的计算机,可以通过上述例程轻松地通过 TLS 1.2 访问服务器。 【参考方案1】:

尝试设置这些注册表设置:

Key: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v4.0.30319 
   Value: SchUseStrongCrypto 
     Data: 1

Key: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server    
   Value: Enabled
     Data: 0
   Value: DisabledByDefault
     Data: 1

之后,在您的 HTTPWebRequest 包含 ServicePointManager 更改之前:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

这应该会强制您的应用程序使用 TLS 1.2。我没有看到任何说您一次尝试了上述所有方法,并且这样做对我们有用。

【讨论】:

嗨,Phen,感谢您的评论!在您发布答案前几个小时,我们确实发现仅在 Wow6432Node 中设置“SchUseStrongCrypto”密钥不足以协调 .NET Framework。 ServicePointManager.SecurityProtocol 现在默认为 Tls1.0 | TLS 1.1 | 1.2。像魅力一样工作!

以上是关于安装 .net Framework 4.7.2 时,4.5.1 应用程序中的 TLS1.2 协商失败的主要内容,如果未能解决你的问题,请参考以下文章

安装.Net Framework 4.7.2时出现“不受信任提供程序信任的根证书中终止”的解决方法

.net framework 版本低于4.5.2的系统可以重装win10解决吗

在 .Net Framework 4.7.2 中注册 ServiceStack.OrmLite

.NET Core Httpclient 有效,但 .Net Framework 4.7.2 httpclient 无效

EnableCors 使用 ApiController 但不使用 Controller .NET Framework 4.7.2

将解决方案从 .net framework 4 升级到更高版本。 4.7.2; 4.8.VS2013