仅在一台特定计算机上的 .NET 应用程序"The message received was unexpected or badly formatted" SSL 错误



我有一个.NET Core 3.1 C#应用程序,它通过HTTPS调用API(并将其公钥作为获取令牌的一部分,因为该证书稍后用于解密单独发送回的信息)。在我们几乎所有的机器上,它都在工作,但在一台Windows 8.1机器上,当我们尝试最初连接身份验证令牌时,我们会遇到以下一系列异常:

The SSL connection could not be established, see inner exception.
---> System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception.
---> System.ComponentModel.Win32Exception (0x80090326): The message received was unexpected or badly formatted.

异常是从System.Net.Http.HttpClient.FinishSendAsyncBuffered抛出的,所以我怀疑它发生在HTTPS级别,而且我们的证书内容在这里并不真正相关。

我们获取令牌的代码如下:

身份验证服务的构造函数:

public XXXXAuthService(IXXDbService dbService, XXXXApiConfig config)
{
_dbService = dbService;
_config = config;

// try forcing TLS1.2 for SSL connection exceptions thrown in some operating environments
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

_httpClient = new HttpClient {BaseAddress = new Uri(config.BaseUrl)};
_httpClient.DefaultRequestHeaders.Accept.Clear();
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}

获取身份验证令牌的代码:

private async Task<string> GetXXXXBearerToken(string userId, DateTime creationTime)
{
var token = await GenerateProviderJwtForXXXX(userId, creationTime);
var kvp = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("grant_type", "urn:ietf:params:oauth:grant-type:token-exchange"),
new KeyValuePair<string, string>("subject_token", token),
new KeyValuePair<string, string>("subject_token_type", "urn:ietf:params:oauth:token-type:jwt")
};
var data = new FormUrlEncodedContent(kvp);
var publicKey = await GetXXXXPublicKey();
_httpClient.DefaultRequestHeaders.Remove("X-XXXX-Public-Cert");
_httpClient.DefaultRequestHeaders.Add("X-XXXX-Public-Cert", publicKey);
var response = await _httpClient.PostAsync("Identity/token", data);
if (!response.IsSuccessStatusCode)
throw new Exception("XXXX Token Server Error: " + response.ReasonPhrase);
var result = await response.Content.ReadAsStringAsync();
var authResponse = JsonConvert.DeserializeObject<OAuthResponse>(result);
if (!string.IsNullOrEmpty(authResponse.access_token))
return authResponse.access_token;
System.Diagnostics.Trace.WriteLine("Token Exchange Result: " + result);
if (!string.IsNullOrEmpty(authResponse.error))
{
var outcome = new XXX.XXXX.Model.OperationOutcome();
outcome.Issue.Add(new XXX.XXXX.Model.OperationOutcome.IssueComponent()
{
//some code to throw an error is here
}
throw new XXX.XXXX.Rest.XXXXOperationException("Bearer Token Exchange failed", response.StatusCode);
}

不幸的是,对于这个特定的错误,Stack Overflow或其他网站上现有的任何问题/建议似乎都没有帮助。它们主要是关于客户端和服务器之间的版本差异,而这里的情况似乎并非如此,因为我正在强制TLS 1.2(它是活动的,并在出现故障的机器上启用)。

有趣的是,我可以通过HTTPS在浏览器中访问服务器URL,这表明问题出在我的代码上,而不是机器上,但它在其他地方都能工作。

我已经确认:

  • 我用于在计算机上验证连接的证书是有效的,并且具有信任链(尽管如上所述,我认为我们还没有走到TLS连接本身失败的地步)
  • 我们正在调用的服务器支持TLS 1.2(通过强制)
  • 我可以通过浏览器独立访问URL的网站

我需要在代码或机器上做些什么才能让这个调用在任何地方工作吗?

我试图解决的问题

  • 目前正在安装所有Windows 8.1更新
  • 在代码中强制TLS 1.2(请参阅上面的代码示例)
  • 仅将VM限制为TLS 1.2

我至少可以为您指明正确的方向…

相同的症状
我有一个在IIS(Windows Server 2012 R2)上运行的.NET Core 3.1 web应用程序,当它尝试使用TLS 1.2连接到另一台服务器时,遇到了完全相同的错误和堆栈竞争。我还出现了可以连接浏览器(Chrome)的症状,但无法连接应用程序。(不过,看看Internet Explorer浏览器是否正常工作会很有趣。)

根本原因
TLS握手失败,因为两台服务器无法就通用的密码套件达成一致。(使用Wireshark,我发现当我的应用程序尝试连接时,它提供的密码套件比Chrome浏览器调用时更有限。)

解决方案
在我的案例中,我使用了IIS Crypto(一个小型免费工具:https://www.nartac.com/Products/IISCrypto/)在我的web应用程序服务器上启用额外的密码套件。我下载并运行了IIS Crypto,在其"密码套件"选项卡上选中了其他密码套件,然后重新启动了机器。

其中一个新的密码套件可以与我的应用程序和目标服务器配合使用,因此TLS握手成功,错误也得到了解决。

一个简单的警告:有些密码套件比其他密码套件更安全,所以您需要了解最佳实践。

附录
如果您想进一步诊断故障,我建议安装Wireshark(另一个免费工具:https://www.wireshark.org/#download)在计算机上使用.NET Core应用程序。如果TLS握手失败是问题所在,您将看到类似以下消息:警报(级别:致命,描述:握手失败)

这篇关于wireshark输出的入门文章帮助了我:https://blog.catchpoint.com/2017/05/12/dissecting-tls-using-wireshark/

我遇到了一个模拟问题,为了帮助其他人,我得出了以下结论:

成功执行此代码并不意味着您的应用程序支持指定的协议版本;SSL错误";在以后尝试建立连接时仍然可能发生:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

在我的案例中,我试图强制Tls13,但发现我的应用程序配置实际上并不支持它:

  • net core 3.0Windows Server Datacenter 2019, version 1809上运行

所以我不得不将我的配置更改为以下内容,为我需要的协议版本提供支持:

Windows Server Datacenter 2022, OS build 20348.288上的Net framework 5.0

我试图连接到一个端点,该端点突然放弃了对Tls1.2的支持(不确定原因),从那时起只接受Tls1.3。

我在使用MySql版本8.0.32时遇到了同样的问题,我不得不将其降级为8.0.26

相关内容

最新更新