Default SecurityProtocol in .NET 4.5
Asked Answered
A

17

324

What is the default security protocol for communicating with servers that support up to TLS 1.2? Will .NET by default, choose the highest security protocol supported on the server side or do I have to explicitly add this line of code:

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

Is there a way to change this default, besides a code change?

Lastly, does .NET 4.0 only support up to TLS 1.0? i.e. I have to upgrade client projects to 4.5 to support TLS 1.2.

My motivation is to remove support for SSLv3 on the client side even if server supports it (I already have a powershell script to disable this in the machine registry) and to support the highest TLS protocol that the server supports.

Update: Looking at the ServicePointManager class in .NET 4.0 I see no enumerated values for TLS 1.0 and 1.1. In both .NET 4.0/4.5, the default is SecurityProtocolType.Tls|SecurityProtocolType.Ssl3. Hopefully this default won't break by disabling SSLv3 in the registry.

However, I've decided I have to upgrade all apps to .NET 4.5 and to explicitly add SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; anyway to all bootstrapping code of all applications.

This will make outbound requests to various apis and services to not downgrade to SSLv3 and should select the highest level of TLS.

Does this approach sound reasonable or overkill? I have many applications to update, and I want to future proof them since I hear even TLS 1.0 may be deprecated in the near future by some providers.

As a client making outbound requests to APIs, does disabling SSL3 in the registry even have an effect in the .NET framework? I see by default, TLS 1.1 and 1.2 are not enabled, do we have to enable it via the registry? RE http://support.microsoft.com/kb/245030.

After a bit of investigation, I believe the registry settings will have no affect since they apply to IIS (server subkey) and browsers (client subkey).

Sorry this post turned into multiple questions, followed up with "maybe" answers.

Asur answered 2/2, 2015 at 20:24 Comment(3)
FYI: Latest best practices around TLS: learn.microsoft.com/en-us/dotnet/framework/network-programming/…Chantell
For those who want to see the best answer for this, sort by votes!Previse
Related SO Q&A: #41619266 Readers should note this question is aging and newer recommendations are in place as of 2020.Judyjudye
L
369

Some of the those leaving comments on other answers have noted that setting System.Net.ServicePointManager.SecurityProtocol to specific values means that your app won't be able to take advantage of future TLS versions that may become the default values in future updates to .NET. Instead of specifying a fixed list of protocols, do the following:

For .NET 4.7 or later, do not set System.Net.ServicePointManager.SecurityProtocol. The default value (SecurityProtocolType.SystemDefault) will allow the operating system to use whatever versions it knows and has been configured for, including any new versions that may not have existed at the time the app was created.

For earlier versions of .NET Framework, you can instead turn on or off protocols you know and care about, leaving any others as they are.

To turn on TLS 1.1 and 1.2 without affecting other protocols:

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

Notice the use of |= to turn on these flags without turning others off.

To turn off SSL3 without affecting other protocols:

System.Net.ServicePointManager.SecurityProtocol &= ~SecurityProtocolType.Ssl3;
Limassol answered 6/4, 2016 at 14:51 Comment(20)
This is the really the correct answer. The accepted answer will ensure that your app will always toggle off new TLS versions unless you go back and update your code.Weisbart
What happens if you run this code multiple times? Won't Tls11 and Tls12 be added again and again? (as in, the result will be "Tls11 | Tls12 | Tls11 | Tls12 | Tls11 | Tls12 | Tls11 | Tls12 | Tls11 | Tls12" etc)Writer
@Writer No, it's a bitwise or, so it just turns the appropriate bits on if they're off. If those bits are already on, no change occurs.Limassol
And the PowerShell equivalent of this is [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12) Invoke-RestMethod relies on the same underlying .NET framework libraries.Adria
Shouldn't with Enum flag with TLS11 | TLS12, .net going to pick TLS12 always? any idea how/ where System.Net.ServicePointManager.SecurityProtocol get called from?Manta
Since nobody is talking about where to put this code, I successfully put it into Application_Start of Global.asax.cs for my ASP.NET MVC application. I was looking for how to get my SMTP requests to be sent over TLS1.2 and NOT over TLS1.0. I also added &= ~SecurityProtocolType.Tls to turn off TLS 1.0Kei
In VB the equivalent is Net.ServicePointManager.SecurityProtocol = Net.ServicePointManager.SecurityProtocol OR Net.SecurityProtocolType.Tls12 OR Net.SecurityProtocolType.Tls12Collins
Based on this answer, I do think it's better to turn off the protocol rather than my answer below, updated "correct" best answer, and the people have voted.Asur
Hmm, does this work if the SecurityProtocol is currently set to SecurityProtocolType.SystemDefault ?Pentalpha
Would it work to have this code in Startup.cs? It seems a bit more convenient for it to live there if possible.Clump
@Collins and the equivalent to explicitly exclude a protocol without affecting the rest is: ServicePointManager.SecurityProtocol = ServicePointManager.SecurityProtocol And Not SecurityProtocolType.Ssl3, which is recommended over explicitly requiring a protocol, because the later would exclude future versions made available whilst the source code is not updated.Shiny
Could anyone provide feedback on @Andrew's question? I have the same question: does System.Net.ServicePointManager.SecurityProtocol &= ~SecurityProtocolType.Ssl3 still work now that with .Net 4.7 the SecurityProtocol is currently set to SecurityProtocolType.SystemDefault ?Shiny
ServicePointManager.SecurityProtocol = SecurityProtocolType.SystemDefault: Dim Response As HttpResponseMessage = Client.GetAsync("https://www.google.com").Result triggers a runtime error: "ArgumentException: The specified value is not valid in the 'SslProtocolType' enumeration."Shiny
It worked for one machine i.e.production box but it did not work for stage box. Can someone tell me what might be wrong?Donee
@Andrew, if the SecurityProtocol is currently set to SecurityProtocolType.SystemDefault (which is default value in .Net 4.7) then setting SecurityProtocol |= Tls11 | Tls12 will disable Tls13. So the sentence "without affecting other protocols" is no longer valid in .Net 4.7.Bremble
adding to @MartinHollingsworth here is the "remove" logic for powershell [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -band -bnot [Net.SecurityProtocolType]::Tls11) also the "not" logic does not work if it is set to "SystemDefault" because its "bit" is 0Stela
Downvoting because actually your code makes an app unable to take advantage of future protocols, like @Bremble pointed out. Microsoft advices against hardcoding the value of System.Net.ServicePointManager.SecurityProtocol.Hieratic
@MuscicapaStriata, the title of the question is "Default SecurityProtocol in .NET 4.5". However, I've updated the answer to include the changes made to .NET 4.7. Thanks for including the link.Limassol
for me its work: For .NET 4.7 or later, do not set System.Net.ServicePointManager.SecurityProtocolAlanis
Hi All My query is related, #75180937 Please help me on this.Bemock
A
206

The default System.Net.ServicePointManager.SecurityProtocol in both .NET 4.0/4.5 is SecurityProtocolType.Tls|SecurityProtocolType.Ssl3.

.NET 4.0 supports up to TLS 1.0 while .NET 4.5 supports up to TLS 1.2

However, an application targeting .NET 4.0 can still support up to TLS 1.2 if .NET 4.5 is installed in the same environment. .NET 4.5 installs on top of .NET 4.0, replacing System.dll.

I've verified this by observing the correct security protocol set in traffic with fiddler4 and by manually setting the enumerated values in a .NET 4.0 project:

ServicePointManager.SecurityProtocol = (SecurityProtocolType)192 |
(SecurityProtocolType)768 | (SecurityProtocolType)3072;

Reference:

namespace System.Net
{
    [System.Flags]
    public enum SecurityProtocolType
    {
       Ssl3 = 48,
       Tls = 192,
       Tls11 = 768,
       Tls12 = 3072,
    }
}

