WCF - 在HTTPS情况下,HTTP.SYS未正确配置证书。适用于Charles代理运行 [英] WCF - certificate not configured properly with HTTP.SYS in the HTTPS case. Works with Charles proxy running

查看:1459
本文介绍了WCF - 在HTTPS情况下,HTTP.SYS未正确配置证书。适用于Charles代理运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这似乎是一个常见的错误(还有其他类似问题的帖子) - 但是,我已经浏览了所有这些帖子和MSDN文章( https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/working - 带证书)。
场景:尝试使用HTTPS端点访问服务。
在代码中设置客户端证书(证书正确加载)。
至于服务器证书,我已经尝试了以下两个选项:
client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;

This seems to be a common error (there are other posts with similar issues) - however, I have gone through all those posts and MSDN articles ( https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/working-with-certificates ). Scenario: Trying to access a service with an HTTPS end point. Setting the client certificate in code (certificate is loading correctly). As for the Server cert, I have tried both the options below: client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;

client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.PeerOrChainTrust;

client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.PeerOrChainTrust;

我已将服务器证书导入Personal和机器商店(受信任的根证书颁发机构/证书) )。
奇怪的是,当我使用Charles Proxy作为SSL代理时,调用正在进行。
其他设置:

I have imported the server certificate to Personal as well as machine store (Trusted Root certificate authorities / certificates). The weird thing is the call is going through when I use Charles Proxy as the SSL proxy. Other settings:

    System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Ssl3;

    ServicePointManager.ServerCertificateValidationCallback +=
            (se, cert, chain, sslerror) =>
            {
                //Console.WriteLine(cert.GetCertHashString());

                if (cert.GetCertHashString() == "[actual hash here]")
                    return true;
                else
                    return false;
            };

当Charles代理运行时,上述哈希检查正常。如果没有代理运行,回调甚至不会被调用。

The above Hash check works fine when Charles proxy is running. Without the proxy running, the callback does not even get called.

任何反馈都表示赞赏。

Any feedback is appreciated.

(可能值得注意的是,使用Apache CXF库的Java客户端可以正常工作 - 针对相同的服务。)

(It may be worthwhile to note that a Java client using Apache CXF library works fine - against the same service.)

更新
为完整起见,原始错误也包含此文本:
这可能是由于未使用HTTP正确配置服务器证书。 HTTPS案例中的SYS。这也可能是由于客户端和服务器之间的安全绑定不匹配造成的。

Update: For completeness, the original error also had this text: This could be due to the fact that the server certificate is not configured properly with HTTP.SYS in the HTTPS case. This could also be caused by a mismatch of the security binding between the client and the server.

推荐答案

好了,几天后(& ;晚上)头撞,以下是我的思考/调查结果(当然还有解决办法!):

OK, after days(& nights) of head banging, the following are my musings / findings (& of course the solution !):


  • 那里是SSL然后是SSLv2,SSLv3,TLSv1.0,TLSv1.1,TLS1.2& TLSv1.3(截至目前的草案)。

  • There is "SSL" and then there is SSLv2, SSLv3, TLSv1.0, TLSv1.1, TLS1.2 & TLSv1.3 (draft as of now).

服务器和客户端能够协商并且至关重要。选择其中一个版本来成功沟通。

It is critical that the server and client are able to negotiate & pick one of these versions to successfully communicate.

HTTP.SYS错误似乎是客户端无法在适当版本上与服务器协商的结果。通过查尔斯代理时,很明显查尔斯和我们试图打击的服务都在使用TLSV1.1。

The HTTP.SYS error seems to be a result of the client not being able to negotiate with the server on the appropriate version. When going through Charles proxy, it was clear that both Charles and the service we were trying to hit, were using TLSV1.1.

在我的情况下,我正在使用wsHTTPBinding&虽然我尝试设置System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;和其他组合,我永远不会得到HTTP.SYS错误消失。似乎服务器和客户端永远不会选择他们可以同意的版本。

In my case, I was using wsHTTPBinding & though I tried setting the System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls; and other combinations, I could never get the HTTP.SYS error to go away. It would seem that the server and the client could never pick a version that they could agree on.

我尝试使用其他绑定,例如basicHttpBinding(使用TransportWithMessageCredential )以及basicHttpsBinding,但无济于事。在每种情况下,绑定元素中的一些小调整(通过配置和代码)还有更多,我在所有3种情况下都以完全相同的绑定配置结束(basicHttp / basichHttps / wsHttp绑定)!从本质上讲,虽然有这些开箱即用的绑定,但它们可能适用于最简单的场景。更重要的是,可能不需要这么多预先打包的绑定,特别是因为它们似乎主要使用相同的绑定元素。

I did try using other bindings such as basicHttpBinding (with TransportWithMessageCredential) as well as basicHttpsBinding, but to no avail. What's more with some minor tweaks in the binding elements (through config & code) in each case, I ended with exactly the same binding configuration in all 3 cases (basicHttp/basichHttps/wsHttp bindings)! In essence, while there are these out-of-the-box bindings, they probably work for the most simple of scenarios. What's more, there is probably no need for so many of these pre-packaged bindings, especially as they seem to be using mostly the same binding elements.

我确实记得在很多情况下使用自定义绑定更好 - 但我想通过自定义wsHttpBinding我会实现同样的目的。看起来没有 - 因为这个绑定中有一些硬编码属性(例如:默认SSL协议)似乎很难解决。我确实看了一下wsHttpBinding的源代码及其基类,但是找不到确切的硬编码位置(但是在System.ServiceModel代码中有对默认协议的引用)。

I did remember reading that using a custom binding is better in many cases - but I imagined that by customizing a wsHttpBinding I would be achieving the same thing. Looks not - as there are some hard-coded properties (e.g.: default SSL protocols) in this binding that seem difficult to get around. I did take a look at the source code of wsHttpBinding and its base class, but could not find the exact hard coded location (but there are references to "default" protocols in the System.ServiceModel code).


  • 最后,CustomBinding为我工作,配置如下:

自定义绑定配置
- 很抱歉将此作为图片包含在内 - 因为SO上的格式正在播放。

Custom Binding configuartion - Sorry for including this as an image - as the formatting on SO was playing up.


  • 想法是使用带有requireClientCertificate的httpsTransport,使用authenticationMode =CertificateOverTransport& includeTimestamp =true(我们的服务需要Timestamp)和相关的messageSecurityVersion - 在我们的例子中是:
    WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10

  • The idea is to use httpsTransport with requireClientCertificate, security with authenticationMode="CertificateOverTransport" & includeTimestamp="true" (our service required Timestamp) and the relevant messageSecurityVersion - in our case it was: WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10

以上配置自动签名时间戳也是如此。

The above configurations automatically signed the Timestamp as well.

除此之外,我们还必须包含用户名/密码凭据。只需设置client.ClientCredentials.UserName.UserName& client.ClientCredentials.UserName.Password未导致Security标头中包含这些凭据。逻辑是添加用户名token,如下所示:

On top of this we had to include the username / password credentials. Simply setting the client.ClientCredentials.UserName.UserName & client.ClientCredentials.UserName.Password did not result in these credentials included in the Security header. The logic was to add the username "token" as well, like so:

//获取当前绑定
System.ServiceModel.Channels.Binding binding = client.Endpoint.Binding;

//Get the current binding System.ServiceModel.Channels.Binding binding = client.Endpoint.Binding;

//获取绑定元素
BindingElementCollection elements = binding.CreateBindingElements();

//Get the binding elements BindingElementCollection elements = binding.CreateBindingElements();

//找到安全绑定元素
SecurityBindingElement security = elements.Find();

//Locate the Security binding element SecurityBindingElement security = elements.Find();

//这不应该为null - 因为我们正在使用证书身份验证
if(security!= null)
{
UserNameSecurityTokenParameters uTokenParams = new UserNameSecurityTokenParameters();
uTokenParams.InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient;
security.EndpointSupportingTokenParameters.SignedEncrypted.Add(uTokenParams);
}

//This should not be null - as we are using Certificate authentication anyway if (security != null) { UserNameSecurityTokenParameters uTokenParams = new UserNameSecurityTokenParameters(); uTokenParams.InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient; security.EndpointSupportingTokenParameters.SignedEncrypted.Add(uTokenParams); }

client.Endpoint.Binding = new CustomBinding(elements.ToArray());

client.Endpoint.Binding = new CustomBinding(elements.ToArray());

通过所有这些设置,我终于可以点击服务并实际获得结果 - 好吧,差不多! - 因为结果不包含时间戳,WCF作为例外抛出。这是另一个需要解决的问题。

With all this setup, I was able to finally hit the Service and actually get the result - well, almost ! - as the result does not include a Timestamp, which WCF is throwing up as an exception. That is another problem to solve though.

希望读者觉得这很有用。

Hopefully readers find this useful.

更新:


  • 现在,时间戳问题也已排序。问题是响应缺少任何安全标头,而不仅仅是时间戳。值得庆幸的是,通过简单地标记安全元素上的属性,有一种直接的方式来通知WCF忽略不安全的响应:enableUnsecuredResponse =true。显然这是不可取的,但由于我们对服务没有任何控制权,这是我们目前可以做的最好的事情。

这篇关于WCF - 在HTTPS情况下,HTTP.SYS未正确配置证书。适用于Charles代理运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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