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.
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;
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:
Upgrade all applications to .NET 4.5 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
ServicePointManager.cs
see referencesource.microsoft.com/#System/net/System/Net/…
.NET 4.5
defaults to Tls12 - but as you've put here, it does not. It gives you the option to use it for SecurityProtocol
SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12
as per support.microsoft.com/en-us/help/3069494/…
You can override the default behavior in 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
.
reg add HKLM\SOFTWARE\Microsoft\.NETFramework\v4.0.30319 /v SchUseStrongCrypto /t REG_DWORD /d 1 /reg:64
(and/or /reg:32
)
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:
Double-click to install...
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.
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
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:
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;
}
}
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:
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
https://i.stack.imgur.com/NGeTH.png
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.
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.
if (!Enum.IsDefined(typeof(SecurityProtocolType), 0) && securityProtocols == 0) { securityProtocols |= SecurityProtocolType.Tls12; }
.
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?
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.
Microsoft recently published best practices around this. https://docs.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://docs.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.
if (System.Environment.OSVersion.Version < new Version(6, 2) /* Windows 8 */) ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; else ServicePointManager.SecurityProtocol = SecurityProtocolType.SystemDefault;
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"
There are two possible scenario,
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 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>
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
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.
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
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.
For Key: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft.NETFramework\v4.0.30319 Value: SchUseStrongCrypto
You have to set the value to 1.
Success story sharing
[Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12)
Invoke-RestMethod relies on the same underlying .NET framework libraries.Net.ServicePointManager.SecurityProtocol = Net.ServicePointManager.SecurityProtocol OR Net.SecurityProtocolType.Tls12 OR Net.SecurityProtocolType.Tls12