繁体   English   中英

带有 TLS/SNI 的 Azure 上的 .net httpclient:请求被中止:无法创建 SSL/TLS 安全通道

[英].net httpclient on Azure w/ TLS/SNI: The request was aborted: Could not create SSL/TLS secure channel

类似的问题之前已被问过多次 - 但在将此问题标记为重复之前,请继续阅读。 这些问题中的大多数都是非常古老的。 我已经解决了很多问题和答案,但没有找到合适的解决方案。

我们在 .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 的所有请求。 (这很重要,因为此答案表明 SNI 标记将使用已初始化的域 HttpClient 创建)。 在工厂实例化 HttpClient 之后,我也尝试过配置 TLS 没变。
  • 证书当然是有效的。 没有自签名证书,而是现成的常规可信证书。 在任何浏览器中打开 API 也很有魅力。
  • TLS1.2 在 .net framework 4.5 中默认不启用,但ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12行实际上应该启用它。 我这样做的方式有什么问题吗?
  • 使用curl --user 'user:pwd' https://myurl在 curl(WSL 和 Azure 远程 bash)中调用 API 也可以完美运行并返回预期数据。
  • 使用 openssl 测试 tls1.2 就像openssl s_client -connect hostname:443 -tls1_2没有发现任何问题。 链显示正确,并确认了 TLSv1.2 会话。 使用 openssl 和openssl s_client -connect host:443 -tls1_2 -servername host -tlsextdebug -msg测试服务器的 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 之间的唯一区别。

在 WireShark 中本地捕获的 TLS/SNI 握手

堆栈跟踪:

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)任务) 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 在 System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() 在 WCFServiceWebRole1.Controllers... 在 [调用 GetAsync() 的行]

我最终在我的一台服务器上重新创建了一个简单的 API,并以这样一种方式配置了软件,以便在那里发送它的请求。 这样我就可以捕获 TLS 握手并在 Wireshark 中对其进行分析。 这些是受支持的密码套件(客户端,即 Azure 云服务):

Azure 云服务上支持的密码套件

这些是 API 支持的密码套件不起作用:

API 服务器上支持的密码套件

我认为应该有一个匹配,以便服务器和客户端可以就一个达成一致。 但是,我找不到匹配项...猜测这就是导致问题的原因。 事实上,本地调试会话中支持的密码套件列表要长得多 - 至少有一个匹配项可以解释为什么它可以在本地工作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM