禁用 SSL 回退,对.NET 中的出站连接仅使用 TLS (Poodle 缓解)

我正试图减轻我们对 Poodle SSL 3.0后备攻击的脆弱性。我们的管理员已经开始禁用 SSL,以支持 TLS 连接到我们的服务器。我们也建议我们的团队在他们的浏览器中禁用 SSL。我现在看着我们的。NET 代码库,它通过 系统启动与各种服务的 HTTPS 连接。我相信,如果这些连接允许从 TLS 回退到 SSL,那么它们很容易受到 MITM 攻击。以下是我目前为止所确定的。有没有人能再核对一下,证明我是对的?这个漏洞是全新的,所以我还没有看到任何来自微软关于如何减轻它的指导。网址:

  1. 系统允许的协议。网。保安。中的安全通信的 SslStream 类。NET,通过 安全协议属性对每个 AppDomain 进行全局设置。

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

    控制台.WriteLine (System.Net.ServicePointManager.SecurityProtocol.ToString ()) ;

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

    SecurityProtocol = System.Net.SecurityProtocolType.Tls;

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

TLS 1.0 vs 1.1/1.2更新:

根据谷歌安全专家 Adam Langley,后来发现 TLS 1.0如果没有正确实现,就容易受到 POODLE 的攻击,所以你应该考虑转移到 TLS 1.2独家。

更新.NET Framework 4.7及以上版本:

正如下面的 Von Lemongargle 教授所暗示的,从4.7版本开始。NET 框架,没有必要使用这种黑客作为默认设置将允许操作系统选择最安全的 TLS 协议版本。有关更多信息,请参见 使用.NETFramework 的传输层安全性(TLS)最佳实践

135574 次浏览

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

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

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

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

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

@watson

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

  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).

using System.Security.Principal

is also needed.

@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 here the 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.

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.

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.

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:

        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.

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

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

// 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.

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

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?

I had to cast the integer equivalent to get around the fact that I'm still using .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,
}
*/

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.

There is more information about this registry entry here:

https://learn.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.

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.

NOTE: As noted by @Jordan Rieger in the comments, this is not a solution for POODLE, since it does not disable the 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.

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:

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

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