If you attempt the hack on an environment with ONLY .NET 4.0 installed, you will get the exception:

Unhandled Exception: System.NotSupportedException: The requested security protocol is not supported. at System.Net.ServicePointManager.set_SecurityProtocol(SecurityProtocolType v alue)

However, I wouldn't recommend this "hack" since a future patch, etc. may break it.*

Therefore, I've decided the best route to remove support for SSLv3 is to:

  1. Upgrade all applications to .NET 4.5
  2. Add the following to boostrapping code to override the default and future proof it:

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

*Someone correct me if this hack is wrong, but initial tests I see it works

Asur answered 4/2, 2015 at 23:11 Comment(14)
Please see imperialviolet.org/2014/12/08/poodleagain.html "This seems like a good moment to reiterate that everything less than TLS 1.2 with an AEAD cipher suite is cryptographically broken."Aggress
Where did you find that default value/where is it documented?Walther
@Mathew, by viewing the source code of ServicePointManager.cs see referencesource.microsoft.com/#System/net/System/Net/…Asur
Thanks for sharing. For people reading the answer: to reiterate: The line of code in point 2 is necessary if you upgrade from 4.0 to 4.5 and if the server your code is trying to connect to restricts the min version of TLS to 1.1Ahem
I keep seeing people claim the .NET 4.5 defaults to Tls12 - but as you've put here, it does not. It gives you the option to use it for SecurityProtocolCephalization
I won't downvote this answer since it does provide a lot of helpful information, but implementing a hardcoded protocol version is not a good idea as it will restrict the application from using best available encryption and may result in security issues down the road. The registry changes to change the default behavior of .Net to actually support modern protocols is very much preferable. (It is, however, worth noting the registry change also disables SSL v3.)Carhop
This worked perfectly in my .NET 4.5 ASP.NET web app connecting to Elavon/Converge.Braggart
+1 for The default System.Net.ServicePointManager.SecurityProtocol in both .NET 4.0/4.5 is SecurityProtocolType.Tls|SecurityProtocolType.Ssl3Barrera
@AJHenderson It wouldn't be necessary to hard-code it if .NET was sane and negotiated the highest protocol version possible automatically. In my testing, it appears it does not -- a connection to a server supporting TLS1.1+ from .NET 4.5 fails using the default settings.Autocade
UPDATE: The registry hack by @dana works without code changes. Nice!Autocade
The registry change works, but it seems unstable (at least on Windows 10) and the change is reverted sometimes after updates are installed. Manually enabling TLS 1.2 in code seems like a more stable option: ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;Reformism
On FW 4.6 and 4.7, the default is now SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 as per support.microsoft.com/en-us/help/3069494/…Admittedly
There is something important missing on this correct answer, and that is in .NET 4.5+, you will need to set SecurityProtocol as below before any WebRequest calls. Before this: (HttpWebRequest)WebRequest.Create(url);Naoise
@IanKemp Why the hell did it take Microsoft that long to change that! TLS 1.2 had been available so many years ago, not to mention TLS 1.1.Shipwreck
D
78

You can override the default behavior in the following registry:

Key  : HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v4.0.30319 
Value: SchUseStrongCrypto
Type: REG_DWORD
Data : 1

and

Key  : HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\.NETFramework\v4.0.30319
Value: SchUseStrongCrypto
Type: REG_DWORD
Data : 1

For details, please see the implementation of ServicePointManager.

