我有一个 .NET Core 3.1 C# 应用程序,它通过 HTTPS 调用 API(并将其公钥作为获取 token 的一部分,因为该证书稍后用于解密单独发回的信息)。在我们几乎所有的机器上,它都在工作,但在一台 Windows 8.1 机器上,当我们尝试初始连接以获取身份验证 token 时,会出现以下一系列异常:
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 级别,而且我们的证书内容在这里并不真正相关。我们获取 token 的代码如下所示:
身份验证服务的构造函数:
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"));
}
获取授权 token 的代码: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,这表明我的代码存在问题而不是机器,但它在其他任何地方都可以正常工作。
我已经确认:
我需要在代码中或机器上做些什么来让这个调用在任何地方都能工作吗?
我尝试解决的问题
最佳答案
我至少可以为您指明正确的方向……
相同的症状
我有一个在 IIS(Windows Server 2012 R2)上运行的 .NET Core 3.1 Web 应用程序,当它尝试使用 TLS 1.2 连接到另一台服务器时,它得到了完全相同的错误和堆栈跟踪。我也有可以连接浏览器(Chrome)但不能连接应用程序的症状。 (不过,看看 Internet Explorer 浏览器是否工作会很有趣。)
根本原因
TLS 握手失败,因为两台服务器无法就共同的 达成一致。密码套件 . (使用 Wireshark,我发现当我的应用程序尝试连接时,它提供的密码套件比 Chrome 浏览器调用电话时更有限。)
解决方案
就我而言,我使用了 IIS 加密 (一个小的免费工具:https://www.nartac.com/Products/IISCrypto/)在我的网络应用程序的服务器上启用额外的密码套件。我下载并运行了 IIS Crypto,在其密码套件选项卡上勾选了其他密码套件,然后重新启动了机器。
其中一个新密码套件可与我的应用程序和目标服务器配合使用,因此 TLS 握手成功并解决了错误。
一个快速警告:一些密码套件比其他密码套件更安全,因此您需要阅读最佳实践。
附录
如果您想进一步诊断故障,我建议您在带有 .NET Core 应用程序的机器上安装 Wireshark(另一个免费工具:https://www.wireshark.org/#download)。如果 TLS 握手失败是问题,您将看到如下消息:警报(级别:致命,描述:握手失败)
这本有关wireshark输出的入门书帮助了我:
https://blog.catchpoint.com/2017/05/12/dissecting-tls-using-wireshark/
关于c# - 仅在一台特定机器上的 .NET 应用程序的 SSL 错误 "The message received was unexpected or badly formatted",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63223539/