[英]This could be due to the fact that the server certificate is not configured properly with HTTP.SYS in the HTTPS case. c#
[英]WCF - certificate not configured properly with HTTP.SYS in the HTTPS case. Works with Charles proxy running
这似乎是一个常见错误(还有其他具有类似问题的帖子) - 但是,我已经浏览了所有这些帖子和 MSDN 文章( https://docs.microsoft.com/en-us/dotnet/framework/wcf/功能详细信息/使用证书)。 场景:尝试访问具有 HTTPS 端点的服务。 在代码中设置客户端证书(证书加载正确)。 至于服务器证书,我尝试了以下两个选项:client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.PeerOrChainTrust;
我已将服务器证书导入到个人和机器存储(受信任的根证书颁发机构/证书)。 奇怪的是,当我使用 Charles Proxy 作为 SSL 代理时,调用正在进行。 其他设置:
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 代理运行时,上述哈希检查工作正常。 没有代理运行,回调甚至不会被调用。
任何反馈表示赞赏。
(可能值得注意的是,使用 Apache CXF 库的 Java 客户端可以正常工作 - 针对相同的服务。)
更新:为了完整起见,原始错误也包含以下文本:这可能是由于在 HTTPS 情况下未使用 HTTP.SYS 正确配置服务器证书。 这也可能是由于客户端和服务器之间的安全绑定不匹配造成的。
好的,经过几天(和晚上)的头部撞击,以下是我的思考/发现(当然还有解决方案!):
有“SSL”,然后是 SSLv2、SSLv3、TLSv1.0、TLSv1.1、TLS1.2 和 TLSv1.3(目前的草案)。
服务器和客户端能够协商并选择这些版本之一以成功通信至关重要。
HTTP.SYS 错误似乎是由于客户端无法在适当的版本上与服务器协商的结果。 当通过 Charles 代理时,很明显 Charles 和我们试图访问的服务都使用 TLSV1.1。
就我而言,我使用的是 wsHTTPBinding & 虽然我尝试设置 System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls; 和其他组合,我永远无法让 HTTP.SYS 错误消失。 服务器和客户端似乎永远无法选择他们可以同意的版本。
我确实尝试使用其他绑定,例如 basicHttpBinding(使用 TransportWithMessageCredential)以及 basicHttpsBinding,但无济于事。 更重要的是,在每种情况下对绑定元素(通过配置和代码)进行了一些小调整,我在所有 3 种情况下都以完全相同的绑定配置结束(basicHttp/basichHttps/wsHttp 绑定)! 本质上,虽然有这些开箱即用的绑定,但它们可能适用于最简单的场景。 更重要的是,可能不需要这么多这些预先打包的绑定,特别是因为它们似乎几乎使用相同的绑定元素。
我确实记得在许多情况下使用自定义绑定更好 - 但我想象通过自定义 wsHttpBinding 我将实现同样的事情。 看起来不是 - 因为在这个绑定中有一些硬编码的属性(例如:默认 SSL 协议)似乎很难绕过。 我确实查看了 wsHttpBinding 及其基类的源代码,但找不到确切的硬编码位置(但在 System.ServiceModel 代码中引用了“默认”协议)。
自定义绑定配置- 很抱歉将其作为图像包含在内 - 因为 SO 上的格式正在播放。
这个想法是使用httpsTransport
和requireClientCertificate
,使用authenticationMode="CertificateOverTransport" & includeTimestamp="true"
(我们的服务需要时间戳)和相关的messageSecurityVersion
- 在我们的例子中是: WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10
.
上述配置也自动签署了时间戳。
最重要的是,我们必须包含用户名/密码凭据。 简单地设置 client.ClientCredentials.UserName.UserName & client.ClientCredentials.UserName.Password 不会导致这些凭据包含在 Security 标头中。 逻辑也是添加用户名“令牌”,如下所示:
//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());
通过所有这些设置,我终于能够点击服务并实际得到结果 - 几乎! - 因为结果不包括时间戳,WCF 将其作为异常抛出。 这是另一个需要解决的问题。
希望读者发现这很有用。
更新:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.