命令行工具
Could not create SSL/TLS secure channel:PowerShell 修法
The request was aborted: Could not create SSL/TLS secure channel.The request was aborted: Could not create SSL/TLS secure channel. 的意思是:Windows PowerShell(或其他 .NET Framework 程序)没能和服务器完成 TLS 握手。 大多数情况是当前会话只提供 SSL 3 或 TLS 1.0,而服务器要求 TLS 1.2 及以上。按微软支持的方式打开 TLS 1.2 即可。问题不在证书上,关闭证书检查没有用。
这条报错是什么意思
这是 .NET Framework 的 TLS 握手失败异常。在 .NET Framework 里,HttpWebRequest、WebClient,以及 Windows PowerShell 5.1 的 Invoke-WebRequest、Invoke-RestMethod,握手失败时会抛出状态为 SecureChannelFailure 的 WebException。它的文字由参考源码中的两条字符串拼成:“The request was aborted: {0}.”和“Could not create SSL/TLS secure channel”,于是你看到:
Invoke-WebRequest : The request was aborted: Could not create SSL/TLS secure channel.
.NET Framework 把 TLS 交给 Windows 的 Schannel 处理:操作系统版本决定能用哪些协议,.NET Framework 的设置决定进程实际提供哪些。微软的说明是,面向 .NET Framework 4.7 及以上的程序使用操作系统默认值;面向更老框架版本的进程,或者没有设置 SchUseStrongCrypto、SystemDefaultTlsVersions 注册表项的机器,可能只提供老协议。
证书信任失败的报错不一样:Could not establish trust relationship for the SSL/TLS secure channel.。如果你看到的是这条,说明协议协商成功了,是服务器证书被拒绝,见 .NET remote certificate is invalid。
跑了好几年的脚本突然报错,通常是对方服务器关闭了 TLS 1.0 和 1.1,脚本本身没变。TLS 1.0、1.1 已被 RFC 8996 正式废弃,服务器和云服务陆续只保留 TLS 1.2 和 1.3,而老机器上的 Windows PowerShell 默认可能还只提供 TLS 1.0。排查时先看本机会话提供哪些协议,再看服务器接受哪些协议。
常见原因(按出现频率排序)
这个报错有 5 种常见原因,排第一的是当前会话没有提供 TLS 1.2。
1. 当前会话没有提供 TLS 1.2
- 确认:
[Net.ServicePointManager]::SecurityProtocol
$PSVersionTable.PSVersion
输出 Ssl3, Tls 说明没有提供 TLS 1.2;输出 SystemDefault 或包含 Tls12,则不是这个原因。
- 修复: 为当前会话开启 TLS 1.2,或者通过注册表整机开启(命令见下文)。
2. Windows 版本不支持服务器要求的东西
微软的 Schannel 支持表显示:Windows 7 和 Server 2008 R2 上 TLS 1.1、1.2 默认禁用;TLS 1.3 从 Windows 11 和 Windows Server 2022 才开始支持。服务器只接受 TLS 1.3,或只开放老版 Windows 没有的加密套件,就连不上。
- 确认: 用 SSL 检测工具查看服务器支持的协议和套件;客户端上运行
Get-TlsCipherSuite | Select-Object Name(Windows 10 / Server 2016 及以上)。 - 修复: 在老系统上为 Schannel 开启 TLS 1.2;请服务器管理员保留 TLS 1.2 和 ECDHE-GCM 套件;或者升级 Windows。
3. 安全加固时禁用了 Schannel 协议
安全基线和加固工具会在 HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client 下写入 Enabled=0。
- 确认:
Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client' -ErrorAction SilentlyContinue
4. 服务器要求客户端证书
双向 TLS 时,没有提供客户端证书,或者运行 PowerShell 的账户读不了证书私钥,握手都会失败。用 -Certificate 参数传入证书,并在 certlm.msc 里检查私钥权限。
5. 代理或防火墙干扰
同样的命令换个网络就正常,说明是代理或防火墙掐断了握手。读取 Schannel 写入“系统”事件日志的记录,见 Windows Schannel 报错。
分平台修复命令
所有修法的目标都是让进程提供 TLS 1.2:临时改当前会话,或者用注册表对整机生效。
Windows PowerShell 5.1,仅当前会话:
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
Invoke-WebRequest https://example.com/ -UseBasicParsing
整机,对所有 .NET Framework 4.x 程序生效(管理员 PowerShell,之后重启受影响的程序):
$keys = 'HKLM:\SOFTWARE\Microsoft\.NETFramework\v4.0.30319',
'HKLM:\SOFTWARE\WOW6432Node\Microsoft\.NETFramework\v4.0.30319'
foreach ($k in $keys) {
New-ItemProperty -Path $k -Name SchUseStrongCrypto -Value 1 -PropertyType DWord -Force | Out-Null
New-ItemProperty -Path $k -Name SystemDefaultTlsVersions -Value 1 -PropertyType DWord -Force | Out-Null
}
微软把这两项设为 1 列为最安全的取值。改动会影响这台机器上所有 .NET Framework 程序,改完要测试业务系统。
老版 Windows(7 / Server 2008 R2):为 Schannel 客户端开启 TLS 1.2:
$p = 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client'
New-Item -Path $p -Force | Out-Null
New-ItemProperty -Path $p -Name Enabled -Value 1 -PropertyType DWord -Force | Out-Null
New-ItemProperty -Path $p -Name DisabledByDefault -Value 0 -PropertyType DWord -Force | Out-Null
改完重启。这些系统已经停止支持,应该安排替换。
PowerShell 7(pwsh): 它的 Web cmdlet 基于 HttpClient,使用操作系统默认值。确实需要限制版本时用 -SslProtocol:
Invoke-RestMethod https://example.com/api -SslProtocol Tls12
在 PowerShell 7 里出错时,报错会变成 The SSL connection could not be established 那一类 .NET 消息。
国内常见场景: 不少单位的老服务器上还跑着多年前写的 PowerShell 脚本,对接的第三方接口一旦关闭 TLS 1.0/1.1,这些脚本就会突然报这个错。最省事的办法是在这些机器上统一设置上面两组注册表项;能升级到 PowerShell 7 的,顺手迁移过去。
不推荐:关闭证书校验
Windows PowerShell 里的 [Net.ServicePointManager]::ServerCertificateValidationCallback = { $true },或 PowerShell 7 的 -SkipCertificateCheck,修不了协议问题,却会让会话中的每个请求都接受伪造证书。微软自己的 -SkipCertificateCheck 文档就写着它不安全,只适用于测试时访问使用自签名证书的已知主机。也不要为了“兼容”把 Ssl3 或 Tls 加进 SecurityProtocol,那等于重新启用已废弃的协议。
更安全的替代办法:提供 TLS 1.2(会话里加一行,或者改注册表);能用 SystemDefault 就用;升级或替换不支持 TLS 1.2 的系统;证书信任问题靠安装正确的根证书解决,而不是跳过检查。
怎么确认已经修好
修好的标志是会话提供 TLS 1.2,请求返回 HTTP 状态码而不是抛异常。
[Net.ServicePointManager]::SecurityProtocol
(Invoke-WebRequest https://example.com/ -UseBasicParsing).StatusCode
第一行应显示包含 Tls12(改完注册表、新开 PowerShell 窗口后则可能显示 SystemDefault),请求应返回 200 或其他 HTTP 状态码,而不是抛异常。TLS 1.3 带来的变化见 TLS 1.3 详解;服务器归你管的话,用 TLS 配置生成器生成一份新老客户端都能用的配置。
如果改完注册表还是不行,打开“事件查看器 → Windows 日志 → 系统”,筛选来源为 Schannel 的事件,里面通常会写明握手失败时的告警类型,可以判断是协议不匹配、加密套件不匹配还是证书问题。修好之后,把脚本里临时加的证书回调代码删掉。
常见问题
Could not create 和 Could not establish trust relationship 有什么区别?
Could not create SSL/TLS secure channel 是握手失败:协议、加密套件、客户端证书或连接被断开。Could not establish trust relationship for the SSL/TLS secure channel 表示协议协商成功了,但服务器证书不被信任。前者要改协议设置,后者要处理证书。
每个脚本都要加 ServicePointManager 那一行吗?
不必长期这样做。在老机器上跑脚本时,这是一个合理的临时办法。长久之计是设置注册表项 SchUseStrongCrypto 和 SystemDefaultTlsVersions,让这台机器上所有 .NET Framework 程序都使用操作系统默认值,或者把脚本迁移到 PowerShell 7。
同一台 Windows 服务器上浏览器能打开,为什么?
浏览器有自己的 TLS 设置,不受 .NET Framework 默认值影响,会直接启用 TLS 1.2 和 1.3。Windows PowerShell 5.1 用的是 .NET Framework 的 ServicePointManager,它提供哪些协议,取决于进程面向的框架版本和注册表设置。
会不会是服务器的问题?
会。如果服务器只接受 TLS 1.3,Windows 10 和 Windows Server 2019 连不上,因为 Schannel 从 Windows 11 和 Windows Server 2022 起才支持 TLS 1.3。服务器只开放老版 Windows 不支持的加密套件,也会报同样的错。可以用 SSL 检测工具检查服务器。
资料来源
- Microsoft Learn: TLS best practices with .NET Framework
- Microsoft Learn: Protocols in TLS/SSL (Schannel SSP)
- Microsoft Learn: Invoke-WebRequest (SslProtocol, SkipCertificateCheck)
- Microsoft Learn: Differences between Windows PowerShell 5.1 and PowerShell 7.x
- Microsoft Learn: WebExceptionStatus enum (SecureChannelFailure, TrustFailure)