Delossantos answered 13/2, 2015 at 15:9 Comment(7)
Thanks, I didn't know about this. I will test it. I created a powershel script to set it: gist.github.com/lukehutton/ab80d207172a923401b1Asur
I was not able to see this actually work yet. I tried .net 4.5.2 and set this in registry. However, sslv3 and tls 1.0 was still the default.Asur
Changing registry does not look like a good solution. If application wants to support TLS1 then the application should take cate about it. Not the running environment. Otherwise it could harm other applications or make a hell from deploying and upgrading your application.Seesaw
@MikhailG quite the opposite. The registry change is the preferable method. SChannel provides an abstraction of the underlying negotiation and you want your application to use whatever the highest supported security level is. Artificially limiting it in software results in future problems when new protocols are released and your software is unable to use them. It would be nice if there was an option to say use only better than a given protocol in software, but there is no option for that without also preventing future versions from working. The did disable SSL v3 with that change though..Carhop
Command-line: reg add HKLM\SOFTWARE\Microsoft\.NETFramework\v4.0.30319 /v SchUseStrongCrypto /t REG_DWORD /d 1 /reg:64 (and/or /reg:32)Jovia
@MikhailG: Setting the registry does not prevent applications from supporting older protocols. It only changes the defaults (which include tls 1.0 as of now). Further, the default behavior in .Net 4.6+ is to use strong crypto; in that case this registry entry would only be useful as a means to disable strong crypto.Ricardo
Beware that if you are deploying to Azure this won't work as you don't have access to registry.Marasco
B
59

Create a text file with a .reg extension and the following contents:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v4.0.30319]
"SchUseStrongCrypto"=dword:00000001

[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319]
"SchUseStrongCrypto"=dword:00000001

Or download it from the following source:

https://gist.githubusercontent.com/dana-n/174759ce95e04fa1a8fd691f633ccbd3/raw/NET40-Enable-TLS-1_2.reg

Double-click to install...

Burgin answered 30/11, 2015 at 23:29 Comment(4)
The link you provided seems to have SSL certificate issues.Euplastic
Even when I add these registry key, I still have that issue. Any idea ?Whirlpool
@Whirlpool - What .NET version are you using? Luke's answer goes into a lot more detail than mine, but it looks like you need to at least have .NET 4.5 installed. Also, if you just made the change, you may have to recycle the app pool. These are kind of guesses, so without more detail I might be able to help much further :)Burgin
A recently applied patch support.microsoft.com/en-us/help/4019114/… to a server caused our .net 4.5.2 application to fail on https REST requests. These keys solved our problem.Funkhouser
D
28

I have found that when I specify only TLS 1.2 that it will still down negotiate to 1.1. System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

I have specified this in the Global.asax startup method for my .net 4.5 web app.

