控制 WCF 客户端中的 SOAP 安全 header "mustUnderstand" 属性

Controling SOAP security header "mustUnderstand" attribute in WCF client

从网上第一次提出这个问题已经好几年了,我仍然没有看到有人解决它。

WSE 能够设置标志 Security.EncodedMustUnderstand =“0”。 WCF 似乎不再具有该功能。自定义消息检查器永远不会在 BeforeSendRequest 方法中看到安全性 header,并且对其中的 headers 所做的任何更改似乎都不会生效。

这似乎是遗留服务或 java 服务的一个巨大的互操作性问题。为什么微软还没有解决?

有人对此问题有解决方法吗?

在我所有的搜索中,只有一个人真正声称解决了这个问题here。但是他们的修复一定不适用于我的场景,因为它根本不会修改外发消息。

我正在使用 CustomBinding 并需要 x509 证书和用户名安全性

        var security = SecurityBindingElement.CreateCertificateOverTransportBindingElement();
        //var security = new TransportSecurityBindingElement();
        security.IncludeTimestamp = true;
        security.DefaultAlgorithmSuite = SecurityAlgorithmSuite.Basic256;
        security.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10;
        //security.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11;
        //security.EndpointSupportingTokenParameters.SignedEncrypted.Add(new X509SecurityTokenParameters(X509KeyIdentifierClauseType.Any, SecurityTokenInclusionMode.AlwaysToRecipient)); // add specific x509 cert security            security.EndpointSupportingTokenParameters.Signed.Add(new UserNameSecurityTokenParameters()); // add specific username security feature
        security.EndpointSupportingTokenParameters.Signed.Add(new UserNameSecurityTokenParameters()); // add specific username security feature
        security.SecurityHeaderLayout = SecurityHeaderLayout.Lax;
        security.EnableUnsecuredResponse = true;
        //security.ProtectTokens = false;


        //security.DefaultAlgorithmSuite = new Basic128Sha256Rsa15Sha1AlgorithmSuite(); // when we need to tweak the security suite


        var encoding = new TextMessageEncodingBindingElement();
        //encoding.MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap11, AddressingVersion.None);// MessageVersion.Soap11;
        encoding.MessageVersion = MessageVersion.Soap11WSAddressingAugust2004;
        encoding.WriteEncoding = Encoding.UTF8;


        var transport = new HttpsTransportBindingElement();
        transport.MaxReceivedMessageSize = 20000000; // 20 megs
        transport.RequireClientCertificate = false;

        CustomBinding binding = new CustomBinding();
        binding.Elements.Add(security);
        binding.Elements.Add(encoding);
        //binding.Elements.Add(new TimestampedTextMsgEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8));
        binding.Elements.Add(transport);

编辑:

我终于能够让这一半与自定义编码器一起工作。删除此互操作性功能似乎是 Microsoft 的重大失败,但可以使用自定义编码器对其进行黑客攻击。

不幸的是,当服务返回看似有效的内容时 xml(在 Fiddler 中观察到),CustomEncoder 在它到达 ReadMessage 函数之前因堆栈溢出错误而崩溃。仍在尝试找出原因。

有时我得到的不是堆栈溢出错误,而是内部异常链:

消息:向 https://service 发出 HTTP 请求时发生错误。这可能是由于服务器证书在 HTTPS 情况下没有正确配置 HTTP.SYS。这也可能是由于客户端和服务器之间的安全绑定不匹配造成的。

消息:基础连接已关闭:发送时发生意外错误。

消息:无法从传输连接读取数据:现有连接被远程主机强行关闭。

奇怪的是连接没有被远程主机强制关闭,远程主机似乎认为一切都成功了。所以这是 .net 内部的错误。要么是 .net 本身的问题,要么是我的自定义编码器的问题,它是直接从微软网站复制的。

我终于想通了。此问题的根源是 Microsoft 从 WCF 中删除了 Security.EncodedMustUnderstand = "0" 功能。无论他们选择这样做的原因是什么,都会给我带来很多额外的工作。创建手动修改此设置的自定义编码器是我能找到解决该问题的唯一方法。

我的第二个大问题是我从他们的网站上复制了 Microsoft 的自定义编码器示例代码。结果发现其中有一个隐藏循环会产生堆栈溢出错误。

在我清理了 Microsoft 的示例代码后,我仍然遇到相同的 HTTP.SYS 错误。这次它实际上是一个有效错误,将代码移动到可以从 https url 获取调用的服务器解决了这个问题。

编辑:我写了一篇关于这个答案的详细博客 post here