使用 TLS1.2 连接到 MS Graph - 服务器重新启动时,SecurityProtocol 从 TLS1.2 重置

Connecting to MS Graph using TLS1.2 - SecurityProtocol resets from TLS1.2 when server is rebooted

提问人:PaulH 提问时间:11/6/2023 最后编辑:PaulH 更新时间:11/7/2023 访问量:29

问:

我有一个安装在 Windows Server 2016 上的 C# 程序,并通过 MS Graph 连接到 Exchange Online。但是,每当服务器重新启动时,程序都会停止工作几个小时。设置了一个 Powershell 脚本来调查问题(并执行与 C# 程序相同的操作),该错误似乎是由服务器重新启动时安全协议重置引起的 - 在正常情况下,它默认为 TLS1.2,但在重新启动后它默认为“Ssl3,Tls”。

MS Graph 目前需要使用 TLS 1.2(Microsoft Graph 服务:停用 TLS 1.0 和 1.1,并在 US Gov Cloud 中准备 TLS 1.2)。

Microsoft 最佳做法建议 .NET 应用程序不应对任何特定版本的 TLS 进行硬编码。相反,.NET 应用程序应使用客户端操作系统支持的任何 TLS 版本,这意味着应用程序将在 TLS 的较新版本可用时自动利用它们(.NET Framework 的传输层安全性 (TLS) 最佳做法)。

那么,如何让服务器操作系统在服务器重新启动后继续默认为 TLS1.2?(如果我不应该将其硬编码到 C# 程序中)。 ...

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 脚本的相关部分,该脚本执行与 C# 程序相同的操作。

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 

通常,Powershell 脚本会生成以下输出:

  Tls12
  Get-AccessToken

在服务器重新启动后的几个小时内,Powershell 脚本将生成以下输出:

  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

根据 Microsoft 最佳做法(如上所述),C# 程序和 Powershell 脚本不指定 TLS 的版本。它们在 Windows Server 2016(支持 TLS1.2)上运行,并安装了 .NET Framework 版本 4.8(默认使用 TLS1.2)。

那么,如何让服务器操作系统在服务器重新启动后继续默认为 TLS1.2,就像它通常所做的那样?

Powershell TLS1.2 NET-4.8 Windows服务器-2016

评论

0赞 Mathias R. Jessen 11/7/2023
您链接到的文章已经指定了如何通过 Windows 注册表配置协议默认值?
0赞 PaulH 11/7/2023
对不起,是的,我想我感觉有点被那篇文章中的所有东西蒙蔽了科学......不过,慢慢地,我通过文章中的各种建议取得了成功!设置 HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\。注册表中的 NETFramework\v4.0.30319:SystemDefaultTlsVersions=1 并再次重新启动服务器已经完成了诀窍 - 谢谢!
0赞 PaulH 11/7/2023
实际上,设置该注册表项已使 C# 程序再次运行,但 PowerShell 脚本仍然无法连接到 MS Graph,因为 SecurityProtocol 错误。奇怪!

答: 暂无答案