Drainage answered 11/12, 2015 at 15:11 Comment(4)
What is the supported security protocol on the server? I believe that is factor here too and may be 1.1 is the latest on the server. www.passionatecoder.caScar
Upvoted because this is the only answer that states WHERE to put the line of code that is the solution.Haler
Client (e.g. your C# WebClient) and the Server (API server you're calling) will negotiate to use the highest protocol that both support. So if your client supports TLS 1.2, but the server only TLS 1.1 - the Client will use TLS 1.1 (unless you REMOVE TLS 1.1 from your client - in which case they may not find a mutually supported protocol, and Client will error)Cephalization
Had to add using System.Net in global.asax.csDzungaria
O
23

Following code will:

  • print enabled protocols
  • print available protocols
  • enable TLS1.2 if platform supports it and if it is not enabled to begin with
  • disable SSL3 if it is enabled
  • print end result

Constants:

  • 48 is SSL3
  • 192 is TLS1
  • 768 is TLS1.1
  • 3072 is TLS1.2

Other protocols will not be affected. This makes this compatible with future protocols (Tls1.3, etc).

Code

// print initial status
    Console.WriteLine("Runtime: " + System.Diagnostics.FileVersionInfo.GetVersionInfo(typeof(int).Assembly.Location).ProductVersion);
    Console.WriteLine("Enabled protocols:   " + ServicePointManager.SecurityProtocol);
    Console.WriteLine("Available protocols: ");
    Boolean platformSupportsTls12 = false;
    foreach (SecurityProtocolType protocol in Enum.GetValues(typeof(SecurityProtocolType))) {                
        Console.WriteLine(protocol.GetHashCode());
        if (protocol.GetHashCode() == 3072){
            platformSupportsTls12 = true;
        }
    }
    Console.WriteLine("Is Tls12 enabled: " + ServicePointManager.SecurityProtocol.HasFlag((SecurityProtocolType)3072));    


// enable Tls12, if possible
    if (!ServicePointManager.SecurityProtocol.HasFlag((SecurityProtocolType)3072)){
        if (platformSupportsTls12){
            Console.WriteLine("Platform supports Tls12, but it is not enabled. Enabling it now.");
            ServicePointManager.SecurityProtocol |= (SecurityProtocolType)3072;
        } else {
            Console.WriteLine("Platform does not supports Tls12.");
        }
    }

// disable ssl3
   if (ServicePointManager.SecurityProtocol.HasFlag(SecurityProtocolType.Ssl3)) { 
      Console.WriteLine("Ssl3SSL3 is enabled. Disabling it now.");
      // disable SSL3. Has no negative impact if SSL3 is already disabled. The enclosing "if" if just for illustration.
      System.Net.ServicePointManager.SecurityProtocol &= ~SecurityProtocolType.Ssl3;                      
   }
    Console.WriteLine("Enabled protocols:   " + ServicePointManager.SecurityProtocol);

Output

Runtime: 4.7.2114.0
Enabled protocols:   Ssl3, Tls
Available protocols: 
0
48
192
768
3072
Is Tls12 enabled: False
Platform supports Tls12, but it is not enabled. Enabling it now.
Ssl3 is enabled. Disabling it now.
Enabled protocols:   Tls, Tls12
Odeen answered 21/2, 2018 at 9:47 Comment(0)
D
14

The registry change mechanism worked for me after a struggle. Actually my application was running as 32bit. So I had to change the value under path.

HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft.NETFramework\v4.0.30319

The value type needs to be DWORD and value above 0 .Better use 1.Registry settings to get .Net 4.0 app use TLS 1.2 provided .Net 4.5 is installed in the machine.

Darg answered 6/7, 2015 at 20:43 Comment(4)
It's not accurate. For .NET 4.5.2, this needs to be set to 1 (or above); but for .NET 4.6, it suffices not to be set to 0 (that is, it can be unset).Worcestershire
Oh I didnt test in .Net 4.6. My findings are there in blogpost joymonscode.blogspot.com/2015/08/…Darg
The registry key you mention should read "Wow6432Node". You omitted the "Node" part for some reason. I tried to edit your response but my change was only 4 letters so it wouldn't let me. :\Amora
I had to bounce IIS to have this setting active itself as the default.Florid
E
14

I got the problem when my customer upgraded TLS from 1.0 to 1.2. My application is using .net framework 3.5 and run on server. So i fixed it by this way:

  1. Fix the program

Before call HttpWebRequest.GetResponse() add this command:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolTypeExtensions.Tls11 | SecurityProtocolTypeExtensions.Tls12;

Extensions 2 DLLs by adding 2 new classes: System.Net and System.Security.Authentication

    namespace System.Net
    {
        using System.Security.Authentication;
        public static class SecurityProtocolTypeExtensions
        {
            public const SecurityProtocolType Tls12 = (SecurityProtocolType)SslProtocolsExtensions.Tls12;
            public const SecurityProtocolType Tls11 = (SecurityProtocolType)SslProtocolsExtensions.Tls11;
            public const SecurityProtocolType SystemDefault = (SecurityProtocolType)0;
        }
    } 

    namespace System.Security.Authentication
    {
        public static class SslProtocolsExtensions
        {
            public const SslProtocols Tls12 = (SslProtocols)0x00000C00;
            public const SslProtocols Tls11 = (SslProtocols)0x00000300;
        }
    } 
  1. Update Microsoft batch

Download batch:

  • For windows 2008 R2: windows6.1-kb3154518-x64.msu
  • For windows 2012 R2: windows8.1-kb3154520-x64.msu

For download batch and more details you can see here:

https://support.microsoft.com/en-us/help/3154518/support-for-tls-system-default-versions-included-in-the-.net-framework-3.5.1-on-windows-7-sp1-and-server-2008-r2-sp1

Entopic answered 21/4, 2017 at 5:12 Comment(2)
is it possible the change SecurityProtocol without changing source code ? like a machine.config or app.config.Seto
Wow. That's voodoo of the year award..stuff...right there. You rock the suburbs!Harar
H
10

I'm running under .NET 4.5.2, and I wasn't happy with any of these answers. As I'm talking to a system which supports TLS 1.2, and seeing as SSL3, TLS 1.0, and TLS 1.1 are all broken and unsafe for use, I don't want to enable these protocols. Under .NET 4.5.2, the SSL3 and TLS 1.0 protocols are both enabled by default, which I can see in code by inspecting ServicePointManager.SecurityProtocol. Under .NET 4.7, there's the new SystemDefault protocol mode which explicitly hands over selection of the protocol to the OS, where I believe relying on registry or other system configuration settings would be appropriate. That doesn't seem to be supported under .NET 4.5.2 however. In the interests of writing forwards-compatible code, that will keep making the right decisions even when TLS 1.2 is inevitably broken in the future, or when I upgrade to .NET 4.7+ and hand over more responsibility for selecting an appropriate protocol to the OS, I adopted the following code:

SecurityProtocolType securityProtocols = ServicePointManager.SecurityProtocol;
if (securityProtocols.HasFlag(SecurityProtocolType.Ssl3) || securityProtocols.HasFlag(SecurityProtocolType.Tls) || securityProtocols.HasFlag(SecurityProtocolType.Tls11))
{
    securityProtocols &= ~(SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11);
    if (securityProtocols == 0)
    {
        securityProtocols |= SecurityProtocolType.Tls12;
    }
    ServicePointManager.SecurityProtocol = securityProtocols;
}

This code will detect when a known insecure protocol is enabled, and in this case, we'll remove these insecure protocols. If no other explicit protocols remain, we'll then force enable TLS 1.2, as the only known secure protocol supported by .NET at this point in time. This code is forwards compatible, as it will take into consideration new protocol types it doesn't know about being added in the future, and it will also play nice with the new SystemDefault state in .NET 4.7, meaning I won't have to re-visit this code in the future. I'd strongly recommend adopting an approach like this, rather than hard-coding any particular security protocol states unconditionally, otherwise you'll have to recompile and replace your client with a new version in order to upgrade to a new security protocol when TLS 1.2 is inevitably broken, or more likely you'll have to leave the existing insecure protocols turned on for years on your server, making your organisation a target for attacks.

Heatherheatherly answered 5/6, 2018 at 1:55 Comment(5)
This answer seems like the most thought out, however, unless I'm missing something, I'm not sure it will be forward compatible whenever TLS 1.2 inevitably breaks. From what I'm seeing in my .NET 4.7.2 app, the SecurityProtocolType.SystemDefault flag evaluates to 0, so checking if (securityProtocols == 0) with the bitwise inclusive or flag for TLS 1.2 will always include TLS 1.2, even after it is "breaks", right? Not sharp shooting here. I am genuinely trying to find the best path forward.Umpteen
I've modified your code to include this and it appears to work and be forward compatible: if (!Enum.IsDefined(typeof(SecurityProtocolType), 0) && securityProtocols == 0) { securityProtocols |= SecurityProtocolType.Tls12; }.Umpteen
@Griswald_911, I haves similar code in my 4.7.2 console application, and I found this line securityProtocols |= SecurityProtocolType.Tls12; (without if block) does not maintain SystemDefault, the securityProtocols only has TLS2 afterward. So do you mean when value is SystemDefault, no value should be updated? Regarding the forward compatible, are you assuming the OS would take care of enabling newer protocol like TLS 1.3?Aspire
@Aspire -- Correct. The line securityProtocols |= SecurityProtocolType.Tls12;' will add TLS 1.2, but because the SecurityProtocolType` enum has a [Flags] attribute, and the SystemDefault enumeration value is 0, the SystemDefault value will be stripped, even if it was previously set. The end result is that you can either set the SevicePointManager.SecurityProtocol to 0, or to any combination of the other enumeration values. If you set it to SystemDefault, you are basically opting out of specifying the protocol yourself and letting the OS decide.Umpteen
@Aspire -- The point is that, after setting the value to SystemDefault, your app should use whatever the OS specifies--which is TLS 1.2 in the latest versions of Windows 10.The idea is that, in the future when TLS 1.3 becomes the standard, you shouldn't have to modify your application to inherit that functionality. See the documentation here, where SystemDefault "allows the operating system to choose the best protocol to use, and to block protocols that are not secure".Umpteen
C
9

Microsoft recently published best practices around this. https://learn.microsoft.com/en-us/dotnet/framework/network-programming/tls

Summary

Target .Net Framework 4.7, remove any code setting the SecurityProtocol, thus the OS will ensure you use the most secure solution.

NB: You will also need to ensure that the latest version of TLS is supported & enabled on your OS.

OS                          TLS 1.2 support

Windows 10                  \_ Supported, and enabled by default.
Windows Server 2016         /   
Windows 8.1                 \_ Supported, and enabled by default.
Windows Server 2012 R2      /
Windows 8.0                 \_ Supported, and enabled by default.
Windows Server 2012         /
Windows 7 SP1               \_ Supported, but not enabled by default*.
Windows Server 2008 R2 SP1  /
Windows Server 2008         -  Support for TLS 1.2 and TLS 1.1 requires an update. See Update to add support for TLS 1.1 and TLS 1.2 in Windows Server 2008 SP2.
Windows Vista               -  Not supported.

* To enable TLS1.2 via the registry see https://learn.microsoft.com/en-us/windows-server/security/tls/tls-registry-settings#tls-12 

    Path: HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server

        Property: Enabled
        Type: REG_DWORD
        Value: 1

        Property: DisabledByDefault 
        Type: REG_DWORD
        Value: 0

    Path: HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client

        Property: Enabled
        Type: REG_DWORD
        Value: 1

        Property: DisabledByDefault 
        Type: REG_DWORD
        Value: 0

For more information and older frameworks, please refer to the MS link.

Chantell answered 8/11, 2018 at 10:53 Comment(4)
Problem is that tls 1.1 and tls 1.2 won't work on Windows 7 and Server 2008 if you follow the guidelines (keeping SecurityProtocolType.SystemDefault) because they are not "enabled" (whatever that means) in these os' without a registry change. This makes SystemDefault in practice broken by design. Microsoft really messed up this one.Series
Nice one, thanks @osexpert, good catch. I've amended the answer to include info on supported OSes, so there are no surprises for people running older OSes where just targeting 4.7 isn't enough.Chantell
NB: There's also a KB to enable the newer protocols on some OSes: support.microsoft.com/en-my/help/3140245/…Chantell
If registry settings are not an option I think this is the best solution for .NET 4.7+: if (System.Environment.OSVersion.Version < new Version(6, 2) /* Windows 8 */) ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; else ServicePointManager.SecurityProtocol = SecurityProtocolType.SystemDefault;Series
G
6

For completeness, here is a Powershell script that sets aforementioned registry keys:

new-itemproperty -path "HKLM:\SOFTWARE\Microsoft\.NETFramework\v4.0.30319" -name "SchUseStrongCrypto" -Value 1 -PropertyType "DWord";
new-itemproperty -path "HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319" -name "SchUseStrongCrypto" -Value 1 -PropertyType "DWord"
Galenism answered 31/8, 2016 at 8:18 Comment(0)
R
5

There are two possible scenario,

  1. If you application run on .net framework 4.5 or less than that and you can easily deploy new code to the production then you can use of below solution.

    You can add below line of code before making api call,

    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; // .NET 4.5

  2. If you cannot deploy new code and you want to resolve with the same code which is present in the production, then you have two options.

Option 1 :

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v4.0.30319]
"SchUseStrongCrypto"=dword:00000001

