c# - 使用 HttpClient 的 HTTPS 请求失败

标签 c# asp.net-core .net-core x509certificate x509certificate2

我正在使用以下代码并得到 HttpRequestException 异常:

using (var handler = new HttpClientHandler())
{
    handler.ClientCertificateOptions = ClientCertificateOption.Manual;
    handler.SslProtocols = SslProtocols.Tls12;
    handler.ClientCertificates.Add(new X509Certificate2(@"C:\certificates\cert.pfx"));

    // I also tried to add another certificates that was provided to https access 
    // by administrators of the site, but it still doesn't work.
    //handler.ClientCertificates.Add(new X509Certificate2(@"C:\certificates\cert.crt"));
    //handler.ClientCertificates.Add(new X509Certificate2(@"C:\certificates\cert_ca.crt"));

    using (var client = new HttpClient(handler))
    {
        var response = client.GetAsync("https://someurl.com/api.php?arg1=some&arg2=test").GetAwaiter().GetResult();
        // ^ HttpRequestException: An error occurred while sending the request.
    }
}

异常:

WinHttpException: A security error occurred
    System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
    System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
    System.Runtime.CompilerServices.ConfiguredTaskAwaitable+ConfiguredTaskAwaiter.GetResult()
    System.Net.Http.WinHttpHandler+<StartRequest>d__105.MoveNext()

HttpRequestException: An error occurred while sending the request.
    System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
    System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
    System.Runtime.CompilerServices.ConfiguredTaskAwaitable+ConfiguredTaskAwaiter.GetResult()
    System.Net.Http.HttpClient+<FinishSendAsync>d__58.MoveNext()
    System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
    System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
    System.Runtime.CompilerServices.TaskAwaiter.GetResult()
    MyApp.Web.Controllers.HomeController.Test() in HomeController.cs
        var response = client.GetAsync("https://someurl.com/api.php?arg1=some&arg2=test").GetAwaiter().GetResult();
    lambda_method(Closure , object , Object[] )
    Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+<InvokeActionMethodAsync>d__27.MoveNext()

我还尝试将相同的证书导出到 Windows 证书存储并通过 Google Chrome 使用它,它工作正常(浏览器要求我确认安装的证书然后加载资源)。​​

为什么它在我的代码中不起作用?

已更新

我还尝试添加回调来验证证书:

handler.ServerCertificateCustomValidationCallback = (message, certificate2, arg3, arg4) =>
{
    // I set a breakpoint to this point but it is not catched.
    return true;
};

已更新2

证书使用 SHA-1。 Neil Moss 在评论中提到 support for SHA1 certs is being withdrawn . 如果这是它不起作用的真正原因,是否有解决方法?

解决方案

感谢 Neil Moss 提供的解决方案。他提议为 SSL 协议(protocol)使用 Tls 标志。

handler.SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls;

但它还需要以下内容:

handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true;

在我添加这个之后它工作正常。

最佳答案

根据 this SO post ,您必须使用 ServicePointManager 启用 TLS1.2。

System.Net.ServicePointManager.SecurityProtocol |=
    SecurityProtocolType.Tls12 | 
    SecurityProtocolType.Tls11 | 
    SecurityProtocolType.Tls; // comparable to modern browsers

同样值得注意的是,MSDN documentation对于 ServicePointManager.SecurityProtocols 属性作出这样的声明:

The .NET Framework 4.6 includes a new security feature that blocks insecure cipher and hashing algorithms for connections.

这表明某种形式的 SHA1 block 可能就位。

编辑 2020 年 9 月 16 日

我从 = 赋值运算符更改为 |= 运算符,以便对仍然需要 SSL 的任何其他遗留站点的请求将继续有效。

关于c# - 使用 HttpClient 的 HTTPS 请求失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62860775/

相关文章:

c# - 将实现哪个接口(interface)?

c# - JsonReaderException - 解析值时遇到意外字符

.net-core - Scaffold-DbContext(EF Core 工具)抛出 'Instance failure' 异常

c# - 如何使用 Serilog 在异步方法上保持一致的标识符

c# - 为什么变量名作为下划线字符 ("_")不适用于解构

c# - 当以编程方式更改值时,不触发 DataGridView 中的单元格值更改事件

c# - 如何循环并检查 C# 中的用户输入是否正确?

c# - LINQ 查询出生日期以获取年龄

c# - Entity Framework 本身引用 -> 父/子

asp.net - launchSettings.json commandName 用法