Skip to content
06 · Legacy ProtocolsPart 2 of 4Intermediate

TLS and Schannel hardening on Windows

Disable SSL, TLS 1.0/1.1 and weak ciphers in Schannel, set the cipher suite order by GPO and make .NET use strong crypto after measuring old TLS use.

Florian Amette7 min read

Most Windows components that speak TLS do it through Schannel, the Windows implementation of SSL and TLS. IIS, Remote Desktop, LDAPS on domain controllers, WinRM over HTTPS, AD FS, SQL Server and every .NET Framework application calling HttpClient all inherit its protocol and cipher choices. Old defaults kept SSL 3.0, TLS 1.0 and TLS 1.1 available and allowed ciphers such as 3DES and RC4, which enable downgrade and decryption attacks with names like POODLE, BEAST and SWEET32.

This guide belongs to the legacy protocols area. The pillar guide handles name resolution, SMB and NTLM; here the focus is transport encryption.

Where Windows stands today

Microsoft has been disabling TLS 1.0 and 1.1 by default in recent Windows releases, starting with Windows 11 previews in 2023. Windows 11 24H2 and 25H2 and Windows Server 2025 are much closer to a hardened default than Windows Server 2016 or 2019, but defaults vary by build and some are controlled by updates, so check the current Microsoft docs for your versions and, more importantly, measure what your servers actually negotiate.

ProtocolStatusAction
SSL 2.0, SSL 3.0BrokenDisable everywhere
TLS 1.0, TLS 1.1Deprecated (RFC 8996)Disable after inventory
TLS 1.2CurrentEnable, with a strong cipher suite order
TLS 1.3Current (Windows 11, Server 2022+)Leave enabled

Step 1: find who still uses TLS 1.0 and 1.1

Switching old protocols off blindly breaks things you forgot existed: a scanner that sends mail over SMTP with STARTTLS, an old Java application talking to LDAPS, a monitoring agent, a SQL client library from 2012.

  • Schannel event logging. Increase logging under HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL with EventLogging (DWORD). The default 1 logs errors only; 7 logs errors, warnings and informational events, including successful handshakes (event 36880 in the System log shows the protocol and cipher suite). This is noisy; enable it on a sample of servers for a few days, not permanently.
  • IIS logging. IIS 10 can log the negotiated protocol and cipher through custom log fields based on server variables such as CRYPT_PROTOCOL and CRYPT_CIPHER_ALG_ID. Add them on web servers and look for the TLS 1.0 and 1.1 protocol values.
  • Domain controllers. LDAPS clients using old TLS show up in Schannel events on DCs. Test a DC in a lab before production: some network appliances only speak TLS 1.0 to LDAPS.
  • External scan. Tools such as Nmap's ssl-enum-ciphers script or testssl.sh, run from an admin workstation against each listening service, give you a before-and-after picture.

Step 2: disable old protocols

Protocol settings live under HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\<Protocol>\Server and ...\Client. Two DWORD values control each: Enabled and DisabledByDefault.

PowerShell
$base = "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols"
foreach ($p in "SSL 2.0","SSL 3.0","TLS 1.0","TLS 1.1") {
  foreach ($side in "Server","Client") {
    $key = "$base\$p\$side"
    New-Item -Path $key -Force | Out-Null
    Set-ItemProperty -Path $key -Name Enabled -Value 0 -Type DWord
    Set-ItemProperty -Path $key -Name DisabledByDefault -Value 1 -Type DWord
  }
}
foreach ($side in "Server","Client") {
  $key = "$base\TLS 1.2\$side"
  New-Item -Path $key -Force | Out-Null
  Set-ItemProperty -Path $key -Name Enabled -Value 1 -Type DWord
  Set-ItemProperty -Path $key -Name DisabledByDefault -Value 0 -Type DWord
}

At scale, deploy the same values with Group Policy Preferences registry items or an Intune remediation, and reboot. Disable the Server side first on servers you have inventoried; disable the Client side once you know the machine does not connect out to legacy services. Microsoft security baselines do not manage these keys, so this is one of the settings you add yourself.

Step 3: remove weak ciphers and key exchange

Cipher switches are under ...\SCHANNEL\Ciphers\<Cipher> with Enabled = 0:

KeyWhy
NULLNo encryption
DES 56/56Trivially brute-forced
RC2 40/128, RC2 56/128, RC2 128/128Obsolete
RC4 40/128, RC4 56/128, RC4 64/128, RC4 128/128Biased keystream
Triple DES 16864-bit block, SWEET32

For Diffie-Hellman, set ServerMinKeyBitLength = 2048 (DWORD, value 0x800) under ...\SCHANNEL\KeyExchangeAlgorithms\Diffie-Hellman. Most modern suites use ECDHE anyway, but this stops a downgrade to weak DH groups.

Several key names contain a slash, which PowerShell's registry provider handles poorly. Create them with a .reg file, Group Policy Preferences, or the .NET registry API rather than New-Item.

Step 4: set the cipher suite order

The cipher suite order decides which suites Schannel offers and in what priority. Configure it with Group Policy: Computer Configuration > Policies > Administrative Templates > Network > SSL Configuration Settings > SSL Cipher Suite Order. The value is a single comma-separated list; the policy text box is limited to 1,023 characters, so list only what you want, strongest first. A reasonable TLS 1.2 list for servers:

Text
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

Enter it without line breaks. On Windows 11 and Server 2022 and later, add the TLS 1.3 suites (TLS_AES_256_GCM_SHA384, TLS_AES_128_GCM_SHA256) at the top if you manage the order by policy, or they may be left out. The companion setting ECC Curve Order in the same folder sets curve preference.

