【问题标题】:Azure, ASP.NET Core 2.0, Invoking Post with HttpClient using a Client Certificate results in "The client certificate credentials were not recognized"Azure、ASP.NET Core 2.0、使用客户端证书使用 HttpClient 调用 Post 导致“无法识别客户端证书凭据”
【发布时间】:2018-07-11 01:50:45
【问题描述】:

我正在尝试从 ASP.NET Core (2.0.2) Web API(在控制器内)调用第三方基于 HTTP 的 API。

在非 Azure 环境(Windows 7 Box)中运行时成功。 在 Azure 中的应用服务中运行时失败,并出现错误“无法识别客户端证书凭据”。 环境之间的代码和证书是相同的。 两者都在 IIS 中运行。

我已缩减代码以隔离我的问题,如下所示。出于显而易见的原因,我在这里更改了密码和 URL 详细信息。

[HttpGet]
public async Task<IActionResult> Get()
{
    string response = null;

    using (HttpClientHandler handler = new HttpClientHandler())
    {
        handler.ClientCertificateOptions = ClientCertificateOption.Manual;
        handler.SslProtocols = SslProtocols.Tls12;
        handler.ClientCertificates.Add(new X509Certificate2("Certificate/Cert.pfx", "<password-removed>"));
        using (HttpClient client = new HttpClient(handler))
        {
            using (HttpResponseMessage responseMessage = await client.PostAsync("https://some-domain.com/action.asp?sourceid=123&key=10101", null))
            {
                response = await responseMessage.Content.ReadAsStringAsync();
            }
        }
    }

    return Ok(response);
}

产生的异常和调用栈如下:

System.Net.Http.HttpRequestException:发送时出错 请求。 ---> System.Net.Http.WinHttpException:客户端证书凭证在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 在 System.Threading.Tasks.RendezvousAwaitable1.GetResult() 在 System.Net.Http.WinHttpHandler.d__105.MoveNext() --- 内部异常堆栈跟踪结束 --- 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 System.Runtime.CompilerServices.ConfiguredTaskAwaitable1.ConfiguredTaskAwaiter.GetResult() 在 System.Net.Http.HttpClient.d__58.MoveNext() --- 从之前抛出异常的位置结束堆栈跟踪 ---\TestController.cs:line 32

另一个有趣的事情是,我可以使用 CURL 在 Azure 应用服务控制台中成功执行此 POST,如下所示。此处使用的 .pem 文件是从 C# 代码中使用的 .pfx 文件生成的。

curl -s --data "" --cert .\Cert.pem:<password-removed> "https://some-domain.com/action.asp?sourceid=123&key=10101"

更新

我已经重构了代码库以简化问题的重复。我现在正在使用一个控制台应用程序,它通过 Kudu 上传到 Azure 中的应用服务并在 Kudu 控制台中运行。它失败了,和上面一样。

static void Main(string[] args)
{
    Console.WriteLine("Starting v3...");
    string response = null;

    try
    {
        using (HttpClientHandler handler = new HttpClientHandler())
        {
            handler.ClientCertificateOptions = ClientCertificateOption.Manual;
            handler.SslProtocols = SslProtocols.Tls12;
            Console.WriteLine("Loading Cert...");
            var cert = new X509Certificate2(certFilePath, certPassword);
            Console.WriteLine("Verifying Cert...");
            bool result = cert.Verify();
            Console.WriteLine($"Verified Cert: {result}"); // Variable result is 'True'here.
            handler.ClientCertificates.Add(cert);

            using (HttpClient client = new HttpClient(handler))
            {
                HttpContent content = new System.Net.Http.StringContent("");
                Console.WriteLine("Posting...");
                using (HttpResponseMessage responseMessage = client.PostAsync(url, content).Result) //  FAILS HERE!
                {
                    Console.WriteLine("Posted...");
                    Console.WriteLine("Reading Response...");
                    response = responseMessage.Content.ReadAsStringAsync().Result;
                    Console.WriteLine($"Response: {response}");
                }
            }
        }
    }
    catch (Exception exc)
    {
        Console.WriteLine("BOOM!!!");
        exc = LogException(exc);
    }

    Console.WriteLine("Done!");
    Console.ReadLine();
}

请注意:我知道这是不寻常的,因为我正在执行带有查询参数且没有实际正文的 POST,但这部分不在我的控制范围内 - 它由第三部分决定 -派对。我没有怀疑这是我的问题的一个因素,但我在这里可能大错特错。

我在这方面花了很多时间,结果碰壁了。

【问题讨论】:

    标签: c# azure asp.net-core certificate httpclient


    【解决方案1】:

    您是否已将他们的服务器证书添加到您的证书存储中?客户端证书用于相互身份验证情况,您向他们发送证书以代表您。如果他们的证书通过了“众所周知”测试,则不会有信任问题,但如果他们有自签名证书,您必须获取他们的证书并将其导入您的证书存储。

    【讨论】:

    • 我们目前正在从 Azure 中的文件系统加载证书。它正在代码中成功加载证书。在相同的环境中,通过 Azure 控制台使用完全相同的证书,我可以向第三方执行 CURL,并在没有错误的情况下返回预期的响应。此代码按原样在 Azure 之外运行。事实上,我已经直接从 Azure Kudu 下载了应用程序的所有内容,没有进行任何更改,并将其放在 IIS 中的另一个盒子上,它就可以工作了。
    • curl、soapUI 和 postman 等工具无法很好地解决证书问题,因为它们通常设置为信任所有证书。
    【解决方案2】:

    解决方案比预期的要容易得多。我需要带有指纹的 WEBSITE_LOAD_CERTIFICATES 键作为 Azure 应用服务应用程序设置中的值,但只有在 Web 服务器的上下文中运行时才会获取该值。所以我用来隔离问题的控制台应用程序只会让我更加痛苦,因为它看不到这些设置。

    这篇文章让我得到了这个修复。

    https://docs.microsoft.com/en-us/azure/app-service/app-service-web-ssl-cert-load

    【讨论】:

      猜你喜欢
      • 2019-08-25
      • 1970-01-01
      • 1970-01-01
      • 2018-05-27
      • 1970-01-01
      • 2015-04-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多