自POODLE以来,Azure Storage .NET API出现了“无法创建SSL/TLS安全通道”错误。

11

当使用.NET Azure存储API库来处理块以及基于存储的Azure队列时,读取工作,但是创建/删除/更新不起作用。此问题发生在ASP.NET MVC 5.2网站中,.NET 4.5.1,所有库都已完全更新到最新版本。这个问题突然出现在昨天(10月14日)晚上,显然是由于POODLE漏洞变得众所周知。多年来一直在使用此API项目而没有出现这个问题,并且已部署的版本一直工作到那个时间点。

令人沮丧的是,在我的开发/本地计算机上,问题并未出现。

有很长一段时间的滞后,直到错误显示,可能是由于重试尝试或其他原因导致的。

请求被中止:无法创建SSL/TLS安全通道。

System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel.
   at System.Net.HttpWebRequest.GetRequestStream(TransportContext& context)
   at System.Net.HttpWebRequest.GetRequestStream()
   at Microsoft.WindowsAzure.Storage.Core.Executor.Executor.ExecuteSync[T](RESTCommand`1 cmd, IRetryPolicy policy, OperationContext operationContext)   at System.Net.HttpWebRequest.GetRequestStream(TransportContext& context)
   at System.Net.HttpWebRequest.GetRequestStream()
   at Microsoft.WindowsAzure.Storage.Core.Executor.Executor.ExecuteSync[T](RESTCommand`1 cmd, IRetryPolicy policy, OperationContext operationContext)

这就是所有的异常情况。
2个回答

13
我遇到了和你一模一样的问题:昨天许多公司在他们的服务器上禁用了 SSLv3,所以当客户端连接到安全终端时必须协商使用 TLS。

在我的开发机上运行时,一切都像以前一样正常。但是在我的所有生产服务器上,当连接到某些服务器(而不是所有服务器,例如 graph.facebook.com,mandrillapp.com 和其他一些服务器没有出现该问题)时,我收到相同的异常。

有趣的是,应用程序重启解决了该问题约一个小时。然后错误再次出现。

经过一些谷歌搜索,我找到了这行代码

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;

希望能提供一些帮助。问题是,这似乎是一个全局设置,对于我来说解决了一些但并非所有的连接问题。Facebook API 已经恢复正常,但是例如 mandrill 在几个小时后又停止工作并显示异常。

问题似乎在于 .NET HttpWebRequest 类(以及 WebClient 类)或底层的 https 实现在协商通信协议方面存在问题。

我已经阅读到,在 .NET 中,TLS 是标准协议,SSLv3 仅被用作备选方案,但尽管如此,仍然出现了异常。


谢谢Jan,实际上我刚刚在另一个SO线程上发布了与相关问题的解决方案。当这里的粗鲁之人决定对我简单地给出帮助性建议进行负面评价时,我将其删除了。无论如何,我已经设置好了这个。你是对的,它解决了一个问题,但它并没有解决我的主要问题,即Azure存储连接本身无法工作。所以,你是说你找到了最终解决所有问题的东西吗?而且,你自己有Azure存储问题(“无法创建SSL/TLS安全通道”)吗? - Nicholas Petersen
2
@NicholasPetersen 不,我没有使用 Azure 存储。我遇到的问题是在使用 HttpWebRequest 类(看起来你也是这个问题)时使用 https 时出现问题。我发现我的应用程序在某个时间点失败的原因是:我使用的一个组件调用了 ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3。因此,当该组件被调用时,它会强制整个过程仅使用 SSLv3,这导致了我的问题。 - Jan
@Jan - 我认为我欠你一瓶啤酒,因为你的最后一条评论引导我在我们的代码中搜索了SecurityProtocol被设置的其他位置,果然被重置为Ssl。 谢谢! - CodeNaked
@CodeNaked - 哈哈,我想你可以想象出当我发现那行代码时我的脸是什么样子...这只是偶然,我在整个解决方案中搜索神秘的ServicePointManager。而谁写了那个?当然是几年前的我自己 :) - Jan

8

我认为我们已经找到了主要问题:Azure Storage,在使用 Azure 云服务(在最新的 Windows 平台上)与其通信时,似乎无法处理 Tls 1.2 安全协议。

因此设置:

System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; // FAILS!

您需要设置:

System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls; // or Tls11 ?

它可能也无法处理Tls 1.1。我可以检查一下,但我很担心这个项目再次出现问题,哪怕只有一秒钟。

