Transport Layer Security (TLS) best practices with the .NET Framework

The Transport Layer Security (TLS) protocol is an industry standard designed to help protect the privacy of information communicated over the Internet. TLS 1.2 is a standard that provides security improvements over previous versions. TLS 1.2 will eventually be replaced by the newest released standard TLS 1.3 which is faster and has improved security. This article presents recommendations to secure .NET Framework applications that use the TLS protocol.

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.

This document targets developers who are:

We recommend that you:

  • Target .NET Framework 4.7 or later versions on your apps. Target .NET Framework 4.7.1 or later versions on your WCF apps.
  • Do not specify the TLS version. Configure your code to let the OS decide on the TLS version.
  • Perform a thorough code audit to verify you're not specifying a TLS or SSL version.

When your app lets the OS choose the TLS version:

  • It automatically takes advantage of new protocols added in the future, such as TLS 1.3.
  • The OS blocks protocols that are discovered not to be secure.

The section Audit your code and make code changes covers auditing and updating your code.

This article explains how to enable the strongest security available for the version of the .NET Framework that your app targets and runs on. When an app explicitly sets a security protocol and version, it opts out of any other alternative, and opts out of .NET Framework and OS default behavior. If you want your app to be able to negotiate a TLS 1.2 connection, explicitly setting to a lower TLS version prevents a TLS 1.2 connection.

If you can't avoid hardcoding a protocol version, we strongly recommend that you specify TLS 1.2. For guidance on identifying and removing TLS 1.0 dependencies, download the Solving the TLS 1.0 Problem whitepaper.

WCF Supports TLS1.0, 1.1 and 1.2 as the default in .NET Framework 4.7. Starting with .NET Framework 4.7.1, WCF defaults to the operating system configured version. If an application is explicitly configured with SslProtocols.None, WCF uses the operating system default setting when using the NetTcp transport.

You can ask questions about this document in the GitHub issue Transport Layer Security (TLS) best practices with the .NET Framework.

Audit your code and make code changes

For ASP.NET applications, inspect the <system.web><httpRuntime targetFramework> element of web.config to verify you're using the intended version of the .NET Framework.

For Windows Forms and other applications, see How to: Target a Version of the .NET Framework.

Use the following sections to verify you're not using a specific TLS or SSL version.

If your app targets .NET Framework 4.7 or later versions

The following sections show how to verify you're not using a specific TLS or SSL version.

For HTTP networking

ServicePointManager, using .NET Framework 4.7 and later versions, defaults to the OS choosing the best security protocol and version. To get the default OS best choice, if possible, don't set a value for the SecurityProtocol property. Otherwise, set it to SystemDefault.

The remainder of this article is not relevant when targeting .NET Framework 4.7 or later versions for HTTP networking.

For TCP sockets networking

SslStream, using .NET Framework 4.7 and later versions, defaults to the OS choosing the best security protocol and version. To get the default OS best choice, if possible, don't use the method overloads of SslStream that take an explicit SslProtocols parameter. Otherwise, pass SslProtocols.None. We recommend that you don't use Default; setting SslProtocols.Default forces the use of SSL 3.0 /TLS 1.0 and prevents TLS 1.2.

Don't set a value for the SecurityProtocol property (for HTTP networking).

Don't use the method overloads of SslStream that take an explicit SslProtocols parameter (for TCP sockets networking). When you retarget your app to .NET Framework 4.7 or later versions, you'll be following the best practices recommendation.

The remainder of this topic is not relevant when targeting .NET Framework 4.7 or later versions for TCP sockets networking.

For WCF TCP transport using transport security with certificate credentials

WCF uses the same networking stack as the rest of the .NET Framework.

If you are targeting 4.7.1, WCF is configured to allow the OS to choose the best security protocol by default unless explicitly configured:

  • In your application configuration file.
  • Or, in your application in the source code.

By default, .NET Framework 4.7 and later versions is configured to use TLS 1.2 and allows connections using TLS 1.1 or TLS 1.0. Configure WCF to allow the OS to choose the best security protocol by configuring your binding to use SslProtocols.None. This can be set on SslProtocols. SslProtocols.None can be accessed from Transport. NetTcpSecurity.Transport can be accessed from Security.

If you're using a custom binding:

  • Configure WCF to allow the OS to choose the best security protocol by setting SslProtocols to use SslProtocols.None.
  • Or configure the protocol used with the configuration path system.serviceModel/bindings/customBinding/binding/sslStreamSecurity:sslProtocols.

