How do I disable SSL fallback and use only TLS for outbound connections in .NET? (Poodle mitigation)
我正在尝试减轻Poodle SSL3.0回退攻击的脆弱性。我们的管理员已经开始禁用ssl,而对我们的服务器的入站连接使用tls。我们还建议我们的团队在他们的Web浏览器中禁用SSL。我现在看看我们的.NET代码库,它通过system.net.httpwebrequest启动与各种服务的HTTPS连接。我相信,如果这些连接允许从TLS回退到SSL,那么它们可能容易受到MITM攻击。这是我到目前为止所决定的。有人能再检查一下这个吗?这个漏洞是全新的,所以我还没有看到微软关于如何在.NET中减轻它的任何指导:
支持.NET中安全通信的System.NET.Security.SSLStream类的允许协议通过System.NET.ServicePointManager.SecurityProtocol属性为每个AppDomain全局设置。
.NET 4.5中此属性的默认值是
console.writeline(system.net.servicePointManager.securityProtocol.toString());
在您启动应用程序中的任何连接之前,应该将其更改为仅
system.net.servicePointManager.securityProtocol=system.net.securityProtocolType.tls;
重要提示:由于该属性支持多个位标志,我假设sslstream在握手期间不会自动回退到其他未指定的协议。否则,支持多个标志的意义是什么?
TLS 1.0与1.1/1.2的更新:
据谷歌安全专家亚当·兰利(AdamLangley)称,如果没有正确实施,tls 1.0很容易受到poodle的攻击,因此您应该考虑只使用tls1.2。
我们也在做同样的事情。要仅支持TLS 1.2且不支持SSL协议,可以执行以下操作:
1 | System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; |
securityProtocolType.tls只是tls 1.0,不是所有的tls版本。
另一方面:如果您要检查您的站点是否不允许SSL连接,可以在此处执行此操作(我认为这不会受到上述设置的影响,我们必须编辑注册表以强制IIS对传入连接使用TLS):网址:https://www.ssllabs.com/ssltest/index.html
要在IIS中禁用SSL 2.0和3.0,请参阅本页:https://www.sslshopper.com/article-how-to-disable-ssl-2.0-in-IIS-7.html
@埃迪·洛芬的回答似乎是这个问题最受欢迎的答案,但它有一些不好的长期影响。如果您在此处查看System.net.ServicePointManager.SecurityProtocol的文档页面,备注部分暗示协商阶段应该解决这一问题(强制使用协议是一种糟糕的做法,因为在将来,TLS 1.2也会受到影响)。然而,如果这个答案是真的,我们就不会去寻找它了。
研究表明,ALPN协商协议在协商阶段需要到达TLS1.2。我们以这一点为出发点,尝试了.NET框架的新版本,以了解从何处开始支持。我们发现.NET 4.5.2不支持与TLS 1.2的协商,但.NET 4.6支持协商。
因此,即使强制TLS1.2现在就能完成任务,我还是建议您升级到.NET 4.6。由于这是2016年6月的PCI DSS问题,窗口很短,但新框架是更好的答案。
更新:根据评论,我构建了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | ServicePointManager.SecurityProtocol = 0; foreach (SecurityProtocolType protocol in SecurityProtocolType.GetValues(typeof(SecurityProtocolType))) { switch (protocol) { case SecurityProtocolType.Ssl3: case SecurityProtocolType.Tls: case SecurityProtocolType.Tls11: break; default: ServicePointManager.SecurityProtocol |= protocol; break; } } |
为了验证这一概念,我将ssl3和tls1.2结合在一起,以仅支持tls 1.0和tls 1.2(禁用1.1)的服务器为目标运行代码。使用OR'D协议,它看起来连接良好。如果我更改为ssl3和tls 1.1,则连接失败。我的验证使用System.NET的httpWebRequest,只调用getResponse()。例如,我尝试了这个方法,但失败了:
1 2 3 | HttpWebRequest request = WebRequest.Create("https://www.contoso.com/my/web/resource") as HttpWebRequest; ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls11; request.GetResponse(); |
当这项工作开始时:
1 2 3 | HttpWebRequest request = WebRequest.Create("https://www.contoso.com/my/web/resource") as HttpWebRequest; ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12; request.GetResponse(); |
这比强制TLS 1.2有一个优势,因为如果.NET框架升级到枚举中有更多条目,那么代码将支持这些条目。它比仅使用.NET 4.6有一个缺点,因为4.6使用ALPN,如果没有指定限制,它应该支持新的协议。
编辑4/29/2019-微软去年10月发表了这篇文章。它有一个非常好的概要,介绍了如何在各种版本的.NET框架中实现这一点。
沃森
在Windows窗体上,它是可用的,在类的顶部
1 2 3 4 5 | static void Main(string[] args) { ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; //other stuff here } |
因为Windows是单线程的,所以它是您所需要的,如果它是一个服务,您需要将它放在对服务调用的正上方(因为不知道您将使用哪个线程)。
1 | using System.Security.Principal |
也是需要的。
我必须对等价整数进行强制转换,以绕过我仍在使用.NET 4.0这一事实。
1 2 3 4 5 6 7 8 9 10 11 | System.Net.ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072; /* Note the property type [System.Flags] public enum SecurityProtocolType { Ssl3 = 48, Tls = 192, Tls11 = 768, Tls12 = 3072, } */ |
如果您想知道.NET支持哪些协议,可以在https://www.howsmysl.com上试用httpclient。/
1 2 3 4 5 6 7 | // set proxy if you need to // WebRequest.DefaultWebProxy = new WebProxy("http://localhost:3128"); File.WriteAllText("howsmyssl-httpclient.html", new HttpClient().GetStringAsync("https://www.howsmyssl.com").Result); // alternative using WebClient for older framework versions // new WebClient().DownloadFile("https://www.howsmyssl.com/","howsmyssl-webclient.html"); |
结果糟透了:
Your client is using TLS 1.0, which is very old, possibly susceptible to the BEAST attack, and doesn't have the best cipher suites available on it. Additions like AES-GCM, and SHA256 to replace MD5-SHA-1 are unavailable to a TLS 1.0 client as well as many more modern cipher suites.
正如Eddie上面解释的,您可以手动启用更好的协议:
1 | System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11; |
我不知道为什么它使用坏的协议。这似乎是一个糟糕的设置选择,相当于一个主要的安全漏洞(我打赌很多应用程序不会改变默认设置)。我们如何报告?
我发现最简单的解决方案是添加两个注册表项,如下所示(在具有管理员权限的命令提示符中运行此项):
1 2 3 | reg add HKLM\SOFTWARE\Microsoft\.NETFramework\v4.0.30319 /v SchUseStrongCrypto /t REG_DWORD /d 1 /reg:32 reg add HKLM\SOFTWARE\Microsoft\.NETFramework\v4.0.30319 /v SchUseStrongCrypto /t REG_DWORD /d 1 /reg:64 |
这些条目似乎会影响.NET CLR在作为客户端进行安全连接时如何选择协议。
有关此注册表项的详细信息,请参阅:
https://docs.microsoft.com/en-us/security-updates/securityadvisories/2015/2960358建议的操作
这不仅简单,而且假设它适用于您的情况,远比基于代码的解决方案更健壮,后者要求开发人员跟踪协议和开发并更新所有相关代码。希望,只要.NET足够哑,不自动选择可用的最高协议,就可以对TLS 1.3及更高版本进行类似的环境更改。
注意:尽管根据上面的文章,这只是应该禁用RC4,但是人们不会认为这会改变.NET客户端是否允许使用TLS1.2+,因为某种原因它确实具有这种效果。
注意:正如@jordan rieger在评论中指出的,这不是poodle的解决方案,因为它不禁用旧的协议A——它只允许客户端使用新的协议,例如,当一个补丁服务器禁用了旧的协议时。然而,对于一个MITM攻击,显然一个受损的服务器将为客户机提供一个旧的协议,然后客户机将愉快地使用该协议。
TODO:尝试对这些注册表项禁用客户端使用tls1.0和tls1.1,但是我不知道.NET HTTP客户端库是否遵守这些设置:
https://docs.microsoft.com/en-us/windows-server/security/tls/tls注册表设置tls-10
https://docs.microsoft.com/en-us/windows-server/security/tls/tls注册表设置tls-11