我正在尝试编写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来调查错误。
在玩这些之后我发现了以下内容:
该代码如下所示:
...
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
这实际上运作得很好,可能是后退解决方案。但我也了解到有问题的服务提供商有一个使用TLS 1.2保护的不同端点(相同的URL,不同的端口)。值得庆幸的是,通过在global.asax.cs应用程序启动事件中扩展我的SecurityProtocol设置:
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
我能够在所有环境中与服务进行良好沟通。它也不会影响我与其他服务的现有集成(例如,CyberSource)。
然而 - 现在有一个新的但相关的问题。 为什么如果我如上所述展开SecurityProtocolType,这个调用是否有效?我的其他集成,如CyberSource,并不需要这样。但是这个确实如此。并且它们似乎都是使用我在浏览器中看到的TLS 1.2保护的。
答案 0 :(得分:1)
如果你运行4.0,你可以像这样使用它:
ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072; // SecurityProtocolType.Tls12
答案 1 :(得分:1)
这个对我有用:
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
| SecurityProtocolType.Tls11
| SecurityProtocolType.Tls12
| SecurityProtocolType.Ssl3;
答案 2 :(得分:0)
隐藏了Web服务器上的某些高级TLS配置。您的生产服务器可能已被修改,以防止DROWN,logjam,FREAK,POODLE和BEAST攻击。
见
要更改这些高级TLS设置,它不像单击IIS中的某些按钮那么简单。如果你使用像这样的第三方工具,那就简单了:https://www.nartac.com/Products/IISCrypto
这些配置适用于主要的最新Web浏览器,但.Net似乎很难使用这种现代安全服务器配置(除非您手动覆盖默认设置)。
结论:这并不明显,你的UAT和制作环境看起来是一样的,但它们不是。