If you're not using a custom binding and you're setting your WCF binding using configuration, set the protocol used with the configuration path system.serviceModel/bindings/netTcpBinding/binding/security/transport:sslProtocols.

For WCF Message Security with certificate credentials

.NET Framework 4.7 and later versions by default uses the protocol specified in the SecurityProtocol property. When the AppContextSwitch Switch.System.ServiceModel.DisableUsingServicePointManagerSecurityProtocols is set to true, WCF chooses the best protocol, up to TLS 1.0.

If your app targets a .NET Framework version earlier than 4.7

Audit your code to verify you're not setting a specific TLS or SSL version using the following sections:

For .NET Framework 4.6 - 4.6.2 and not WCF

Set the DontEnableSystemDefaultTlsVersions AppContext switch to false. See Configuring security via AppContext switches.

For WCF using .NET Framework 4.6 - 4.6.2 using TCP transport security with Certificate Credentials

You must install the latest OS patches. See Security updates.

The WCF framework automatically chooses the highest protocol available up to TLS 1.2 unless you explicitly configure a protocol version. For more information, see the preceding section For WCF TCP transport using transport security with certificate credentials.

For .NET Framework 3.5 - 4.5.2 and not WCF

We recommend you upgrade your app to .NET Framework 4.7 or later versions. If you cannot upgrade, take the following steps. At some point in the future, your application may fail until you upgrade to .NET Framework 4.7 or later versions.

Set the SchUseStrongCrypto and SystemDefaultTlsVersions registry keys to 1. See Configuring security via the Windows Registry. The .NET Framework version 3.5 supports the SchUseStrongCrypto flag only when an explicit TLS value is passed.

If you are running on .NET Framework 3.5, you need to install a hot patch so that TLS 1.2 can be specified by your program:

KB3154518 Reliability Rollup HR-1605 - Support for TLS System Default Versions included in the .NET Framework 3.5.1 on Windows 7 SP1 and Server 2008 R2 SP1
KB3154519 Reliability Rollup HR-1605 - Support for TLS System Default Versions included in the .NET Framework 3.5 on Windows Server 2012
KB3154520 Reliability Rollup HR-1605 -Support for TLS System Default Versions included in the .NET Framework 3.5 on Windows 8.1 and Windows Server 2012 R2
KB3156421 1605 Hotfix rollup 3154521 for the .NET Framework 4.5.2 and 4.5.1 on Windows

For WCF using .NET Framework 3.5 - 4.5.2 using TCP transport security with Certificate Credentials

These versions of the WCF framework are hardcoded to use values SSL 3.0 and TLS 1.0. These values cannot be changed. You must update and retarget to NET Framework 4.6 or later versions to use TLS 1.1 and 1.2.

If your app targets .NET Framework 3.5

If you must explicitly set a security protocol instead of letting the .NET framework or the OS pick the security protocol, add SecurityProtocolTypeExtensions and SslProtocolsExtension enumerations to your code. SecurityProtocolTypeExtensions and SslProtocolsExtension include values for Tls12, Tls11, and the SystemDefault value. See Support for TLS System Default Versions included in .NET Framework 3.5 on Windows 8.1 and Windows Server 2012 R2.

Configuring security via AppContext switches (for .NET Framework 4.6 or later versions)

The AppContext switches described in this section are relevant if your app targets, or runs on, .NET Framework 4.6 or later versions. Whether by default, or by setting them explicitly, the switches should be false if possible. If you want to configure security via one or both switches, then don't specify a security protocol value in your code; doing so would override the switch(es).

The switches have the same effect whether you're doing HTTP networking (ServicePointManager) or TCP sockets networking (SslStream).

Switch.System.Net.DontEnableSchUseStrongCrypto

A value of false for Switch.System.Net.DontEnableSchUseStrongCrypto causes your app to use strong cryptography. A value of false for DontEnableSchUseStrongCrypto uses more secure network protocols (TLS 1.2, TLS 1.1, and TLS 1.0) and blocks protocols that are not secure. For more info, see The SCH_USE_STRONG_CRYPTO flag. A value of true disables strong cryptography for your app.

If your app targets .NET Framework 4.6 or later versions, this switch defaults to false. That's a secure default, which we recommend. If your app runs on .NET Framework 4.6, but targets an earlier version, the switch defaults to true. In that case, you should explicitly set it to false.

DontEnableSchUseStrongCrypto should only have a value of true if you need to connect to legacy services that don't support strong cryptography and can't be upgraded.

Switch.System.Net.DontEnableSystemDefaultTlsVersions

