HttpClient与客户端证书一起重用 [英] HttpClient reused with client certificate

查看:92
本文介绍了HttpClient与客户端证书一起重用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经在几个地方阅读过(例如此处 此处),这是一种不好的做法在请求后直接处理HttpClient,最好在所有请求完成后进行处理,以允许连接的重用。

I've read at several places (like here, here or here) that it's a bad practice to dispose of the HttpClient directly after a request and it's better to dispose of it after all the request have been made, to allow reuse of the connection.

尝试一下,我已经创建了HttpClient的实例,并通过以下方式将其添加到类中的静态字段中:

To try that out, I've created an instance of HttpClient and added to a static field in my class this way:

public class Test
{
    private static X509Certificate2 _certificate;
    private static HttpClient HttpClient { get; set; }

    ...

    public Test()
    {
        ...

        if (HttpClient == null)
        {
            LoadCertificate();

            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
                                                    | SecurityProtocolType.Tls11
                                                    | SecurityProtocolType.Tls12
                                                    | SecurityProtocolType.Ssl3;

            var handler = new WebRequestHandler();
            handler.ClientCertificates.Add(_certificate);
            HttpClient = new HttpClient(handler, false);
        }
    }

    private void LoadCertificate()
    {
        using (var store = new X509Store(StoreName.My, CertificateStoreLocation))
        {
            store.Open(OpenFlags.ReadOnly);
            var certificates = store.Certificates.Find(X509FindType.FindBySubjectName, CertificateFriendlyName, true);
            if (certificates.Count != 1)
                throw new ArgumentException(
                    $"Cannot find a valid certificate with name {CertificateFriendlyName} in {CertificateStoreLocation}");
            _certificate = certificates[0];

            store.Close();
        }

        ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
    }

}

我正在使用我的实例通过以下命令调用Web服务:

I'm then using my instance to call a web service through this command:

var result = await HttpClient.PostAsJsonAsync(completeUri, request);

第一次运行代码时,一切正常,我得到了正确的响应,但是然后,在接下来的所有时间里,我都从服务器得到未经授权的通知,告诉我我没有使用客户端证书。

The first time I'm running the code, everything works fine and I get a response correctly, but then, all the following time I get an unauthorized from the server telling me that I didn't use a client certificate.

这就像对于以下调用来说,<没有考虑code> WebRequestHandler 。

It's like if for the following calls, the WebRequestHandler wasn't took into consideration.

推荐答案

您的修复应如下所示:

handler.PreAuthenticate = true;

建立与服务的连接后,您可以重新使用该服务以使用不同的方式与其通信具有不同身份验证信息的客户端。这意味着服务需要每次都知道哪个客户端发送了请求,否则可能是安全漏洞-例如在最后一个连接的客户端下执行请求。这取决于您的身份验证机制,但是基本上 WebRequestHandler 在第一个请求后设置标志 IsAuthenticated ,并停止发送身份验证信息在下一个请求。 PreAuthenticate 选项强制在每个请求上发送身份验证信息。

Once you establish a connection to a service, you can re-use it to communicate with it using different clients with different auth information. That means, the service needs to know which client sent a request each time, otherwise it could be a security breach - e.g. executing a request under last connected client. It depends on your authentication mechanism, but basically WebRequestHandler sets flag IsAuthenticated after the first request, and stops sending the auth information on next requests. The PreAuthenticate options forces to send the auth info on every request.

这篇关于HttpClient与客户端证书一起重用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