简体   繁体   English

处理较大负载的PUT / POST请求时,C#request.GetClientCertificate()冻结

[英]C# request.GetClientCertificate() freezes when processing PUT/POST request with larger payload

Given: two C# console apps, on different machines. 给定:在不同计算机上的两个C#控制台应用程序。 One is a client, one is a server. 一个是客户端,一个是服务器。 The client uses HttpClient.SendAsync to send request to the server. 客户端使用HttpClient.SendAsync将请求发送到服务器。

Every request sent to the server has a client certificate attached to the request handler and each time the server gets the cert for validation using GetClientCertificate(). 发送到服务器的每个请求都将客户端证书附加到请求处理程序,并且每次服务器使用GetClientCertificate()获取证书以进行验证时。

Normally everything works fine: all the GET calls as well as PUT calls with small payload (~4kb) consistently go through. 通常情况下,一切正常:所有GET调用以及有效载荷较小(〜4kb)的PUT调用都会持续通过。

However, when you do a PUT request with a larger payload (eg. ~40kb), then GetClientCertificate() call on the server side block and doesn't return until after 2 minutes (which is our timeout period). 但是,当您使用较大的有效负载(例如〜40kb)执行PUT请求时,则在服务器端块上调用GetClientCertificate(),直到2分钟(这是我们的超时时间)之后才会返回。 The cert returned is null. 返回的证书为空。 The client reports an error "cannot establish SSL/TLS channel." 客户端报告错误“无法建立SSL / TLS通道”。

It appears that GetClientCertificate() does some extra communication that I don't understand, and would like some information about to know what could be timing out. 似乎GetClientCertificate()进行了一些我不理解的额外通信,并希望获得一些有关可能超时的信息。 For example, we have tried disabling the cert revocation check on the server, but that didn't help. 例如,我们尝试禁用服务器上的证书吊销检查,但这没有帮助。 Also, I'm wondering if it's possible for some intermediate network node to drop that certificate, and how can this be diagnosed. 另外,我想知道某个中间网络节点是否有可能丢弃该证书,以及如何对其进行诊断。

Also, this error doesn't happen consistently. 此外,此错误不会始终发生。 Sometimes it can work for a few dozen times, but when it starts failing, and it will keep failing. 有时它可以工作几十次,但是当它开始出现故障时,它将继续失败。 This may indicate resource leaks of some sort, and it would nice to know what we could be leaking with this scenario. 这可能表明存在某种形式的资源泄漏,很高兴知道在这种情况下我们可能泄漏的内容。 We do dispose of http client, handlers, and close the certificate store. 我们确实处理了HTTP客户端,处理程序,并关闭了证书存储。

I've seen similar questions on StackOverflow where the problem was that ASP.NET requires configuring await to NOT resume on a captured context. 我在StackOverflow上看到过类似的问题,其中的问题是ASP.NET需要配置await,以使其无法在捕获的上下文中恢复。 I'm wondering if the any similar concerns could be applicable to console apps. 我想知道是否有任何类似的顾虑都可以适用于控制台应用程序。

Thanks for your help! 谢谢你的帮助!

You need to read the POST data first before calling GetClientCertificate() . 您需要先读取POST数据,然后再调用GetClientCertificate()

Also, enabling client certificate negotiation on the server's SSL certificate binding may be an option for you (but it will cause every request to ask for one). 另外,在服务器的SSL证书绑定上启用客户端证书协商可能是您的一种选择(但这会导致每个请求都要求一个)。

Run netsh http show sslcert on your server and look for the certificate that is bound to the port in question and look at the Negotiate Client Certificate property. 在服务器上运行netsh http show sslcert ,然后查找绑定到所讨论端口的证书,然后查看“ 协商客户端证书”属性。 If you change that to Enabled , then it will invoke client certificate negotiation at the beginning of each connection, so by the time your code calls GetClientCertificate() , it will already be there. 如果将其更改为Enabled ,它将在每个连接的开始处调用客户端证书协商,因此在您的代码调用GetClientCertificate() ,该证书已经存在。

Here is some code that will read the POST data before accessing the client certificate. 这是一些代码,这些代码将在访问客户端证书之前读取POST数据。 In my tests, this works reliably, but as I noted in the comment may not be ideal for all use cases. 在我的测试中,这可靠地起作用,但是正如我在评论中指出的那样,对于所有用例而言可能并不理想。

private static void ProcessPostRequest(System.Net.HttpListenerContext context)
{
    // Read the entire POST data into a byte array.  This isn't ideal.  Also, it does not supported 'chunked' encoding.
    byte[] input      = new byte[context.Request.ContentLength64];
    int    bytesRead  = 0;
    int    totalBytes = 0;

    while ((bytesRead = context.Request.InputStream.Read(input, totalBytes, Math.Min(4096, input.Length - totalBytes))) > 0)
    {
        totalBytes += bytesRead;
    }

    System.Diagnostics.Debug.WriteLine($"Read {totalBytes:#,##}");

    var cert = context.Request.GetClientCertificate();

    if (cert != null)
    {
        System.Diagnostics.Debug.WriteLine(cert.Subject);
    }

    // Be sure to write to or close the Response.
}

Please read this article . 请阅读这篇文章 It has the reason and recommendations for handling such cases. 它具有处理此类案件的原因和建议。 In short, Kevin's suggestion of reading the body before reading the client certificate should solve the problem. 简而言之,凯文(Kevin)的建议是在阅读客户证书之前先阅读尸体,这样可以解决这个问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM