【问题标题】:WebRequest Error - Could not create SSL/TLS secure channelWebRequest 错误 - 无法创建 SSL/TLS 安全通道
【发布时间】:2017-05-25 10:19:42
【问题描述】:

我正在尝试编写 C# 代码,该代码针对用于在 Web 应用程序中计算销售税的 REST 服务端点发出 Web 请求。这是第三方服务,它使用 SSL 进行保护。有两种环境,UAT 和生产环境。运行 webrequest 的代码如下所示:

...

var req = WebRequest.Create(url) as HttpWebRequest;
req.Method = "POST";
req.ContentType = "application/json";

...

using (var webresponse = req.GetResponse())
{
    using (var responseStream = new StreamReader(webresponse.GetResponseStream()))
    {
        var respJson = responseStream.ReadToEnd();
        calcResult = BuildResponse(calcRequest, respJson, consoleWriteRawReqResponse);
    }
}

return calcResult;

这适用于 UAT 环境。但是当我在生产环境中运行相同的代码时,我得到了错误:

“无法创建 SSL/TLS 安全通道”

能够毫无问题地执行来自 Postman 的两个请求,无需任何特殊修改。

这使我找到了调查此错误的路径,并且我发现了许多有用的 SO 帖子讨论该主题,包括:

The request was aborted: Could not create SSL/TLS secure channel

Could not create SSL/TLS secure channel, despite setting ServerCertificateValidationCallback

这些帮助我指出了正确的方向,即查看将 ServicePointManager.SecurityProtocol 设置设置为不同的值,并使用 ServicePointManager.ServerCertificateValidationCallback 调查错误。

我玩了这些之后发现如下:

  • UAT 环境调用将使用默认设置Ssl3 | Tls(.NET 4.5.2 的默认设置),而生产环境不会。
  • 只有当我将此设置明确设置为 Ssl3 时,生产调用才会起作用。

该代码如下所示:

...

var req = WebRequest.Create(url) as HttpWebRequest;
req.Method = "POST";
req.ContentType = "application/json";

...

ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CertValidationCallback);
using (var webresponse = req.GetResponse())
{
    using (var responseStream = new StreamReader(webresponse.GetResponseStream()))
    {
        var respJson = responseStream.ReadToEnd();
        calcResult = BuildResponse(calcRequest, respJson, consoleWriteRawReqResponse);
    }
}
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls;

return calcResult;

这特别令人困惑,因为在 Web 浏览器中查看端点时,我可以看到它们都由相同的通配符证书保护并且都使用 TLS 1.0。

所以我希望将 ServicePointManager.SecurityProtocol 设置为 TLS 会起作用,但它不会。

我真的想避免将 ServicePointManager.SecurityProtocol 显式设置为 SSL3,因为我们的应用程序是一个 Web 应用程序,并且有多个通过 SSL 进行通信的其他集成点。这些都工作正常,我不想对它们的功能产生不利影响。即使我在调用之前设置了此设置,然后在之后立即将其更改回来,我也会冒着遇到并发问题的风险,因为 ServicePointManager.SecurityProtocol 是静态的。

我也调查了那个话题,但不喜欢我读到的内容。有人提到使用不同的应用程序域:

.NET https requests with different security protocols across threads

How to use SSL3 instead of TLS in a particular HttpWebRequest?

但这对我来说似乎过于复杂/老套。处理创建应用程序域真的是唯一的解决方案吗?或者这是我根本不应该尝试解决的问题,而是与相关服务的所有者一起解决?我很好奇它可以在一个环境/服务器上使用 TLS,但不能在另一个环境/服务器上使用。

编辑 我做了一些更多的玩这个。我更改了我的客户端以使用这篇博文中很好地概述的方法(使用不同的应用程序域来隔离更改 ServicePointManager.SecurityProtocol 的代码):

https://bitlush.com/blog/executing-code-in-a-separate-application-domain-using-c-sharp

这实际上效果很好,可以作为备用解决方案。但我还了解到,相关服务的提供者有一个不同的端点(相同的 URL,不同的端口),它使用 TLS 1.2 进行保护。幸运的是,通过在 global.asax.cs 应用程序启动事件中扩展我的 SecurityProtocol 设置:

ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;

我能够在所有环境中与服务正常通信。它也不会影响我与其他服务(例如 Cyber​​Source)的现有集成。

但是 - 现在有一个新的但相关的问题。 为什么这个调用只有在我像上面那样扩展 SecurityProtocolType 时才有效?我的其他集成,比如 Cyber​​Source,不需要这个。然而这个确实如此。从我在浏览器中看到的内容来看,它们似乎都使用 TLS 1.2 进行了保护。

【问题讨论】:

    标签: c# ssl https


    【解决方案1】:

    网络服务器上的一些高级 TLS 配置是隐藏的。您的生产服务器可能已被修改以防止 DROWN、logjam、FREAK、POODLE 和 BEAST 攻击。

    要更改这些高级 TLS 设置,并不像单击 IIS 中的某些按钮那么简单。好吧,如果您使用这样的第三方工具,它可能就这么简单:https://www.nartac.com/Products/IISCrypto

    这些配置适用于最近的主要网络浏览器,但 .Net 似乎难以应对这种现代安全服务器配置(除非您手动覆盖您发现的默认设置)。

    结论:这并不明显,您的 UAT 和生产环境看起来是一样的,但实际上并非如此。

    【讨论】:

    • 联系您的最佳方式是什么?迫不及待地等待您的答复。谢谢
    【解决方案2】:

    如果你运行 4.0,你可以像这样使用它:

    ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072; // SecurityProtocolType.Tls12
    

    【讨论】:

      【解决方案3】:

      这个对我有用:

      ServicePointManager.Expect100Continue = true;
      ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
                         | SecurityProtocolType.Tls11
                         | SecurityProtocolType.Tls12
                         | SecurityProtocolType.Ssl3;
      

      【讨论】:

        猜你喜欢
        • 2018-04-06
        • 2018-08-12
        • 1970-01-01
        • 1970-01-01
        • 2020-12-15
        • 2019-06-17
        • 1970-01-01
        • 2021-12-13
        • 2014-12-26
        相关资源
        最近更新 更多