A value of false for Switch.System.Net.DontEnableSystemDefaultTlsVersions causes your app to allow the operating system to choose the protocol. A value of true causes your app to use protocols picked by the .NET Framework.

If your app targets .NET Framework 4.7 or later versions, this switch defaults to false. That's a secure default that we recommend. If your app runs on .NET Framework 4.7 or later versions, but targets an earlier version, the switch defaults to true. In that case, you should explicitly set it to false.

Switch.System.ServiceModel.DisableUsingServicePointManagerSecurityProtocols

A value of false for Switch.System.ServiceModel.DisableUsingServicePointManagerSecurityProtocols causes your application to use the value defined in ServicePointManager.SecurityProtocols for message security using certificate credentials. A value of true uses the highest protocol available, up to TLS1.0

For applications targeting .NET Framework 4.7 and later versions, this value defaults to false. For applications targeting .NET Framework 4.6.2 and earlier, this value defaults to true.

Switch.System.ServiceModel.DontEnableSystemDefaultTlsVersions

A value of false for Switch.System.ServiceModel.DontEnableSystemDefaultTlsVersions sets the default configuration to allow the operating system to choose the protocol. A value of true sets the default to the highest protocol available, up to TLS1.2.

For applications targeting .NET Framework 4.7.1 and later versions, this value defaults to false. For applications targeting .NET Framework 4.7 and earlier, this value defaults to true.

For more information about TLS protocols, see Mitigation: TLS Protocols. For more information about AppContext switches, see <AppContextSwitchOverrides> Element.

Configuring security via the Windows Registry

Warning

Setting registry keys affects all applications on the system. Use this option only if you are in full control of the machine and can control changes to the registry.

If setting one or both AppContext switches isn't an option, you can control the security protocols that your app uses with the Windows Registry keys described in this section. You might not be able to use one or both the AppContext switches if your app runs on .NET Framework 4.5.2 or earlier versions, or if you can't edit the configuration file. If you want to configure security with the registry, don't specify a security protocol value in your code; doing so overrides the registry setting.

The names of the registry keys are similar to the names of the corresponding AppContext switches but without a DontEnable prepended to the name. For example, the AppContext switch DontEnableSchUseStrongCrypto is the registry key called SchUseStrongCrypto.

These keys are available in all .NET Framework versions for which there's a recent security patch. See Security updates.

All of the registry keys described below have the same effect whether you're doing HTTP networking (ServicePointManager) or TCP sockets networking (SslStream).

SchUseStrongCrypto

The HKEY_LOCAL_MACHINE\SOFTWARE\[Wow6432Node\]Microsoft\.NETFramework\<VERSION>: SchUseStrongCrypto registry key has a value of type DWORD. A value of 1 causes your app to use strong cryptography. The strong cryptography uses more secure network protocols (TLS 1.2, TLS 1.1, and TLS 1.0) and blocks protocols that are not secure. A value of 0 disables strong cryptography. For more information, see The SCH_USE_STRONG_CRYPTO flag.

If your app targets .NET Framework 4.6 or later versions, this key defaults to a value of 1. That's a secure default that we recommend. If your app runs on .NET Framework 4.6, but targets an earlier version, then the key defaults to 0. In that case, you should explicitly set its value to 1.

This key should only have a value of 0 if you need to connect to legacy services that don't support strong cryptography and can't be upgraded.

SystemDefaultTlsVersions

The HKEY_LOCAL_MACHINE\SOFTWARE\[Wow6432Node\]Microsoft\.NETFramework\<VERSION>: SystemDefaultTlsVersions registry key has a value of type DWORD. A value of 1 causes your app to allow the operating system to choose the protocol. A value of 0 causes your app to use protocols picked by the .NET Framework.

<VERSION> must be v4.0.30319 (for .NET Framework 4 and above) or v2.0.50727 (for .NET Framework 3.5).

If your app targets .NET Framework 4.7 or later versions, this key defaults to a value of 1. That's a secure default that we recommend. If your app runs on .NET Framework 4.7 or later versions, but targets an earlier version, the key defaults to 0. In that case, you should explicitly set its value to 1.

For more info, see Cumulative Update for Windows 10 Version 1511 and Windows Server 2016 Technical Preview 4: May 10, 2016.

For more information with .NET framework 3.5.1, see Support for TLS System Default Versions included in .NET Framework 3.5.1 on Windows 7 SP1 and Server 2008 R2 SP1.

The following .REG file sets the registry keys and their variants to their most safe values:

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

Configuring Schannel protocols in the Windows Registry