[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319]
"SchUseStrongCrypto"=dword:00000001


then create a file with extension .reg and install.

Note : This setting will apply at registry level and is applicable to all application present on that machine and if you want to restrict to only single application then you can use Option 2

Option 2 : This can be done by changing some configuration setting in config file. You can add either of one in your config file.

<runtime>
    <AppContextSwitchOverrides value="Switch.System.Net.DontEnableSchUseStrongCrypto=false"/>
  </runtime>

or

<runtime>
  <AppContextSwitchOverrides value="Switch.System.Net.DontEnableSystemDefaultTlsVersions=false"
</runtime>
Reliance answered 16/9, 2020 at 19:13 Comment(0)
J
3

According to Transport Layer Security (TLS) best practices with the .NET Framework: To ensure .NET Framework applications remain secure, the TLS version should not be hardcoded. Instead set the registry keys: SystemDefaultTlsVersions and SchUseStrongCrypto:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\.NETFramework\v2.0.50727]
"SystemDefaultTlsVersions"=dword:00000001
"SchUseStrongCrypto"=dword:00000001

[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\.NETFramework\v4.0.30319]
"SystemDefaultTlsVersions"=dword:00000001
"SchUseStrongCrypto"=dword:00000001

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v2.0.50727]
"SystemDefaultTlsVersions"=dword:00000001
"SchUseStrongCrypto"=dword:00000001

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v4.0.30319]
"SystemDefaultTlsVersions"=dword:00000001
"SchUseStrongCrypto"=dword:00000001
Johore answered 9/4, 2020 at 11:11 Comment(0)
S
2

