服务器重启后SecurityProtocol重置,如何默认TLS1.2连接MS Graph?
我有一个部署在Windows Server 2016上的C#程序,通过MS Graph连接Exchange Online。服务器重启后,程序会停止工作数小时。通过PowerShell脚本排查发现,重启后[Net.ServicePointManager]::SecurityProtocol会从默认的TLS1.2重置为Ssl3, Tls,而MS Graph当前要求使用TLS1.2。遵循微软最佳实践,.NET应用不应硬编码TLS版本,需使用系统支持的版本。请问如何让服务器重启后仍默认使用TLS1.2?
当前环境:Windows Server 2016(支持TLS1.2),已安装.NET Framework 4.8(默认使用TLS1.2)。
C#程序重启后报错
System.Net.HttpRequestException: An error occurred while sending the request. -->
System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a send. -->
System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
PowerShell排查脚本
function Get-AccessToken { param( [string] $AppId, [string] $TenantName, [string] $AppSecret) $Scope = "https://graph.microsoft.com/.default" $Url = "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token" # Add System.Web for urlencode Add-Type -AssemblyName System.Web # Create body $Body = @{ client_id = $AppId client_secret = $AppSecret scope = $Scope grant_type = 'client_credentials' } # Splat the parameters for Invoke-Restmethod for cleaner code $PostSplat = @{ ContentType = 'application/x-www-form-urlencoded' Method = 'POST' Body = $Body Uri = $Url } # Request the token! $Request = Invoke-RestMethod @PostSplat return $Request } #ClientID = "..<redacted>.." #DirectoryID = "..<redacted>.." #ClientSecret = "..<redacted>.." #MailboxName = "..<redacted>.." #MailboxFolderName = "Inbox" [Net.ServicePointManager]::SecurityProtocol Write-Output "Get-AccessToken" $Credential = Get-AccessToken -AppId $ClientID -TenantName $DirectoryID -AppSecret $ClientSecret
输出情况
正常输出
Tls12 Get-AccessToken
重启后数小时内输出
Ssl3, Tls Get-AccessToken Invoke-RestMethod : The underlying connection was closed: An unexpected error occurred on a send. At C:\Path\TestMSGraphGetEmails.ps1:37 char:16 + $Request = Invoke-RestMethod @PostSplat + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
要让Windows Server 2016重启后默认使用TLS1.2,需修改系统注册表,强制启用TLS1.2并设置为默认协议,同时禁用不安全的SSL3和TLS1.0。
操作步骤
- 打开注册表编辑器(运行命令
regedit)。 - 导航到注册表路径:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols
禁用不安全协议
禁用SSL 3.0
- 新建子项:
SSL 3.0\Client- 新建DWORD值:
DisabledByDefault,赋值1 - 新建DWORD值:
Enabled,赋值0
- 新建DWORD值:
- 新建子项:
SSL 3.0\Server- 新建DWORD值:
DisabledByDefault,赋值1 - 新建DWORD值:
Enabled,赋值0
- 新建DWORD值:
- 新建子项:
禁用TLS 1.0
- 新建子项:
TLS 1.0\Client- 新建DWORD值:
DisabledByDefault,赋值1 - 新建DWORD值:
Enabled,赋值0
- 新建DWORD值:
- 新建子项:
TLS 1.0\Server- 新建DWORD值:
DisabledByDefault,赋值1 - 新建DWORD值:
Enabled,赋值0
- 新建DWORD值:
- 新建子项:
启用并设置TLS 1.2为默认
- 新建子项:
TLS 1.2\Client- 新建DWORD值:
DisabledByDefault,赋值0 - 新建DWORD值:
Enabled,赋值1
- 新建DWORD值:
- 新建子项:
TLS 1.2\Server- 新建DWORD值:
DisabledByDefault,赋值0 - 新建DWORD值:
Enabled,赋值1
- 新建DWORD值:
配置.NET Framework默认协议(针对.NET 4.5+)
导航到注册表路径:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v4.0.30319
- 新建DWORD值:
SchUseStrongCrypto,赋值1 - 若为64位系统,同时修改路径
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319下的SchUseStrongCrypto为1
- 重启服务器,使所有配置生效。
验证配置
重启后运行PowerShell命令:
[Net.ServicePointManager]::SecurityProtocol
输出应显示Tls12,此时再运行测试脚本即可正常获取MS Graph令牌。
内容的提问来源于stack exchange,提问作者PaulH

