WCF-证书在HTTPS情况下未正确配置HTTP.SYS。与Charles代理一起运行
这似乎是一个常见的错误(还有其他类似问题的帖子)-但是,我已经阅读了所有这些帖子和MSDN文章()。 场景:尝试使用HTTPS端点访问服务。 在代码中设置客户端证书(证书正在正确加载)。 至于服务器证书,我尝试了以下两种选择: client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode=X509CertificateValidationMode.None client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode=X509CertificateValidationMode.PeerOrChainTrust 我已将服务器证书导入个人和计算机存储(受信任的根证书颁发机构/证书)。 奇怪的是,当我使用Charles Proxy作为SSL代理时,调用正在进行。 其他设置:WCF-证书在HTTPS情况下未正确配置HTTP.SYS。与Charles代理一起运行,wcf,ssl,soap,https,client-certificates,Wcf,Ssl,Soap,Https,Client Certificates,这似乎是一个常见的错误(还有其他类似问题的帖子)-但是,我已经阅读了所有这些帖子和MSDN文章()。 场景:尝试使用HTTPS端点访问服务。 在代码中设置客户端证书(证书正在正确加载)。 至于服务器证书,我尝试了以下两种选择: client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode=X509CertificateValidationMode.None client.ClientCre
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代理运行时,上面的哈希检查可以正常工作。如果代理不运行,回调甚至不会被调用
任何反馈都将不胜感激
(值得注意的是,使用ApacheCXF库的Java客户机在相同的服务上运行良好。)
更新:
为完整起见,原始错误还包含以下文本:
这可能是因为在HTTPS情况下,服务器证书未正确配置为HTTP.SYS。这也可能是由于客户端和服务器之间的安全绑定不匹配造成的。好的,经过几天(和几夜)的激烈争论,下面是我的思考/发现(当然是解决方案!):
- 先是“SSL”,然后是SSLv2、SSLv3、TLSv1.0、TLSv1.1、TLS1.2和TLSv1.3(目前的草案)
- 服务器和客户机能够协商并选择其中一个版本以成功通信是至关重要的
- HTTP.SYS错误似乎是客户端无法与服务器协商相应版本的结果。通过Charles proxy,很明显Charles和我们试图访问的服务都在使用TLSV1.1
- 在我的例子中,我使用了wsHTTPBinding&尽管我尝试设置System.Net.ServicePointManager.SecurityProtocol=SecurityProtocolType.Tls;和其他组合,我永远无法让HTTP.SYS错误消失。服务器和客户端似乎永远无法选择一个他们可以达成一致的版本
- 我确实尝试过使用其他绑定,如basicHttpBinding(带有TransportWithMessageCredential)和basicHttpsBinding,但没有效果。更重要的是,在每种情况下,通过对绑定元素(通过config和code)进行一些小的调整,我在所有3种情况下都使用了完全相同的绑定配置(basicHttp/basichHttps/wsHttp绑定)!本质上,虽然有这些现成的绑定,但它们可能适用于最简单的场景。更重要的是,可能不需要这么多预打包的绑定,特别是因为它们似乎使用了几乎相同的绑定元素
- 我确实记得读过,在许多情况下使用自定义绑定会更好——但我想象,通过自定义wsHttpBinding,我将实现同样的效果。看起来不是-因为在这个绑定中有一些硬编码属性(例如:默认SSL协议)似乎很难绕过。我确实查看了wsHttpBinding的源代码及其基类,但找不到确切的硬编码位置(但System.ServiceModel代码中有对“默认”协议的引用)
- 最后,一个“CustomBinding”对我起了作用,配置如下:
- 我们的想法是使用
和httpstransort
,使用requireClientCertificate
(我们的服务需要时间戳)和相关的authenticationMode=“CertificateOverTransport”&includeTimestamp=“true”
,在我们的案例中是:messageSecurityVersion
wssecurity10wstrustfebruary2005wssecurityconversation2005wssecuritypolicy11basicsecurityprofile10
- 上述配置也会自动签署时间戳
- 除此之外,我们还必须包括用户名/密码凭据。仅设置client.ClientCredentials.UserName.UserName和client.ClientCredentials.UserName.Password不会导致这些凭据包含在安全标头中。逻辑是添加用户名“token”,如下所示:
//Get the current binding System.ServiceModel.Channels.Binding binding = client.Endpoint.Binding; //Get the binding elements BindingElementCollection elements = binding.CreateBindingElements(); //Locate the Security binding element SecurityBindingElement security = elements.Find<SecurityBindingElement>(); //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());
//获取当前绑定 System.ServiceModel.Channels.Binding Binding=client.Endpoint.Binding; //获取绑定元素 BindingElementCollection元素=binding.CreateBindingElements(); //找到安全绑定元素 SecurityBindingElement security=elements.Find(); //这不应该为null-因为我们正在使用证书身份验证 if(安全性!=null) { UserNameSecurityTokenParameters uTokenParams=新的UserNameSecurityTokenParameters(); uTokenParams.InclusionMode=SecurityTokenInclusionMode.AlwayStoreCiClient; EndpointSupportingTokenParameters.SignedEncrypted.Add(uTokenParams); } client.Endpoint.Binding=新的CustomBinding(elements.ToArray());
- 通过所有这些设置,我终于能够点击服务并实际获得结果-好吧,几乎结果不包括时间戳,WCF将其作为异常抛出。这是另一个需要解决的问题
- 现在时间戳问题也被“排序”。问题是响应缺少任何安全头,而不仅仅是时间戳。谢天谢地,有一种简单的方式通知WCF忽略不安全的响应,只需简单的mar