--- 更新 ---

Azure支持人员指出,在.NET 4.5之前(4.0及更早版本),此枚举中唯一可用的Tls值是.Tls(没有Tls11、Tls12)。

请参见msdn文档

我敢打赌Azure存储中接收端(在其自己的内部堆栈上处理请求)也没有使用.NET 4.5(这是一个经过教育的猜测)。

--- 更新结束 ---

本地机器没有问题。这让我想知道客户端(在Azure托管的云服务虚拟机)是否缺少某些东西。

到目前为止,这似乎是有效的。

有关从远程访问实例获取的详细日志信息,请参考以下明显相关的日志,这可能有助于某些人为将来解决此问题。在每种情况下,根本异常是:

System.Security.Authentication.AuthenticationException // (of type: `System.ComponentModel.Win32Exception)`

主要错误消息为:

客户端和服务器无法通信,因为它们没有共同的算法

显然,在这种情况下,其中一个(我认为是云服务客户端?)无法处理Tls1.2?

日志片段:

    DetailID = 6
    Count:    4
    Type:     System.Security.Authentication.AuthenticationException
    Message:  A call to SSPI failed, see inner exception.
        Type:     System.ComponentModel.Win32Exception
        Message:  The client and server cannot communicate, because they do not possess a common algorithm
    Stack:    
        [HelperMethodFrame]
        System.Net.Security.SslState.ForceAuthentication(Boolean, Byte[], System.Net.AsyncProtocolRequest)
        [HelperMethodFrame]
        System.Net.Security.SslState.StartSendAuthResetSignal(System.Net.Security.ProtocolToken, System.Net.AsyncProtocolRequest, System.Exception)
        System.Net.Security.SslState.StartSendBlob(Byte[], Int32, System.Net.AsyncProtocolRequest)
        System.Net.Security.SslState.ProcessReceivedBlob(Byte[], Int32, System.Net.AsyncProtocolRequest)
        System.Net.Security.SslState.StartReceiveBlob(Byte[], System.Net.AsyncProtocolRequest)
        System.Net.Security.SslState.StartSendBlob(Byte[], Int32, System.Net.AsyncProtocolRequest)
        System.Net.Security.SslState.ForceAuthentication(Boolean, Byte[], System.Net.AsyncProtocolRequest)
        System.Net.Security.SslState.ProcessAuthentication(System.Net.LazyAsyncResult)
        System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
        System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
        System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
        System.Net.TlsStream.ProcessAuthentication(System.Net.LazyAsyncResult)
        System.Net.TlsStream.Write(Byte[], Int32, Int32)
        System.Net.ConnectStream.WriteHeaders(Boolean)
        System.Net.HttpWebRequest.EndSubmitRequest()
        System.Net.Connection.CompleteConnection(Boolean, System.Net.HttpWebRequest)
        System.Net.Connection.CompleteStartConnection(Boolean, System.Net.HttpWebRequest)
        System.Net.Connection.CompleteStartRequest(Boolean, System.Net.HttpWebRequest, System.Net.TriState)
        System.Net.Connection.SubmitRequest(System.Net.HttpWebRequest, Boolean)
        System.Net.ServicePoint.SubmitRequest(System.Net.HttpWebRequest, System.String)
        System.Net.HttpWebRequest.SubmitRequest(System.Net.ServicePoint)
        System.Net.HttpWebRequest.GetRequestStream(System.Net.TransportContext ByRef)
        System.Net.HttpWebRequest.GetRequestStream()
        Microsoft.WindowsAzure.Storage.Core.Executor.Executor.ExecuteSync[[System.__Canon, mscorlib]](Microsoft.WindowsAzure.Storage.Core.Executor.RESTCommand`1<System.__Canon>, Microsoft.WindowsAzure.Storage.RetryPolicies.IRetryPolicy, Microsoft.WindowsAzure.Storage.OperationContext)
        Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob.UploadFromStreamHelper(System.IO.Stream, System.Nullable`1<Int64>, Microsoft.WindowsAzure.Storage.AccessCondition, Microsoft.WindowsAzure.Storage.Blob.BlobRequestOptions, Microsoft.WindowsAzure.Storage.OperationContext)
        Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob.UploadFromByteArray(Byte[], Int32, Int32, Microsoft.WindowsAzure.Storage.AccessCondition, Microsoft.WindowsAzure.Storage.Blob.BlobRequestOptions, Microsoft.WindowsAzure.Storage.OperationContext)
        Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob.UploadText(System.String, System.Text.Encoding, Microsoft.WindowsAzure.Storage.AccessCondition, Microsoft.WindowsAzure.Storage.Blob.BlobRequestOptions, Microsoft.WindowsAzure.Storage.OperationContext)
        ... my own project's calls begin here ...

        DetailID = 7
    Count:    4
    Type:     System.Security.Authentication.AuthenticationException
    Message:  A call to SSPI failed, see inner exception.
        Type:     System.ComponentModel.Win32Exception
        Message:  The client and server cannot communicate, because they do not possess a common algorithm
    Stack:    
        [HelperMethodFrame]
        System.Net.TlsStream.ProcessAuthentication(System.Net.LazyAsyncResult)
        [HelperMethodFrame]
        System.Net.Security.SslState.ForceAuthentication(Boolean, Byte[], System.Net.AsyncProtocolRequest)
        [HelperMethodFrame]
        System.Net.Security.SslState.StartSendAuthResetSignal(System.Net.Security.ProtocolToken, System.Net.AsyncProtocolRequest, System.Exception)
        System.Net.Security.SslState.StartSendBlob(Byte[], Int32, System.Net.AsyncProtocolRequest)
        System.Net.Security.SslState.ProcessReceivedBlob(Byte[], Int32, System.Net.AsyncProtocolRequest)
        System.Net.Security.SslState.StartReceiveBlob(Byte[], System.Net.AsyncProtocolRequest)
        System.Net.Security.SslState.StartSendBlob(Byte[], Int32, System.Net.AsyncProtocolRequest)
        System.Net.Security.SslState.ForceAuthentication(Boolean, Byte[], System.Net.AsyncProtocolRequest)
        System.Net.Security.SslState.ProcessAuthentication(System.Net.LazyAsyncResult)
        System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
        System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
        System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
        System.Net.TlsStream.ProcessAuthentication(System.Net.LazyAsyncResult)
        System.Net.TlsStream.Write(Byte[], Int32, Int32)
        System.Net.ConnectStream.WriteHeaders(Boolean)
        System.Net.HttpWebRequest.EndSubmitRequest()
        System.Net.Connection.CompleteConnection(Boolean, System.Net.HttpWebRequest)
        System.Net.Connection.CompleteStartConnection(Boolean, System.Net.HttpWebRequest)
        System.Net.Connection.CompleteStartRequest(Boolean, System.Net.HttpWebRequest, System.Net.TriState)
        System.Net.Connection.SubmitRequest(System.Net.HttpWebRequest, Boolean)
        System.Net.ServicePoint.SubmitRequest(System.Net.HttpWebRequest, System.String)
        System.Net.HttpWebRequest.SubmitRequest(System.Net.ServicePoint)
        System.Net.HttpWebRequest.GetRequestStream(System.Net.TransportContext ByRef)
        System.Net.HttpWebRequest.GetRequestStream()
        Microsoft.WindowsAzure.Storage.Core.Executor.Executor.ExecuteSync[[System.__Canon, mscorlib]](Microsoft.WindowsAzure.Storage.Core.Executor.RESTCommand`1<System.__Canon>, Microsoft.WindowsAzure.Storage.RetryPolicies.IRetryPolicy, Microsoft.WindowsAzure.Storage.OperationContext)
        Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob.UploadFromStreamHelper(System.IO.Stream, System.Nullable`1<Int64>, Microsoft.WindowsAzure.Storage.AccessCondition, Microsoft.WindowsAzure.Storage.Blob.BlobRequestOptions, Microsoft.WindowsAzure.Storage.OperationContext)
        Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob.UploadFromByteArray(Byte[], Int32, Int32, Microsoft.WindowsAzure.Storage.AccessCondition, Microsoft.WindowsAzure.Storage.Blob.BlobRequestOptions, Microsoft.WindowsAzure.Storage.OperationContext)
        Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob.UploadText(System.String, System.Text.Encoding, Microsoft.WindowsAzure.Storage.AccessCondition, Microsoft.WindowsAzure.Storage.Blob.BlobRequestOptions, Microsoft.WindowsAzure.Storage.OperationContext)
        ... my own project's calls begin here ...

    DetailID = 8
    Count:    4
    Type:     System.Security.Authentication.AuthenticationException
    Message:  A call to SSPI failed, see inner exception.
        Type:     System.ComponentModel.Win32Exception
        Message:  The client and server cannot communicate, because they do not possess a common algorithm
    Stack:    
        [HelperMethodFrame]
        System.Net.TlsStream.ProcessAuthentication(System.Net.LazyAsyncResult)
        [HelperMethodFrame]
        System.Net.TlsStream.ProcessAuthentication(System.Net.LazyAsyncResult)
        [HelperMethodFrame]
        System.Net.Security.SslState.ForceAuthentication(Boolean, Byte[], System.Net.AsyncProtocolRequest)
        [HelperMethodFrame]
        System.Net.Security.SslState.StartSendAuthResetSignal(System.Net.Security.ProtocolToken, System.Net.AsyncProtocolRequest, System.Exception)
        System.Net.Security.SslState.StartSendBlob(Byte[], Int32, System.Net.AsyncProtocolRequest)
        System.Net.Security.SslState.ProcessReceivedBlob(Byte[], Int32, System.Net.AsyncProtocolRequest)
        System.Net.Security.SslState.StartReceiveBlob(Byte[], System.Net.AsyncProtocolRequest)
        System.Net.Security.SslState.StartSendBlob(Byte[], Int32, System.Net.AsyncProtocolRequest)
        System.Net.Security.SslState.ForceAuthentication(Boolean, Byte[], System.Net.AsyncProtocolRequest)
        System.Net.Security.SslState.ProcessAuthentication(System.Net.LazyAsyncResult)
        System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
        System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
        System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
        System.Net.TlsStream.ProcessAuthentication(System.Net.LazyAsyncResult)
        System.Net.TlsStream.Write(Byte[], Int32, Int32)
        System.Net.ConnectStream.WriteHeaders(Boolean)
        System.Net.HttpWebRequest.EndSubmitRequest()
        System.Net.Connection.CompleteConnection(Boolean, System.Net.HttpWebRequest)
        System.Net.Connection.CompleteStartConnection(Boolean, System.Net.HttpWebRequest)
        System.Net.Connection.CompleteStartRequest(Boolean, System.Net.HttpWebRequest, System.Net.TriState)
        System.Net.Connection.SubmitRequest(System.Net.HttpWebRequest, Boolean)
        System.Net.ServicePoint.SubmitRequest(System.Net.HttpWebRequest, System.String)
        System.Net.HttpWebRequest.SubmitRequest(System.Net.ServicePoint)
        System.Net.HttpWebRequest.GetRequestStream(System.Net.TransportContext ByRef)
        System.Net.HttpWebRequest.GetRequestStream()
        Microsoft.WindowsAzure.Storage.Core.Executor.Executor.ExecuteSync[[System.__Canon, mscorlib]](Microsoft.WindowsAzure.Storage.Core.Executor.RESTCommand`1<System.__Canon>, Microsoft.WindowsAzure.Storage.RetryPolicies.IRetryPolicy, Microsoft.WindowsAzure.Storage.OperationContext)
        Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob.UploadFromStreamHelper(System.IO.Stream, System.Nullable`1<Int64>, Microsoft.WindowsAzure.Storage.AccessCondition, Microsoft.WindowsAzure.Storage.Blob.BlobRequestOptions, Microsoft.WindowsAzure.Storage.OperationContext)
        Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob.UploadFromByteArray(Byte[], Int32, Int32, Microsoft.WindowsAzure.Storage.AccessCondition, Microsoft.WindowsAzure.Storage.Blob.BlobRequestOptions, Microsoft.WindowsAzure.Storage.OperationContext)
        Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob.UploadText(System.String, System.Text.Encoding, Microsoft.WindowsAzure.Storage.AccessCondition, Microsoft.WindowsAzure.Storage.Blob.BlobRequestOptions, Microsoft.WindowsAzure.Storage.OperationContext)
        ... my own project's calls begin here ...

Jan的答案从技术上讲最终给出了正确的解决方法,但它没有给出真正的原因,这是真正的问题所在(正如我在评论中所说,我已经设置了这个,只是偶然地将值设置得更高,到Tls12)。因此,虽然我总是更喜欢不覆盖别人的答案,但我认为这更受欢迎,对于那些与这个确切的问题斗争的人来说也更有帮助(事实上,当我看到他的答案时,它甚至没引起我的注意,因为它与我所做的事情没有什么不同)。但还是要感谢Jan的帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接