我正在C#(.Net framework 3.5)应用程序中使用SSL POST调用来开发登录/注销功能。通过HttpWebRequest::BeginGetResponse()从服务器获取响应80%的时间有效,但其他20%的时间是间歇性抛出:
The request was aborted: Could not create SSL/TLS secure channel.
我使用另一个问题中的建议文章启用了SSL跟踪。这在请求跟踪中产生了两种不同的模式。
似乎在执行过程中,错误:
System.Net Error: 0 : [3680] Decrypt returned SEC_I_RENEGOTIATE.
正在接收,导致安全上下文的重新初始化。当这种情况发生并且成功时,以下是输出(注意我省略了实际地址):
System.Net Error: 0 : [3680] Decrypt returned SEC_I_RENEGOTIATE.
System.Net Information: 0 : [3680] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 4bec0d0:4c0a8a8, targetName = [omitted].com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [3680] InitializeSecurityContext(In-Buffer length=0, Out-Buffer length=78, returned code=ContinueNeeded).
System.Net Information: 0 : [7148] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 4bec0d0:4c0a8a8, targetName = [omitted].com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [7148] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=ContinueNeeded).
System.Net Information: 0 : [7148] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 4bec0d0:4c0a8a8, targetName = [omitted].com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [7148] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=ContinueNeeded).
System.Net Information: 0 : [7148] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 4bec0d0:4c0a8a8, targetName = [omitted].com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [7148] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=1259, returned code=ContinueNeeded).
System.Net Information: 0 : [7148] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 4bec0d0:4c0a8a8, targetName = [omitted].com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [7148] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=ContinueNeeded).
System.Net Information: 0 : [7148] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 4bec0d0:4c0a8a8, targetName = [omitted].com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [7148] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=OK).
System.Net Information: 0 : [7148] Remote certificate: [Version]
V1
失败时:
System.Net Error: 0 : [3680] Decrypt returned SEC_I_RENEGOTIATE.
System.Net Information: 0 : [3680] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 4bec0d0:4c0ab50, targetName = [omitted].com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [3680] InitializeSecurityContext(In-Buffer length=0, Out-Buffer length=78, returned code=ContinueNeeded).
System.Net Error: 0 : [3680] Exception in the HttpWebRequest#20730349:: - The request was aborted: Could not create SSL/TLS secure channel.
System.Net Verbose: 0 : [3680] HttpWebRequest#20730349::EndGetResponse()
System.Net Error: 0 : [3680] Exception in the HttpWebRequest#20730349::EndGetResponse - The request was aborted: Could not create SSL/TLS secure channel.
我当然可以发现这个异常,但正确的处理方法是什么?
我的应用程序有没有办法防止(或正确处理)这些错误?当这种情况发生时,它似乎会在一段时间内不断出错,但在一些数量不确定的请求之后,它又开始工作了。
谢谢!
(有关原始答案,请参阅下文。)
此错误通常意味着您的客户端和服务器未设置为使用相同类型的加密。通常,解决此问题的最简单方法是显式设置要在客户端中使用的版本。
如果您使用的是.NET 4.5或更新版本,以下是可以尝试的选项,按从最安全到最不安全的顺序排列:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
如果您使用的是.NET 4.0或更低版本,则只能使用上面的最后一行,因为这些版本不支持TLSv1.1和TLSv1.2强烈建议您升级到.NET 4.5以利用对TLSv1.2的支持
除了设置SecurityProtocol
属性外,您可能还必须设置:ServicePointManager.Expect100Continue = true;
如果这些设置都没有帮助,则可能意味着您的服务器只支持SSLv3(或者更糟的是,SSLv2)。如果是这种情况,升级您的服务器SSLv3已损坏,不应再使用。
SSLv3不再被认为是安全的。不要使用这些设置虽然这是2011年的正确答案,但它仍然存在只是出于历史原因。
您需要在请求之前添加以下代码行:
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
据我所见,旧版本(.NET 2和/或Windows xp/2003及更旧版本)使用这些选项作为默认选项,但新版本(.NET 3和/或WindowsVista/2008及更高版本)没有
这不是一个解释,也不是一个真正的解决方案:这只是我们在案例中发现的处理这个问题的最实用的方法(使用基于Apache和Java的服务器的客户端SSL证书通过HTTPS执行WCF SOAP请求)。
捕获SecurityNegotiationException并当场重试(即,如果使用msmq,则不重新处理消息),并在这种情况下禁止报告异常。只要加一个性能计数器或类似的东西,你就可以跟踪问题是否会变得更糟。
归根结底,这只是代码需要处理的与网络相关的固有问题之一。
我想我应该分享我的经验,因为我最近读到了关于的大多数堆叠式问题
我看到的另一种方法是考虑HTTPKeepAlive。对于最新版本的.Net,它使用HTTP 1.1作为默认值,这意味着Keep Alive设置为true,Expect100也处于启用状态。
根据我的经验,这会对下游资源产生粘性,并且在负载均衡器后面是不可靠的。
两种选择
1) 恢复并重试,这似乎有点臭。然而,正如Khanfx所提到的,网络问题可能会发生在网络的谬误中。TOPAZ是解决这个问题的一种方法:https://msdn.microsoft.com/en-us/library/hh680901%28v=pandp.50%29.aspx?f=255&MSPP错误=-2147217396
2) 通过HttpwebRequest关闭Keep Alive,或者如果使用HttpClient则发出连接关闭标头。
HTH。