在C#中查询HTTPS SOAP服务失败。

huangapple go评论59阅读模式
英文:

Querying an HTTPS SOAP service fails in C#

问题

首先,我了解到关于SOAP的知识非常有限(我真的希望能够幸运地远离它),所以请原谅我对这方面的完全无知。

我需要调用一个在Java中创建的旧SOAP服务的一些函数(来自.NET 4 Framework),但由于某种原因我无法做到这一点,我不明白为什么,因为在VPN内部的测试环境中一切都正常工作。

我尝试过这里和在线找到的其他解决方案,但似乎没有任何东西能够解决问题,我无法访问SOAP服务器上的日志以查看到底出了什么问题。

我知道这个服务是有效的,因为SoapUI(版本5.7.0)可以与其通信而无任何问题。

在SoapUI中,在"Outgoing WS-Security Configurations"页面中,我添加了这些WSS条目:

  • 时间戳
  • 签名
  • 加密

正如服务提供商所说,我不知道这是否重要。

这是客户端在测试环境中(使用HTTP)的工作方式:【以下代码不翻译】

正如我所说,这段代码在测试VPN环境中完美运行。

不幸的是,当我不得不将其移入生产环境时,端点地址发生了变化,现在不再是HTTP,而是HTTPS... 根据提供此SOAP服务的人说,除了签名和加密的证书(我确实更新了)之外,没有其他变化。

由于这段代码不再起作用,我尝试使用BasicHttpsBinding而不是BasicHttpBinding,我尝试了BasicHttpsSecurityMode.Transport以及BasicHttpsSecurityMode.TransportWithMessageCredential,但是没有用... 我得到了这个错误:"发现处理<wsse:Security>头时发生错误"。

正如我所说,不幸的是我无法访问服务器端的日志,因此我不知道到底出了什么问题。我在某处读到,也许消息的正文没有被签名(为什么?),所以我尝试添加【以下内容不翻译】。

我甚至尝试创建自己的自定义绑定,但由于我不知道自己在做什么,也没有成功。

对任何帮助表示感激。

到目前为止,我尝试过:

  • 将BasicHttpBinding更改为BasicHttpsBinding
  • 将安全模式从BasicHttpSecurityMode.Message更改为BasicHttpsSecurityMode.Transport和BasicHttpsSecurityMode.TransportWithMessageCredential(使用BasicHttpBinding和BasicHttpsBinding)
  • 尝试通过System.Net.Security.ProtectionLevel.Sign和System.Net.Security.ProtectionLevel.EncryptAndSign强制对消息正文进行签名
  • 创建自己的自定义绑定(但我不知道我在做什么,我尝试遵循在线的几个示例,但我不完全理解它们)
英文:

