Azure w/TLS/SNI 上的 .net httpclient:请求被中止:无法创建 SSL/TLS 安全通道
Posted
技术标签:
【中文标题】Azure w/TLS/SNI 上的 .net httpclient:请求被中止:无法创建 SSL/TLS 安全通道【英文标题】:.net httpclient on Azure w/ TLS/SNI: The request was aborted: Could not create SSL/TLS secure channel 【发布时间】:2020-10-23 09:47:29 【问题描述】:之前曾多次提出类似问题 - 但在将此问题标记为重复之前,请继续阅读。这些问题中的大多数都是非常古老的。我已经解决了很多问题和答案,但没有找到合适的解决方案。
我们在 .net 4.5 中有一个 Azure 云服务项目。它可以毫无问题地连接到我们客户的数十个 API(不一定是云托管),但单个 API 失败并显示以下错误消息:
请求中止:无法创建 SSL/TLS 安全通道
我在这里错过了什么?
这是我用来连接到 API 的代码(略微精简)(每个 API 运行,因此基本 URL 不会改变):
ServicePointManager.ServerCertificateValidationCallback += ValidateRemoteCertificate;
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol =
SecurityProtocolType.Tls12 |
SecurityProtocolType.Tls11 |
SecurityProtocolType.Tls |
SecurityProtocolType.Ssl3;
ApiClient = HttpClientFactory.Create();
ApiClient.DefaultRequestHeaders.Authorization = null;
ApiClient.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", "Basic passwordToken");
ApiClient.DefaultRequestHeaders.Accept.Clear();
ApiClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
SemaphoreSlim throttler = new SemaphoreSlim(initialCount: 50);
var sp = ServicePointManager.FindServicePoint(new Uri(baseUrl));
sp.SetTcpKeepAlive(true, 30000, 30000);
foreach (var request in urls)
Result = new HttpResponseMessage();
Result = await ApiClient.GetAsync(url);
...
这就是难以调试的原因:
此问题仅发生在生产中,即作为 Azure 云服务运行时。在本地调试时不会。 它只发生在通过 HttpClient 发送的请求中。不使用 WebClient。 进一步研究(比较 API)发现 此 API 是唯一启用 SNI 且仅支持 TLS1.2 的 API。从其他关于 .net Framework 中 SNI 的问题/答案中考虑的建议:
为防止误解:这是关于连接到 API 的云服务,而不是关于正在建立到云服务的连接。 HttpClient 实例被重新用于对单个 API 的所有请求。 (这很重要,因为this answer 建议将使用已初始化的域 HttpClient 创建 SNI 标签)。 I have also tried configuring TLS after the Factory instantiated the HttpClient。没有变化。 证书当然是有效的。没有自签名证书,但有现成的常规受信任证书。在任何浏览器中打开 API 也很有效。 .net framework 4.5 中默认不启用 TLS1.2,但ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
行实际上应该启用它。我这样做有什么问题吗?
使用 curl --user 'user:pwd' https://myurl
在 curl(WSL 和 Azure 远程 bash)中调用 API 也可以正常工作并返回预期的数据。
使用像openssl s_client -connect hostname:443 -tls1_2
这样的openssl 测试tls1.2 不会发现任何问题。链显示正确,并确认了 TLSv1.2 会话。使用带有 openssl s_client -connect host:443 -tls1_2 -servername host -tlsextdebug -msg
的 openssl 测试服务器的 SNI 功能通过返回 TLS server extension "server name" (id=0), len=0
来显示 SNI 支持如果我提供完全不同的幻想主机名,我将获得相同的证书。
我在本地调试时捕获了 TLS/SNI 握手(请参见下面的屏幕截图)。没有问题。我的调试能力以云服务结束。我很想看到云服务和 WireShark 中的 API 之间的握手,但我不知道在 Azure 云服务上分析该层网络流量的任何选项。但如果有人知道如何捕捉握手过程,我会很感激一些提示。
服务器在与 openssl 握手期间选择 ECDHE-RSA-AES256-GCM-SHA384 作为密码套件,这对于 TLS1.2 来说几乎是默认设置。我无权访问它将在 Client Hello 中提供的密码套件的云服务列表 - 知道如何找到吗?
我没有任何证据表明 SNI 确实导致了问题,但这是此 API 与我能发现的许多其他 API 之间的唯一区别。
堆栈跟踪:
System.Net.Http.HttpRequestException:发送请求时出错。 ---> System.Net.WebException:请求被中止:无法创建 SSL/TLS 安全通道。在 System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult) 在 System.Net.Http.HttpClientHandler.GetResponseCallback(IAsyncResult ar) --- 内部异常堆栈跟踪结束 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() at WCFServiceWebRole1.Controllers... 在 [调用 GetAsync() 的行]
【问题讨论】:
由于 Microsoft 在禁用 TLS 1.0/1.1 的服务器上进行安全更新,今年 6 月一切都发生了变化。微软在进行网络更新时也会更改为最新的默认值,因此 SHA 的版本也会发生变化。 SHA 必须匹配证书。我会检查证书以查看 SHA 的版本。还要更改代码以仅使用 TLS 1.2/1.3:SecurityProtocolType.Tls12 | SecurityProtocolType.Tls13 感谢您强调这一点。我不能减少对 TLS 1.2 和 1.3 的支持,因为许多客户端还不支持这些。这些环境不在我的控制之下。 我认为您需要与您的客户讨论这个问题。一旦他们安装了 microsoft 安全更新,该应用程序可能会停止工作。检查以下 wiki 站点。使您的证书与您的客户正在使用的所有 TLS 版本兼容 (en.wikipedia.org/wiki/Transport_Layer_Security)。我怀疑所有人都在使用 TLS 1.2/1.3,因为微软安全更新禁用了其他版本的 TLS 将 TLS1.3 添加到您的选择列表中。this API is the only one
实际上,现在每个人都需要 TLS1.2。所有云提供商、主要服务、支付行业等。这意味着谷歌也需要 TLS1.2。
【参考方案1】:
我最终在我的一台服务器上重新创建了一个简单的 API,并以这样一种方式配置了软件,以便在那里发送它的请求。这样我就可以捕获 TLS 握手并在 Wireshark 中对其进行分析。这些是受支持的密码套件(客户端,即 Azure 云服务):
这些是 API 支持但不起作用的密码套件:
我认为应该有一个匹配项,以便服务器和客户端可以就一个匹配项达成一致。但是,我找不到匹配项......猜测这就是导致问题的原因。事实上,在本地调试会话中支持的密码套件列表要长得多 - 并且至少有一个匹配项可以解释它为什么在本地工作。
【讨论】:
您在代码中明确启用了 weaker TLS 版本。所有云供应商、主要服务、航空公司、支付处理器已经切换到至少 TLS1.2 4 年了。将您的 .NET 版本升级到自动使用 TLS1.2 的版本,问题就会消失。实际上,这是 4.7.2 或更高版本,以避免与 .NET Standard 包的兼容性问题以上是关于Azure w/TLS/SNI 上的 .net httpclient:请求被中止:无法创建 SSL/TLS 安全通道的主要内容,如果未能解决你的问题,请参考以下文章
.net 核心 3.0 上的 Azure Functions
Azure 上的 .NET Core 无法连接到 SQL Server 数据库
为啥 Azure Web 角色上的 IIS 需要如此频繁地重新编译 ASP.NET 应用程序?
Windows Azure 上的 ASP.NET 应用程序性能问题
SqlException (0x80131904):在 Azure 上托管的 .NET 6 WebAPI 上的用户“dbuser”登录失败