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.
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.
| Protocol | Status | Action |
|---|---|---|
| SSL 2.0, SSL 3.0 | Broken | Disable everywhere |
| TLS 1.0, TLS 1.1 | Deprecated (RFC 8996) | Disable after inventory |
| TLS 1.2 | Current | Enable, with a strong cipher suite order |
| TLS 1.3 | Current (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\SCHANNELwithEventLogging(DWORD). The default1logs errors only;7logs 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_PROTOCOLandCRYPT_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-ciphersscript 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.
$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:
| Key | Why |
|---|---|
NULL | No encryption |
DES 56/56 | Trivially brute-forced |
RC2 40/128, RC2 56/128, RC2 128/128 | Obsolete |
RC4 40/128, RC4 56/128, RC4 64/128, RC4 128/128 | Biased keystream |
Triple DES 168 | 64-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:
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_SHA256Enter 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:
Get-TlsCipherSuite | Format-Table Name, Protocols
Disable-TlsCipherSuite -Name "TLS_RSA_WITH_3DES_EDE_CBC_SHA"
Get-TlsEccCurveWhen 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:
$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:
| Ring | Scope | What to change |
|---|---|---|
| 1 | Admin workstations, IT test servers | Everything: protocols, ciphers, order, .NET |
| 2 | Workstations | SSL and weak ciphers off; TLS 1.0/1.1 client side off; .NET strong crypto |
| 3 | Web and application servers you inventoried | Server-side TLS 1.0/1.1 off, cipher order |
| 4 | Domain controllers, AD FS, Exchange, SQL Server | Same, one server at a time, after vendor and app checks |
| 5 | Exceptions | Isolated, 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
- From outside: rerun the scan from step 1. TLS 1.0 and 1.1 handshakes must fail; only your chosen suites are offered.
- On the host:
Get-TlsCipherSuitereturns only the expected suites; the registry keys match the table above. - Logs: keep Schannel
EventLoggingat1in production and alert on spikes in Schannel error events after each change ring. - 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
SchUseStrongCryptoandSystemDefaultTlsVersionsset 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