Browsers and scanners dropped TLS 1.0/1.1 and a long list of RSA-and-CBC suites years ago, yet many IIS boxes still accept them. On Windows Server 2025, Schannel is modern by default, but upgrades, GPO drift, and “temporary” registry edits leave weak protocols enabled. If you host ASP.NET or ASP.NET Core sites, treat TLS as part of the app surface—not something the certificate binding alone fixes.
The practical goal is simple: only TLS 1.2 and TLS 1.3, a short forward-secrecy cipher list, and proof from outside the box that old handshakes fail. Everything below is host-level Schannel work that applies to every IIS site on the machine.
#What to enforce in 2026
For public HTTPS endpoints serving .NET apps, lock the policy to:
- Protocols: TLS 1.2 and TLS 1.3 only (disable SSL 2.0/3.0 and TLS 1.0/1.1 for both Server and Client keys).
- Key exchange: prefer ECDHE; avoid plain RSA key exchange suites.
- Bulk ciphers: AES-GCM (and ChaCha20-Poly1305 where offered); drop 3DES, RC4, and most CBC suites.
- Certificates: SHA-256+ signatures, 2048-bit RSA minimum or ECDSA P-256/P-384; bindings still use SNI as usual.
Windows Server 2025 already favors TLS 1.3 and strong suites out of the box. Your job is to remove exceptions introduced by older images, third-party installers, or copied hardening scripts that re-enabled legacy protocols “for compatibility.”
#Inventory before you change anything
On the IIS host, list what Schannel will actually offer. Run this in an elevated PowerShell session:
Get-TlsCipherSuite |
Select-Object Name, Certificate, Exchange, Cipher, Hash, Directory |
Format-Table -AutoSize
Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\*\*' |
Select-Object PSPath, Enabled, DisabledByDefault
Note any TLS_RSA_* (no forward secrecy), *_3DES_*, *_RC4_*, and *_CBC_* entries still enabled. Also confirm whether TLS 1.0 or 1.1 Server keys still show Enabled=1. Document the before state so you can roll back a single suite if a legacy integration partner breaks.
#Disable legacy protocols and weak suites
Prefer the TLS cmdlets for cipher suites; use explicit Schannel protocol keys when you must force Server/Client off. Example pattern—disable a known-weak suite and ensure TLS 1.2 Server is on:
# Drop obsolete suites (repeat per Name you identified)
Disable-TlsCipherSuite -Name 'TLS_RSA_WITH_3DES_EDE_CBC_SHA' -ErrorAction SilentlyContinue
Disable-TlsCipherSuite -Name 'TLS_RSA_WITH_AES_128_CBC_SHA' -ErrorAction SilentlyContinue
Disable-TlsCipherSuite -Name 'TLS_RSA_WITH_AES_256_CBC_SHA' -ErrorAction SilentlyContinue
# TLS 1.2 Server present and enabled
$p12 = 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server'
New-Item -Path $p12 -Force | Out-Null
New-ItemProperty -Path $p12 -Name 'Enabled' -Value 1 -PropertyType DWord -Force | Out-Null
New-ItemProperty -Path $p12 -Name 'DisabledByDefault' -Value 0 -PropertyType DWord -Force | Out-Null
# TLS 1.0 Server off (mirror for Client and for TLS 1.1)
$p10 = 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server'
New-Item -Path $p10 -Force | Out-Null
New-ItemProperty -Path $p10 -Name 'Enabled' -Value 0 -PropertyType DWord -Force | Out-Null
New-ItemProperty -Path $p10 -Name 'DisabledByDefault' -Value 1 -PropertyType DWord -Force | Out-Null
# Reboot or restart dependent services after protocol key changes
Write-Host 'Protocol changes require a reboot to apply cleanly.'
Apply the same Enabled=0 / DisabledByDefault=1 pattern for SSL 2.0, SSL 3.0, and TLS 1.1 under both Server and Client. Keep TLS 1.3 enabled (Server 2025 default). After protocol registry edits, plan a maintenance reboot; cipher-suite Disable-TlsCipherSuite changes are usually live immediately for new connections but still verify after an IIS reset.
Order matters for clients that do not speak TLS 1.3. Put ECDHE-ECDSA and ECDHE-RSA GCM suites first. You can reorder with Disable-TlsCipherSuite / Enable-TlsCipherSuite in the sequence you want, or manage order via your standard image baseline so every Windows host matches.
#IIS-side checks that still matter
Schannel is machine-wide, but a few IIS settings interact with what clients experience:
- Site bindings: HTTPS + correct cert, SNI host name set; no leftover HTTP-only host headers for admin endpoints you think are TLS-only.
- Require SSL at the site or application level when the app should never answer cleartext (IIS Manager → SSL Settings, or web.config system.webServer/security/access sslFlags).
- HSTS belongs in the app or URL Rewrite—not in Schannel—but only enable it after you know HTTPS works for every hostname on the site.
- Outbound calls from ASP.NET (payment APIs, webhooks) use the same Schannel Client settings; disabling TLS 1.0 Client can break ancient upstreams—test those paths too.
For an app-only push toward HTTPS without waiting on DNS cutover, a minimal rewrite rule can redirect HTTP→HTTPS once certificates and bindings are correct. Keep that rule out of the discussion until TLS negotiation itself is clean; otherwise you mask handshake failures behind redirect noise.
#Verify from outside the host
Do not trust the registry alone. From a separate machine, confirm old protocols fail and modern ones succeed:
# Expect failure on TLS 1.0 / 1.1 after hardening
try {
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls
Invoke-WebRequest -Uri 'https://your-site.example' -UseBasicParsing | Out-Null
'TLS1.0 unexpectedly succeeded'
} catch { 'TLS1.0 blocked (good): ' + $_.Exception.Message }
# Modern default stack should succeed
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::SystemDefault
(Invoke-WebRequest -Uri 'https://your-site.example' -UseBasicParsing).StatusCode
Follow with a public scanner or an internal openssl s_client pass against each hostname on the box (multi-site IIS hosts often mix old and new certs). Watch Windows Event Log under System for Schannel errors after you cut weak suites—failed handshakes from corporate crawlers show up quickly.
#Rollout pattern for shared and VPS IIS hosts
Change one non-production host first. Keep a short allowlist only if a named integration still requires a single CBC suite—and ticket a removal date. Bake the final Get-TlsCipherSuite output into your golden image so new Windows Server 2025 instances do not regress. For multi-tenant IIS, remember protocol policy is per machine: one customer asking for TLS 1.0 affects every site on that server, which is why the answer is usually “no” and a move to a dedicated instance if they truly cannot upgrade.
Practical takeaway: on Windows Server 2025 IIS, export your current cipher list, disable TLS 1.0/1.1 and non-forward-secret suites with the TLS cmdlets plus Schannel protocol keys, reboot once, then prove from an external client that only TLS 1.2+ connects. Re-check after every OS image update so ASP.NET sites keep negotiating clean, modern HTTPS without surprise legacy fallout.
Comments
No comments yet