You can use the registry for fine-grained control over the protocols that your client and/or server app negotiates. Your app's networking goes through Schannel (which is another name for Secure Channel. By configuring Schannel, you can configure your app's behavior.

Start with the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols registry key. Under that key you can create any subkeys in the set SSL 2.0, SSL 3.0, TLS 1.0, TLS 1.1, and TLS 1.2. Under each of those subkeys, you can create subkeys Client and/or Server. Under Client and Server, you can create DWORD values DisabledByDefault (0 or 1) and Enabled (0 or 0xFFFFFFFF).

The SCH_USE_STRONG_CRYPTO flag

When it's enabled (by default, by an AppContext switch, or by the Windows Registry), the .NET Framework uses the SCH_USE_STRONG_CRYPTO flag when your app requests a TLS security protocol. The SCH_USE_STRONG_CRYPTO flag can be enabled by default, with the AppContext switch, or with the Registry. The OS passes the flag to Schannelto instruct it to disable known weak cryptographic algorithms, cipher suites, and TLS/SSL protocol versions that may be otherwise enabled for better interoperability. For more information, see:

The SCH_USE_STRONG_CRYPTO flag is also passed to Schannel when you explicitly use the Tls (TLS 1.0), Tls11, or Tls12 enumerated values of SecurityProtocolType or SslProtocols.

Security updates

The best practices in this article depend on recent security updates being installed. These updates include the ability to use advanced .NET Framework 4.7 and later features. Recent security updates are important if your app runs on .NET Framework 4.7 and later versions (even if it targets an earlier version).

To update the .NET Framework to allow the operating system to choose the best version of TLS to use, you must install at least:

See also:

Support for TLS 1.2

For your app to negotiate TLS 1.2, the OS and the .NET Framework version both need to support TLS 1.2.

Operating system requirements to support TLS 1.2

To enable or re-enable TLS 1.2 and/or TLS 1.1 on a system that supports them, see Transport Layer Security (TLS) registry settings.

OS TLS 1.2 support
Windows 10
Windows Server 2016
Supported, and enabled by default.
Windows 8.1
Windows Server 2012 R2
Supported, and enabled by default.
Windows 8.0
Windows Server 2012
Supported, and enabled by default.
Windows 7 SP1
Windows Server 2008 R2 SP1
Supported, but not enabled by default. See the Transport Layer Security (TLS) registry settings web page for details on how to enable TLS 1.2.
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.

For information about which TLS/SSL protocols are enabled by default on each version of Windows, see Protocols in TLS/SSL (Schannel SSP).

Requirements to support TLS 1.2 with .NET Framework 3.5

This table shows the OS update you'll need to support TLS 1.2 with .NET Framework 3.5. We recommend you apply all OS updates.

OS Minimum update needed to support TLS 1.2 with .NET Framework 3.5
Windows 10
Windows Server 2016
Cumulative Update for Windows 10 Version 1511 and Windows Server 2016 Technical Preview 4: May 10, 2016
Windows 8.1
Windows Server 2012 R2
Support for TLS System Default Versions included in the .NET Framework 3.5 on Windows 8.1 and Windows Server 2012 R2
Windows 8.0
Windows Server 2012
Support for TLS System Default Versions included in the .NET Framework 3.5 on Windows Server 2012
Windows 7 SP1
Windows Server 2008 R2 SP1
Support for TLS System Default Versions included in the .NET Framework 3.5.1 on Windows 7 SP1 and Server 2008 R2 SP1
Windows Server 2008 Support for TLS System Default Versions included in the .NET Framework 2.0 SP2 on Windows Vista SP2 and Server 2008 SP2
Windows Vista Not supported

Azure Cloud Services

If you are using Azure Cloud Services Web and Worker roles to host and run your application, there are some considerations that you need to take into account to support TLS 1.2.

.NET Framework 4.7 is not installed on Azure Guest OS by default

The latest version installed in the latest Azure Guest OS Family 5 release (Windows Server 2016) is 4.6.2. To see which versions of .NET Framework are installed on each Azure Guest OS, see the Azure Guest OS releases and SDK compatibility matrix.

If your app targets a .NET Framework version that is not available on the Azure Guest OS version, then you need to install it yourself. See Install .NET on Azure Cloud Service Roles. If the framework installation requires a restart, the service roles might also restart before entering the Ready state.

Azure Guest OS registry settings

The Azure Guest OS Family 5 image for Azure Cloud Services already has the SchUseStrongCrypto registry key set to a value of 1. For more information, see SchUseStrongCrypto.

Set the SystemDefaultTlsVersions registry key to 1. See Configuring security via the Windows Registry.