禁用 SSL 回退并仅将 TLS 用于 .NET 中的出站连接?(贵宾犬缓解)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26389899/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 12:50:06  来源:igfitidea点击:

Disable SSL fallback and use only TLS for outbound connections in .NET? (Poodle mitigation)

.netssl

提问by Jordan Rieger

I am trying to mitigate our vulnerability to the Poodle SSL 3.0 Fallbackattack. Our admins have already started disabling SSL in favor of TLS for inbound connections to our servers. And we have also advised our team to disable SSL in their web browsers. I'm now looking at our .NET codebase, which initiates HTTPS connections with various services through System.Net.HttpWebRequest. I believe that these connections could be vulnerable to a MITM attack if they allow fallback from TLS to SSL. Here is what I have determined so far. Could some one please double-check this to verify that I am right? This vulnerability is brand new, so I have yet to see any guidance from Microsoft on how to mitigate it in .NET:

我正在尝试减轻我们对Poodle SSL 3.0 Fallback攻击的脆弱性。我们的管理员已经开始禁用 SSL,转而使用 TLS 来连接到我们的服务器。我们还建议我们的团队在他们的网络浏览器中禁用 SSL。我现在正在查看我们的 .NET 代码库,它通过System.Net.HttpWebRequest启动与各种服务的 HTTPS 连接。我相信如果这些连接允许从 TLS 回退到 SSL,它们可能容易受到 MITM 攻击。这是我迄今为止所确定的。有人可以仔细检查一下以确认我是对的吗?这个漏洞是全新的,所以我还没有看到微软关于如何在 .NET 中缓解它的任何指导:

  1. The allowed protocols for the System.Net.Security.SslStream class, which underpins secure communication in .NET, are set globally for each AppDomain via the System.Net.ServicePointManager.SecurityProtocolproperty.

  2. The default value of this property in .NET 4.5 is Ssl3 | Tls(although I can't find documentation to back that up.) SecurityProtocolType is an enum with the Flags attribute, so it's a bitwise ORof those two values. You can check this in your environment with this line of code:

    Console.WriteLine(System.Net.ServicePointManager.SecurityProtocol.ToString());

  3. This should be changed to just Tls, or perhaps Tls12, before you initiate any connections in your app:

    System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls;

  4. Important:Since the property supports multiple bitwise flags, I assume that the SslStream will notautomatically fallback to other unspecified protocols during handshake. Otherwise, what would be the point of supporting multiple flags?

  1. System.Net.Security.SslStream 类允许的协议(支持 .NET 中的安全通信)通过System.Net.ServicePointManager.SecurityProtocol属性为每个 AppDomain 全局设置。

  2. 这个属性在 .NET 4.5 中的默认值是Ssl3 | Tls(虽然我找不到支持它的文档。)SecurityProtocolType 是一个带有 Flags 属性的枚举,所以它是这两个值的按位。您可以使用以下代码行在您的环境中检查这一点:

    Console.WriteLine(System.Net.ServicePointManager.SecurityProtocol.ToString());

  3. 在您在应用程序中启动任何连接之前Tls,这应该更改为 just ,或者可能是Tls12

    System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls;

  4. 重要提示:由于该属性支持多个按位标志,我假设 SslStream在握手期间不会自动回退到其他未指定的协议。否则,支持多个标志有什么意义?

Update on TLS 1.0 vs 1.1/1.2:

TLS 1.0 与 1.1/1.2 的更新:

According to Google security expert Adam Langley, TLS 1.0 was later found to be vulnerable to POODLE if not implemented correctly, so you should consider moving to TLS 1.2 exclusively.

根据 Google 安全专家 Adam Langley 的说法,后来发现 TLS 1.0 如果没有正确实施就容易受到 POODLE 的攻击,因此您应该考虑专门迁移到 TLS 1.2。

Update for .NET Framework 4.7 and above:

.NET Framework 4.7 及更高版本的更新:

As alluded to by Prof Von Lemongarglebelow, starting with version 4.7 of the .NET Framework, there is no need to use this hack as the default setting will allow the OS to choose the most secure TLS protocol version. See Transport Layer Security (TLS) best practices with the .NET Frameworkfor more information.

正如下面Von Lemongargle 教授所暗示的那样,从 .NET Framework 4.7 版开始,无需使用此 hack,因为默认设置将允许操作系统选择最安全的 TLS 协议版本。有关详细信息,请参阅.NET Framework 的传输层安全性 (TLS) 最佳实践

回答by Eddie Fletcher

We are doing the same thing. To support only TLS 1.2 and no SSL protocols, you can do this:

我们正在做同样的事情。要仅支持 TLS 1.2 而没有 SSL 协议,您可以执行以下操作:

System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

SecurityProtocolType.Tls is only TLS 1.0, not all TLS versions.

SecurityProtocolType.Tls 只是 TLS 1.0,并非所有 TLS 版本。

As a side: If you want to check that your site does not allow SSL connections, you can do so here (I don't think this will be affected by the above setting, we had to edit the registry to force IIS to use TLS for incoming connections): https://www.ssllabs.com/ssltest/index.html

一方面:如果您想检查您的站点是否不允许 SSL 连接,您可以在此处进行(我认为这不会受到上述设置的影响,我们必须编辑注册表以强制 IIS 使用 TLS对于传入连接):https: //www.ssllabs.com/ssltest/index.html

To disable SSL 2.0 and 3.0 in IIS, see this page: https://www.sslshopper.com/article-how-to-disable-ssl-2.0-in-iis-7.html

要在 IIS 中禁用 SSL 2.0 和 3.0,请参阅此页面:https: //www.sslshopper.com/article-how-to-disable-ssl-2.0-in-iis-7.html

回答by Prof Von Lemongargle

@Eddie Loeffen's answer seems to be the most popular answer to this question, but it has some bad long term effects. If you review the documentation page for System.Net.ServicePointManager.SecurityProtocol herethe remarks section implies that the negotiation phase should just address this (and forcing the protocol is bad practice because in the future, TLS 1.2 will be compromised as well). However, we wouldn't be looking for this answer if it did.

@Eddie Loeffen 的答案似乎是这个问题最受欢迎的答案,但它有一些不好的长期影响。如果您在此处查看 System.Net.ServicePointManager.SecurityProtocol 的文档页面,备注部分暗示协商阶段应该解决这个问题(并且强制协议是不好的做法,因为将来 TLS 1.2 也会受到损害)。但是,如果确实如此,我们就不会寻找这个答案。

Researching, it appears that the ALPN negotiation protocol is required to get to TLS1.2 in the negotiation phase. We took that as our starting point and tried newer versions of the .Net framework to see where support starts. We found that .Net 4.5.2 does not support negotiation to TLS 1.2, but .Net 4.6 does.

经研究,似乎需要ALPN协商协议在协商阶段达到TLS1.2。我们以此为出发点,并尝试了更新版本的 .Net 框架以查看支持的起点。我们发现 .Net 4.5.2 不支持与 TLS 1.2 的协商,但 .Net 4.6 支持。

So, even though forcing TLS1.2 will get the job done now, I recommend that you upgrade to .Net 4.6 instead. Since this is a PCI DSS issue for June 2016, the window is short, but the new framework is a better answer.

因此,即使强制使用 TLS1.2 现在可以完成工作,我还是建议您升级到 .Net 4.6。由于这是 2016 年 6 月的 PCI DSS 问题,窗口很短,但新框架是更好的答案。

UPDATE: Working from the comments, I built this:

更新:根据评论,我构建了这个:

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;
        }
    }