first of all, i know near to nothing about SOAP (and i really hoped i'd be lucky enough to stay away from it), so pardon my total ignorance.

I need to call (from the .NET 4 Framework) some functions on an old SOAP service made in Java but for some reason i am unable to do so and i don't understand why since everything worked on a test environment with HTTP inside a VPN.

I tried other solutions found here and online but nothing seems to work and i cannot access the log on the SOAP server to see exactly what goes wrong.

I know that the service works because SoapUI (version 5.7.0) can communicate with it without a problem.

In SoapUI, in the Outgoing WS-Security Configurations page i added these WSS Entries:

  • Timestamp
  • Signature
  • Encryption

as told by the service provider, i don't know if it matters.

This is how the client used to work inside the test environment (with HTTP):

var myBinding = new BasicHttpBinding();
myBinding.Security.Mode = BasicHttpSecurityMode.Message;
myBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.Certificate;
myBinding.Security.Message.AlgorithmSuite = SecurityAlgorithmSuite.TripleDes;
myBinding.MaxReceivedMessageSize = 2 * 1024 * 1024;
var ei = EndpointIdentity.CreateDnsIdentity(&quot;test&quot;);
var aec = new AddressHeaderCollection();
var ea = new EndpointAddress(new Uri(&quot;http://endpointurl/servicename&quot;), ei, aec);
var client = new DonorportalServiceInsiel.DonorportalServicePortClient(myBinding, ea);
client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
client.ClientCredentials.ClientCertificate.Certificate = new X509Certificate2(File.ReadAllBytes(@&quot;D:\cert1.p12&quot;), &quot;12345678&quot;);
client.ClientCredentials.ServiceCertificate.DefaultCertificate = new X509Certificate2(File.ReadAllBytes(@&quot;D:\cert2.p12&quot;), &quot;12345678&quot;);
return client;

As i said, this code worked perfectly inside the test VPN environment.

Unfortunately when i had to move it into production the endpoint address changed, now it is not HTTP anymore, but it is HTTPS... according to the guys that provide this SOAP service nothing else has changed (beside the certificates for signing and encryption which i did update).

Since this code didn't work anymore i tried using the BasicHttpsBinding instead than BasicHttpBinding and i tried BasicHttpsSecurityMode.Transport and also BasicHttpsSecurityMode.TransportWithMessageCredential, but nothing... i get this error: "An error was discovered processing the <wsse:Security> header".

As i said, unfortunately i do not have access to the log on the server side so i don't exactly know what's wrong. I read somewhere that perhaps the body of the message is not getting signed (why??) so i tried adding
client.Endpoint.Contract.ProtectionLevel = System.Net.Security.ProtectionLevel.Sign;
and also
client.Endpoint.Contract.ProtectionLevel = System.Net.Security.ProtectionLevel.EncryptAndSign;
but same error.

I even tried creating my own custom binding but since i don't know what i'm doing i had no success either.

Any help is appreciated.

So far i tried:

  • Changing BasicHttpBinding to BasicHttpsBinding
  • Changing the security mode from BasicHttpSecurityMode.Message to BasicHttpsSecurityMode.Transport and BasicHttpsSecurityMode.TransportWithMessageCredential (with both BasicHttpBinding and BasicHttpsBinding)
  • Trying to force the body signature with System.Net.Security.ProtectionLevel.Sign and System.Net.Security.ProtectionLevel.EncryptAndSign
  • Create my own custom binding (but i don't know what i am doing, i tried to follow several examples online but i don't fully understand them)

答案1

得分: 1

我不了解您的需求。我认为这些需求已经过时,以下是我的理由:

  1. Net 4.7.1之前的库不支持所有加密算法。您的新证书不支持旧版本的Net。
  2. 您正在使用支持所有加密模式的Windows 10。
  3. TLS 1.2和1.3是唯一有效的TLS版本。旧版本不安全,因为黑客已经破解了加密模式。
  4. 您正在使用Net 4.7.2,它使用操作系统而不是Net进行TLS。
  5. 您的证书是SHA-256(而不是SecurityAlgorithmSuite.TripleDes)。您不应该支持容易受到攻击的旧加密模式。
  6. 如果您必须使用更新的加密算法才能确保安全并与新证书配合使用,那么以前的测试已经不再有效。
英文:

I do not know your requirements. I believe the requirements are outdated and here is my justification

  1. Net Library before Net 4.7.1 did not support all encryption algorithms. You new certificate is not supported with older version of Net
  2. You are using Windows 10 which supports all encryption modes
  3. TLS 1.2 and 1.3 are only valid TLS versions. Older version are not secure since hackers have broken the encryption mode
  4. You are using Net 4.7.2 which is using OS for TLS, instead of Net.
  5. Your certificate is SHA-256 (not SecurityAlgorithmSuite.TripleDes). You should not be supporting older encryption modes that are vulnerable.
  6. Previous testing is not longer valid if you must use newer encryption algorithms to be secure and to work with your new certificate.

答案2

得分: 0

经过多次失败的尝试,我终于成功了。
由于测试环境中的版本(使用BasicHttpBinding的HTTP)可以工作,我比较了与生产环境(使用HTTPS)的绑定元素,并发现如果我使用BasicHttpsBinding,包是未加密的(我猜测因为它已经通过HTTPS加密了)。

不幸的是,服务器上的旧代码除了使用过时且不安全的加密标准外,还完全忽略了我们使用HTTPS的事实,并要求包无论如何都必须加密,这使得整个事情失败了。

由于我无法访问服务器日志,所以无法弄清楚问题出在哪里,因为它只给我一个通用的错误消息:“发现处理wsse:Security头部时发生错误”,而没有告诉我到底是什么问题。由于SOAP有大约1000种不同的配置和选项,即使经过几个小时/天的失败尝试后,我也很难理解服务器上的旧代码究竟不喜欢什么。

所以,正如我所说,为了找出问题所在,我比较了这两种绑定,并发现安全元素是不同的。

这是我用来比较这两种绑定的代码:

var httpBinding = new BasicHttpBinding();
httpBinding.Security.Mode = BasicHttpSecurityMode.Message;
httpBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.Certificate;
httpBinding.Security.Message.AlgorithmSuite = SecurityAlgorithmSuite.TripleDes;
httpBinding.MaxReceivedMessageSize = 2 * 1024 * 1024;
var httpElements = httpBinding.CreateBindingElements();

var httpsBinding = new BasicHttpsBinding();
httpsBinding.Security.Mode = BasicHttpsSecurityMode.TransportWithMessageCredential; // 请注意,BasicHttpsSecurityMode.Message 在BasicHttpsBinding中不可用
httpsBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.Certificate;
httpsBinding.Security.Message.AlgorithmSuite = SecurityAlgorithmSuite.TripleDes;
httpsBinding.MaxReceivedMessageSize = 2 * 1024 * 1024;
var httpsElements = httpsBinding.CreateBindingElements();

然后,我比较了httpElements集合中的3个元素与httpsElements集合中的3个元素,发现索引为0的元素(安全绑定元素)不同。

通过在上面的代码后添加这行代码,我成功地使其首次运行:

httpsElements[0] = httpElements[0];

当然,这是一个不太优雅的小技巧,我并不喜欢它,但现在我知道如果我能重新创建BasicHttpBinding的安全元素,我就能够创建一个有效的自定义绑定。

所以,这是最终的工作代码:

var customBinding = new CustomBinding();

var sbe = (AsymmetricSecurityBindingElement)SecurityBindingElement.CreateMutualCertificateBindingElement(MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10);
sbe.DefaultAlgorithmSuite = SecurityAlgorithmSuite.TripleDes;
sbe.MessageProtectionOrder = MessageProtectionOrder.SignBeforeEncryptAndEncryptSignature;
sbe.SecurityHeaderLayout = SecurityHeaderLayout.Lax;

customBinding.Elements.Add(sbe); // 安全性
customBinding.Elements.Add(new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8)); // 消息
customBinding.Elements.Add(new HttpsTransportBindingElement() { MaxReceivedMessageSize = 2 * 1024 * 1024 }); // 传输

var ei = EndpointIdentity.CreateDnsIdentity("test");
var aec = new AddressHeaderCollection();
var ea = new EndpointAddress(new Uri("https://endpointurl/servicename"), ei, aec);

var client = new DonorportalServiceProduzione.DonorportalServicePortClient(customBinding, ea);
client.Endpoint.Contract.ProtectionLevel = System.Net.Security.ProtectionLevel.EncryptAndSign;
client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
client.ClientCredentials.ClientCertificate.Certificate = new X509Certificate2(File.ReadAllBytes(@"D:\cert1.p12"), "12345678");
client.ClientCredentials.ServiceCertificate.DefaultCertificate = new X509Certificate2(File.ReadAllBytes(@"D:\cert2.p12"), "");
return client;

为了找出SecurityBindingElement(上面代码中的sbe)的正确选项,我基本上复制了BasicHttpBinding的Security元素(上面代码中的httpElements[0]),现在它完美运行。

如果解决方案太长,我很抱歉,但我认为解释我是如何理解问题的,以及也许可以帮助处于我的同样情况但像我一样对SOAP一无所知且不知如何解决问题的其他人,会有所帮助。

英文:

So after many failed attempts i finally made it work.
Since the version in the test environment (which used HTTP with BasicHttpBinding) did work, i compared the binding elements with the production environment (which uses HTTPS) and found that if i use the BasicHttpsBinding the package was not encrypted (i guess because it is already encrypted via HTTPS).

Unfortunately the legacy code on the server, beside using outdated and insecure encryption standards, completely ignored the fact that we were using HTTPS and required the package to be encrypted anyways which made the whole thing fail.

I didn't have access to the server logs so i couldn't figure out what was wrong since it just gave me a generic "An error was discovered processing the <wsse:Security> header" without telling me exactly what was the problem. Since SOAP has, like, 1000 different configurations and options it was quite hard for me to understand what exactly the legacy code on the server didn't like even after several hours/days of failed attempts.

So, as i said, to figure out what was wrong i compared the two bindings and found out that the Security Element was different.

This is the code i used to compare the two bindings:

var httpBinding = new BasicHttpBinding();
httpBinding.Security.Mode = BasicHttpSecurityMode.Message;
httpBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.Certificate;
httpBinding.Security.Message.AlgorithmSuite = SecurityAlgorithmSuite.TripleDes;
httpBinding.MaxReceivedMessageSize = 2 * 1024 * 1024;
var httpElements = httpBinding.CreateBindingElements();

var httpsBinding = new BasicHttpsBinding();
httpsBinding.Security.Mode = BasicHttpsSecurityMode.TransportWithMessageCredential; // Note that BasicHttpsSecurityMode.Message is not available with BasicHttpsBinding
httpsBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.Certificate;
httpsBinding.Security.Message.AlgorithmSuite = SecurityAlgorithmSuite.TripleDes;
httpsBinding.MaxReceivedMessageSize = 2 * 1024 * 1024;
var httpsElements = httpsBinding.CreateBindingElements();

I then compared the 3 elements inside the httpElements collection with the 3 elements inside the httpsElements collection and found that the element with index 0 (the Security Binding Element) was different.

By simply adding this line after the code above i managed to make it work for the first time.

httpsElements[0] = httpElements[0];

This was of course a dirty little trick and i didn't like it, but now i knew that if i managed to recreate the Security Element of the BasicHttpBinding i would be able to create a Custom Binding that did work.

So, this is the final working code:

var customBinding = new CustomBinding();

var sbe = (AsymmetricSecurityBindingElement)SecurityBindingElement.CreateMutualCertificateBindingElement(MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10);
sbe.DefaultAlgorithmSuite = SecurityAlgorithmSuite.TripleDes;
sbe.MessageProtectionOrder = MessageProtectionOrder.SignBeforeEncryptAndEncryptSignature;
sbe.SecurityHeaderLayout = SecurityHeaderLayout.Lax;

customBinding.Elements.Add(sbe); // Security
customBinding.Elements.Add(new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8)); // Message
customBinding.Elements.Add(new HttpsTransportBindingElement() { MaxReceivedMessageSize = 2 * 1024 * 1024 }); // Transport

var ei = EndpointIdentity.CreateDnsIdentity(&quot;test&quot;);
var aec = new AddressHeaderCollection();
var ea = new EndpointAddress(new Uri(&quot;https://endpointurl/servicename&quot;), ei, aec);

var client = new DonorportalServiceProduzione.DonorportalServicePortClient(customBinding, ea);
client.Endpoint.Contract.ProtectionLevel = System.Net.Security.ProtectionLevel.EncryptAndSign;
client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
client.ClientCredentials.ClientCertificate.Certificate = new X509Certificate2(File.ReadAllBytes(@&quot;D:\cert1.p12&quot;), &quot;12345678&quot;);
client.ClientCredentials.ServiceCertificate.DefaultCertificate = new X509Certificate2(File.ReadAllBytes(@&quot;D:\cert2.p12&quot;), &quot;&quot;);
return client;

To figure out the correct options of the SecurityBindingElement (sbe in the code above) i just pretty much copied the settings in the Security Element of the BasicHttpBinding (httpElements[0] in the code above) and now it works perfectly.

Sorry if the solution is long but i thought that it would have been helpful to explain how i understood what was wrong so that perhaps it can help someone else that finds himself or herself in my same situation, knows nothing about SOAP like me and doesn't know how to tackle the problem.

huangapple
  • 本文由 发表于 2023年6月26日 16:58:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/76555130.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定