The TLS PowerShell module shows and edits the effective list locally:

PowerShell
Get-TlsCipherSuite | Format-Table Name, Protocols
Disable-TlsCipherSuite -Name "TLS_RSA_WITH_3DES_EDE_CBC_SHA"
Get-TlsEccCurve

When the Group Policy setting is present, it wins over local changes made with these cmdlets. Manage the order in one place only.

Keep a fallback in mind: if you remove all non-ECDHE suites, some older clients and appliances that only do TLS_RSA_WITH_AES_* break. Decide consciously, based on the inventory from step 1.

Step 5: make .NET Framework use strong crypto

.NET Framework applications built against older targets may pin themselves to TLS 1.0 regardless of Schannel. Two values fix that for both 64-bit and 32-bit runtimes:

PowerShell
$paths = "HKLM:\SOFTWARE\Microsoft\.NETFramework\v4.0.30319",
         "HKLM:\SOFTWARE\WOW6432Node\Microsoft\.NETFramework\v4.0.30319",
         "HKLM:\SOFTWARE\Microsoft\.NETFramework\v2.0.50727",
         "HKLM:\SOFTWARE\WOW6432Node\Microsoft\.NETFramework\v2.0.50727"
foreach ($p in $paths) {
  if (Test-Path $p) {
    Set-ItemProperty $p -Name SchUseStrongCrypto -Value 1 -Type DWord
    Set-ItemProperty $p -Name SystemDefaultTlsVersions -Value 1 -Type DWord
  }
}

SystemDefaultTlsVersions lets the OS choose the protocol, and SchUseStrongCrypto removes weak protocols and ciphers from .NET's own defaults. Applications that hardcode SecurityProtocolType.Tls still need a code change. Modern .NET (5 and later) uses the OS defaults already.

Step 6: roll out in rings

Schannel changes are global to the machine and need a reboot, so a failed change takes every TLS service on that host down at once. Roll out by risk, not by convenience:

RingScopeWhat to change
1Admin workstations, IT test serversEverything: protocols, ciphers, order, .NET
2WorkstationsSSL and weak ciphers off; TLS 1.0/1.1 client side off; .NET strong crypto
3Web and application servers you inventoriedServer-side TLS 1.0/1.1 off, cipher order
4Domain controllers, AD FS, Exchange, SQL ServerSame, one server at a time, after vendor and app checks
5ExceptionsIsolated, documented, with an end date

For each ring, capture the scan result and the Schannel error count before and after. Put a rollback ready to go: a GPO or script that sets Enabled back to 1 for the specific protocol, not a wholesale restore of the SCHANNEL key.

Exceptions are normal. An old appliance that only speaks TLS 1.0 is better handled by isolating it on its own network segment behind a proxy that terminates modern TLS than by keeping TLS 1.0 enabled on the servers it talks to.

What breaks

  • Old SQL Server builds and client drivers that predate TLS 1.2 support. Patch SQL Server and update drivers (ODBC, OLE DB) first.
  • Printers, scanners and appliances sending mail or querying LDAPS.
  • Old RDP clients on unpatched systems, when TLS 1.0 is off on RDP hosts.
  • Third-party software with embedded Java or OpenSSL that hardcodes TLS 1.0.
  • Management tools that connect to WinRM over HTTPS or to WSUS from old OS versions.

Verify it

  1. From outside: rerun the scan from step 1. TLS 1.0 and 1.1 handshakes must fail; only your chosen suites are offered.
  2. On the host: Get-TlsCipherSuite returns only the expected suites; the registry keys match the table above.
  3. Logs: keep Schannel EventLogging at 1 in production and alert on spikes in Schannel error events after each change ring.
  4. Applications: run the smoke tests of your inventory list, not just a browser check; browsers do not use these settings.

Checklist

  • TLS 1.0/1.1 users inventoried via Schannel events, IIS logs and scans
  • SSL 2.0/3.0 disabled everywhere; TLS 1.0/1.1 disabled server side, then client side
  • NULL, DES, RC2, RC4 and 3DES disabled; DH minimum 2048 bits
  • Cipher suite order set once, by GPO, ECDHE with AES-GCM first
  • .NET SchUseStrongCrypto and SystemDefaultTlsVersions set in 32- and 64-bit keys
  • Servers rebooted and rescanned after each ring
  • Exceptions documented with an owner and an end date

Strong TLS protects the channels other controls depend on, such as WinRM over HTTPS and Remote Desktop. Check it again after every baseline refresh described in the security baselines guide.

Frequently asked questions

Does disabling TLS 1.0 and 1.1 in Schannel affect browsers?

Mostly no. Chrome, Edge and Firefox use their own TLS stacks and already refuse TLS 1.0 and 1.1 by default. Schannel settings affect Windows components and applications that use the Windows TLS stack: IIS, RDP, LDAPS, SMTP in Exchange, SQL Server, WinHTTP clients, PowerShell and most .NET Framework applications. Those are the systems to inventory and test.

Is a reboot needed after changing Schannel settings?

Yes. Protocol and cipher registry values under the SCHANNEL key are read when the security subsystem starts, so plan a restart for every server you change. The cipher suite order set by Group Policy also applies after a restart. Stage changes in maintenance windows and verify from outside after each reboot rather than trusting the registry alone.

Should I enable TLS 1.3 on Windows Server?

TLS 1.3 is supported and enabled by default for Schannel on Windows Server 2022 and later and on Windows 11. Leave it on. It removes weak options entirely and completes handshakes faster. Older servers such as Windows Server 2019 do not support TLS 1.3 in Schannel, so TLS 1.2 with a strong cipher suite order remains their ceiling.

TLS and Schannel hardening on Windows

Related guides