An alternative to hard-coding ServicePointManager.SecurityProtocol or the explicit SchUseStrongCrypto key as mentioned above:
You can tell .NET to use the default SCHANNEL settings with the SystemDefaultTlsVersions key,
e.g.:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v4.0.30319] "SystemDefaultTlsVersions"=dword:00000001
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319] "SystemDefaultTlsVersions"=dword:00000001
Silicone answered 20/7, 2016 at 16:17 Comment(0)
E
2

The BEST solution to this problem appears to be to upgrade to at least .NET 4.6 or later, which will automatically choose strong protocols as well as strong ciphers.

If you can't upgrade to .NET 4.6, the advice of setting

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

And using the registry settings:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft.NETFramework\v4.0.30319 – SchUseStrongCrypto = DWORD of 1 HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft.NETFramework\v4.0.30319 – SchUseStrongCrypto = DWORD of 1

Results in using something other than TLS 1.0 and a strong cipher.

In my testing, only the setting in the Wow6432Node made any difference, even though my test application was built for Any CPU.

Emelineemelita answered 18/5, 2017 at 17:25 Comment(1)
Clarification: you need only set the SevicePointManager.SecurityProtocol OR set the registry settings. There's no need to do both. For my application, I opted to just set ServicePointManager.SecurityProtocol. My reasoning is that setting the registry affects the entire machine, and I didn't want someone else's application breaking because it depended on TLS 1.0.Emelineemelita
F
1

If you can use .NET 4.7.1 or newer, it will use TLS 1.2 as the minimum protocol based on the operating system capabilities. Per Microsoft recommendation :

To ensure .NET Framework applications remain secure, the TLS version should not be hardcoded. .NET Framework applications should use the TLS version the operating system (OS) supports.
Ferrante answered 4/6, 2020 at 10:43 Comment(0)
S
-2

For Key: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft.NETFramework\v4.0.30319 Value: SchUseStrongCrypto

You have to set the value to 1.

Sweater answered 23/6, 2015 at 15:30 Comment(1)
I think you're getting downvoted because its the same answer @Jira Mares offered, but with less detailJennijennica

© 2022 - 2024 — McMap. All rights reserved.