In order to validate the concept, I or'd together SSL3 and TLS1.2 and ran the code targeting a server that supports only TLS 1.0 and TLS 1.2 (1.1 is disabled). With the or'd protocols, it seems to connect fine. If I change to SSL3 and TLS 1.1, that failed to connect. My validation uses HttpWebRequest from System.Net and just calls GetResponse(). For instance, I tried this and failed:

为了验证这个概念,我将 SSL3 和 TLS1.2 放在一起,并运行了针对仅支持 TLS 1.0 和 TLS 1.2(1.1 已禁用)的服务器的代码。使用 or'd 协议,它似乎连接良好。如果我更改为 SSL3 和 TLS 1.1,则无法连接。我的验证使用来自 System.Net 的 HttpWebRequest 并且只调用 GetResponse()。例如,我尝试了这个并失败了:

        HttpWebRequest request = WebRequest.Create("https://www.contoso.com/my/web/resource") as HttpWebRequest;
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls11;
        request.GetResponse();

while this worked:

虽然这有效:

        HttpWebRequest request = WebRequest.Create("https://www.contoso.com/my/web/resource") as HttpWebRequest;
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12;
        request.GetResponse();

This has an advantage over forcing TLS 1.2 in that, if the .Net framework is upgraded so that there are more entries in the Enum, they will be supported by the code as is. It has a disadvantage over just using .Net 4.6 in that 4.6 uses ALPN and should support new protocols if no restriction is specified.

与强制使用 TLS 1.2 相比,这有一个优势,因为如果 .Net 框架升级以便在 Enum 中有更多条目,则代码将按原样支持它们。与仅使用 .Net 4.6 相比,它有一个缺点,因为 4.6 使用 ALPN,如果没有指定限制,它应该支持新协议。

Edit 4/29/2019 - Microsoft published this articlelast October. It has a pretty good synopsis of their recommendation of how this should be done in the various versions of .net framework.

编辑 2019 年 4月29 日 - 微软去年 10 月发表了这篇文章。他们对如何在各种版本的 .net 框架中完成的建议有一个很好的概要。

回答by Colonel Panic

If you're curious which protocols .NET supports, you can try HttpClient out on https://www.howsmyssl.com/

如果您对 .NET 支持哪些协议感到好奇,您可以在https://www.howsmyssl.com/上试用 HttpClient

