ChatGPT解决这个技术问题 Extra ChatGPT

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

I am trying to mitigate our vulnerability to the Poodle SSL 3.0 Fallback attack. 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:

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.SecurityProtocol property. 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 OR of those two values. You can check this in your environment with this line of code: Console.WriteLine(System.Net.ServicePointManager.SecurityProtocol.ToString()); 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; Important: Since the property supports multiple bitwise flags, I assume that the SslStream will not automatically fallback to other unspecified protocols during handshake. Otherwise, what would be the point of supporting multiple flags?

Update on TLS 1.0 vs 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.

Update for .NET Framework 4.7 and above:

As alluded to by Prof Von Lemongargle below, 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 Framework for more information.

Regarding point 2 above: see referencesource.microsoft.com/#System/net/System/Net/… SslProtocols " Default = Ssl3 | Tls"
@Dai Bok The default now is SystemDefault option docs.microsoft.com/en-us/dotnet/api/…
@MarwaAhmad if that is the case, the source code reference in my link does not reflect default (48 | 192) . If set to none ( 0 ) , it should revert to the system default. This smells to me and I'd probably test this before making changes as it may lead to missconfiguration...and turning off protocols on the wrong .net framework...

B
Brad C

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


Right. Good idea to support the newer TLS versions too: future-proofing.
And for the benefit of others, the registry edit you mentioned can also be done with these steps: serverfault.com/a/637263/98656. In Windows Server 2003 to 2012 R2 the protocols are controlled by flags at HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\Schannel\Protocols. To disable SSLv3, create a subkey at the above location named 'SSL 3.0' and, under that, a subkey named 'Server' and, under there, a DWORD value named 'Enabled', set at 0. You should also disable SSL 2.0 in the same way.
@ScotterMonkey You only need to set System.Net.ServicePointManager.SecurityProtocol if you are initiating outbound connections from .NET code, e.g. connecting to a web service or API from custom code running on your server. If you are only running a simple web site, and you are only accepting incoming connections from browsers, then the registry fix is enough.
Note: It appears SecurityProtocolType.Tls11 and SecurityProtocolType.Tls12 enum values are only available in ASP.net 4.5 and up. Not sure what we would have to do for older code bases running on 2.0 if TLS 1.0 goes by the wayside.
@AnishV You put that line of code in the initialization of your app, before any code that initiates an outbound SSL/TLS connection.
P
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 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.


Interesting. It looks like the documentation page was updated along with the MSDN move to ".NET Framework (current version)" and now explains that "no default value is listed for this property, on purpose." Perhaps a more future-proof version of the accepted answer would be to first query the property to retrieve the list of allowed protocols, and then remove the ones that your app considers insecure (i.e. anything less than TLS 1.2) rather than explicitly adding only the ones that you deem secure. This would not exclude new versions in the future.
It would be good to be able to have the program remove protocols from a list that the system generates, but I don't see a way to do that in the current API. The only option seems to be to force the specific protocol, which I don't see why anyone would desire to do. Unfortunately, without the ALPN support, it seems to be the only way to get a TLS1.2 connection to work.
It should be possible to loop through all the SecurityProtocolType enums, see which ones are present in the ServicePointManager.SecurityProtocol flags enum (it's a logical OR of all set flags, so you can test each one with an AND), and then build a new list of them with the ones you don't want removed. Then combine those into one enum and set the property with that.
I was just re-reading your enum/looping code, and I think it's incorrect. The |= logical operator will result in the property including whatever default values were set in the property initially, rather than including only Tls12 and above. To fix it, you have to initialize a SecurityProtocolType enum variable with a value of 0, do the |= loop against that variable, and then assign it to the ServicePointManager.SecurityProtocol property afterward.
Does anyone else find it insane that .NET doesn't automatically negotiate the highest protocol version it is capable of?!
C
CZahrobsky

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,
   } 
*/

This works but .NET 4.0 doesn't support TLS 1.2, however .NET 4.5 and higher support TLS 1.2. So you can add this code (or add do a bitwise OR to add support for TLS 1.2 negotiation) to your .NET 4.0 application and build it but you will need to deploy the code on .NET 4.5 or higher. blogs.perficient.com/microsoft/2016/04/tsl-1-2-and-net-support
Also see this, .NET 4.0 code will work fine on higher version of .NET including .NET 4.5 and .NET 4.6 stackoverflow.com/questions/33378902/…
The integer cast worked for sending TLS 1.2. The Tls12 enum value just doesn't exist in. NET 4.0
Two different points. See my comment. You can put the value but if your runtime Net version is 4.0 it will fail. You can compile with this flag but your runtime .NET versions needs to be 4.5 or higher as the base components on .NET 4.0 don't support the ciphers required for TLS 1.2 (see the links)
There are several hotfixes for older .NET runtime versions to add TLS 1.2 support. e.g. support.microsoft.com/en-us/help/3154518/…, CZahrobsky could have also been using this on the Win10 fall creators update which also included the hotfix.
D
DirtyHowi

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


C
Colonel Panic

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?


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

There is more information about this registry entry here:

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.

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


Registry settings as an alternative to a code would be great, but do these settings actually disable TLS 1.0 and 1.1 in favor of only allowing client connections using TLS 1.2 and above? According to the link, it seems to only disable RC4 in TLS. I think the Poodle attack is broader than that.
@JordanRieger These registry entries allow a .NET client to connect to a server that has the older protocols disabled to mitigate POODLE. Without these, the client will throw an error as the .NET client stupidly insists on using an older protocol even when the server is asking for a newer one. All bets are off if your server still allows connections using the older protocols. Theoretically the older protocols should be disabled. I wonder if the same registry entries that allow disabling these on the server (e.g. nartac.com/Products/IISCrypto) would work for the client too?
In the registry entries that nartac manipulates, there are separate settings for (when acting as) client and (when acting as) server. I don't recall if their interface distinguishes however. Do you know what versions of .net support this registry hack?
@Raman the point of my question, though, was to mitigate the POODLE vulnerability when your client is connecting to a server that you don't control. The vulnerability will allow a MITM attacker to downgrade the protocol to an older TLS or SSL version which can be hacked. Just disabling RC4 is not sufficient. These registry settings might be useful for certain cases, but not the scenario in my question.
@JordanRieger Agreed. I updated the text with some additional observations and thoughts.

关注公众号,不定期副业成功案例分享
Follow WeChat

Success story sharing

Want to stay one step ahead of the latest teleworks?

Subscribe Now