// 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");

The result is damning:

结果惨不忍睹:

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.

您的客户端使用的是 TLS 1.0,它非常旧,可能容易受到 BEAST 攻击,并且没有最好的密码套件可用。诸如 AES-GCM 和 SHA256 之类的用于替换 MD5-SHA-1 的附加功能对 TLS 1.0 客户端以及许多更现代的密码套件不可用。

As Eddie explains above, you can enable better protocols manually:

正如 Eddie 上面解释的那样,您可以手动启用更好的协议:

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

I don't know why it uses bad protocols out-the-box. That seems a poor setup choice, tantamount to a major security bug (I bet plenty of applications don't change the default). How can we report it?

我不知道为什么它开箱即用地使用糟糕的协议。这似乎是一个糟糕的设置选择,相当于一个主要的安全漏洞(我敢打赌,很多应用程序都不会更改默认设置)。我们如何举报?

回答by CZahrobsky

I had to cast the integer equivalent to get around the fact that I'm still using .NET 4.0

我不得不转换等效的整数来绕过我仍在使用 .NET 4.0 的事实

System.Net.ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;
/* Note the property type  
   [System.Flags]
   public enum SecurityProtocolType
   {
     Ssl3 = 48,
     Tls = 192,
     Tls11 = 768,
     Tls12 = 3072,
   } 
*/

回答by DirtyHowi

@watson

@沃森

On windows forms it is available, at the top of the class put

在 windows 窗体上它是可用的,在类的顶部放置

  static void Main(string[] args)
    {
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
       //other stuff here
    }

since windows is single threaded, its all you need, in the event its a service you need to put it right above the call to the service (since there is no telling what thread you'll be on).

由于 Windows 是单线程的,因此您只需要它,如果它是一项服务,您需要将它放在对服务的调用之上(因为不知道您将在哪个线程上)。

using System.Security.Principal 

is also needed.

也是需要的。

回答by Raman

I found the simplest solution is to add two registry entries as follows (run this in a command prompt with admin privileges):

我发现最简单的解决方案是添加两个注册表项,如下所示(在具有管理员权限的命令提示符中运行):

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

These entries seem to affect how the .NET CLR chooses a protocol when making a secure connection as a client.

这些条目似乎会影响 .NET CLR 在作为客户端进行安全连接时选择协议的方式。

There is more information about this registry entry here:

此处提供了有关此注册表项的更多信息:

https://docs.microsoft.com/en-us/security-updates/SecurityAdvisories/2015/2960358#suggested-actions

https://docs.microsoft.com/en-us/security-updates/SecurityAdvisories/2015/2960358#suggested-actions

Not only is this simpler, but assuming it works for your case, far more robust than a code-based solution, which requires developers to track protocol and development and update all their relevant code. Hopefully, similar environment changes can be made for TLS 1.3 and beyond, as long as .NET remains dumb enough to not automatically choose the highest available protocol.

这不仅更简单,而且假设它适用于您的情况,比基于代码的解决方案健壮得多,后者需要开发人员跟踪协议和开发并更新所有相关代码。希望 TLS 1.3 及更高版本可以进行类似的环境更改,只要 .NET 保持足够愚蠢,不会自动选择最高的可用协议。

NOTE: Even though, according to the article above, this is only supposed to disable RC4, and one would not think this would change whether the .NET client is allowed to use TLS1.2+ or not, for some reason it does have this effect.

注意:尽管根据上面的文章,这只是应该禁用 RC4,并且人们不会认为这会改变 .NET 客户端是否被允许使用 TLS1.2+,出于某种原因它确实有这个影响。

NOTE: As noted by @Jordan Rieger in the comments, this is not a solution for POODLE, since it does not disablethe older protocols a -- it merely allows the client to work with newer protocols e.g. when a patched server has disabled the older protocols. However, with a MITM attack, obviously a compromised server will offer the client an older protocol, which the client will then happily use.

注意:正如@Jordan Rieger 在评论中所指出的,这不是 POODLE 的解决方案,因为它不会禁用旧协议 a - 它仅允许客户端使用新协议,例如当打补丁的服务器禁用了旧协议时协议。但是,对于 MITM 攻击,显然受感染的服务器将为客户端提供旧协议,然后客户端会很乐意使用该协议。

TODO: Try to disable client-side use of TLS1.0 and TLS1.1 with these registry entries, however I don't know if the .NET http client libraries respect these settings or not:

TODO:尝试通过这些注册表项禁用客户端使用 TLS1.0 和 TLS1.1,但是我不知道 .NET http 客户端库是否尊重这些设置:

https://docs.microsoft.com/en-us/windows-server/security/tls/tls-registry-settings#tls-10

https://docs.microsoft.com/en-us/windows-server/security/tls/tls-registry-settings#tls-10

https://docs.microsoft.com/en-us/windows-server/security/tls/tls-registry-settings#tls-11

https://docs.microsoft.com/en-us/windows-server/security/tls/tls-registry-settings#tls-11