实现通过 SSL 使用 WebServices 的 C# 客户端?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/853896/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Implement a C# Client that uses WebServices over SSL?
提问by Mat Nadrofsky
So I've got a ServiceReference added to a C# Console Application which calls a Web Service that is exposed from Oracle.
因此,我将 ServiceReference 添加到 C# 控制台应用程序,该应用程序调用从 Oracle 公开的 Web 服务。
I've got everything setup and it works like peaches when it's not using SSL (http). I'm trying to set it up using SSL now, and I'm running into issues with adding it to the Service References (or even Web References). For example, the URL (https) that the service is being exposed on, isn't returning the appropriate web methods when I try to add it into Visual Studio.
我已经完成了所有设置,当它不使用 SSL (http) 时,它就像桃子一样工作。我现在正在尝试使用 SSL 进行设置,但在将其添加到服务引用(甚至 Web 引用)时遇到了问题。例如,暴露服务的 URL (https) 在我尝试将其添加到 Visual Studio 时没有返回适当的 Web 方法。
The underlying connection was closed: An unexpected error occurred on a send. Received an unexpected EOF or 0 bytes from the transport stream. Metadata contains a reference that cannot be resolved: 'https://srs204.mywebsite.ca:7776/SomeDirectory/MyWebService?WSDL'
基础连接已关闭:发送时发生意外错误。从传输流中收到意外的 EOF 或 0 字节。元数据包含无法解析的引用:' https://srs204.mywebsite.ca:7776/SomeDirectory/MyWebService?WSDL'
Another quandary I've got is in regards to certificate management and deployment. I've got about 1000 external client sites that will need to use this little utility and they'll need the certificate installed in the appropriate cert store in order to connect to the Web Service. Not sure on the best approach to handling this. Do they need to be in the root store?
我遇到的另一个困境是关于证书管理和部署。我有大约 1000 个外部客户端站点需要使用这个小实用程序,他们需要在适当的证书存储中安装证书才能连接到 Web 服务。不确定处理此问题的最佳方法。他们需要在根存储中吗?
I've spent quite a few hours on the web looking over various options but can't get a good clean answer anywhere.
我在网上花了好几个小时查看各种选项,但在任何地方都找不到一个好的干净的答案。
To summarize, I've got a couple of questions here:
总而言之,我在这里有几个问题:
1) Anybody have some good links on setting up Web Services in Visual Studio that use SSL?
1) 任何人都有一些关于在使用 SSL 的 Visual Studio 中设置 Web 服务的好链接?
2) How should I register the certificate? Which store should it exist in? Can I just use something like CertMgr to register it?
2)我应该如何注册证书?它应该存在于哪个商店?我可以使用 CertMgr 之类的东西来注册它吗?
There's gotta be a good book/tutorial/whatever that will show me common good practices on setting something like this up. I just can't seem to find it!
必须有一本好书/教程/任何可以向我展示设置此类内容的常见良好做法的东西。我就是找不到!
采纳答案by Mat Nadrofsky
Well, I've figured this out. It took me far longer than I care to talk about, but I wanted to share my solution since it's a HUGE pet peeve of mine to see the standard. "Oh I fixed it! Thanks!" posts that leave everyone hanging on what actually happened.
嗯,我已经想通了。我花了比我想谈论的时间长得多的时间,但我想分享我的解决方案,因为看到标准让我非常恼火。“哦,我修好了!谢谢!” 帖子让每个人都在关注实际发生的事情。
So.
所以。
The root problem was that by default Visual Studio 2008 uses TLS for the SSL handshake and the Oracle/Java based Webservice that I was trying to connect to was using SSL3.
根本问题是,默认情况下,Visual Studio 2008 使用 TLS 进行 SSL 握手,而我尝试连接的基于 Oracle/Java 的 Web 服务使用的是 SSL3。
When you use the "Add Service Reference..." in Visual Studio 2008, you have no way to specify that the security protocolfor the service point manager should be SSL3.
在 Visual Studio 2008 中使用“添加服务引用...”时,您无法指定服务点管理器的安全协议应为 SSL3。
Unless.
除非。
You take a static WSDL document and use wsdl.exe to generate a proxy class.
您获取静态 WSDL 文档并使用 wsdl.exe 生成代理类。
wsdl /l:CS /protocol:SOAP /namespace:MyNamespace MyWebService.wsdl
Then you can use the C Sharp Compilerto turn that proxy class into a library (.dll) and add it to your .Net projects "References".
然后您可以使用C Sharp Compiler将该代理类转换为库 (.dll) 并将其添加到您的 .Net 项目“参考”中。
csc /t:library /r:System.Web.Services.dll /r:System.Xml.dll MyWebService.cs
At this point you also need to make sure that you've included System.Web.Services in your "References" as well.
此时,您还需要确保在“参考”中也包含 System.Web.Services。
Now you should be able to call your web service without an issue in the code. To make it workyou're going to need one magic line of code added before you instantiate the service.
现在您应该能够调用您的 Web 服务而不会出现代码问题。为了使其工作,您需要在实例化服务之前添加一行神奇的代码。
// We're using SSL here and not TLS. Without this line, nothing workie.
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
Okay, so I was feeling pretty impressed with myself as testing was great on my dev box. Then I deployed to another client box and it wouldn't connect again due to a permissions/authority issue. This smelled like certificates to me (whatever they smell like). To resolve this, I used certmgr.exeto register the certificate for the site to the Trusted Root on the Local Machine.
好的,所以我对自己印象非常深刻,因为我的开发箱上的测试很棒。然后我部署到另一个客户端,由于权限/权限问题,它不会再次连接。这对我来说就像证书(无论它们闻起来如何)。为了解决这个问题,我使用 certmgr.exe将站点的证书注册到本地机器上的受信任根。
certmgr -add -c "c:\someDir\yourCert.cer" -s -r localMachine root
This allows me to distribute the certificate to our client sites and install it automatically for the users. I'm still not sure on how "security friendly" the different versions of windows will be in regards to automated certificate registrations like this one, but it's worked great so far.
这允许我将证书分发到我们的客户端站点并为用户自动安装。我仍然不确定不同版本的 Windows 在像这样的自动证书注册方面会有多“安全友好”,但到目前为止效果很好。
Hope this answer helps some folks. Thanks to blowdart too for all of your help on this one and providing some insight.
希望这个回答能帮助到一些人。也感谢 blowdart 为您提供的所有帮助并提供了一些见解。
回答by blowdart
It sounds like the web service is using a self signed certificate. Frankly this isn't the best approach.
听起来 Web 服务正在使用自签名证书。坦率地说,这不是最好的方法。
Assuming you're a large organisation and it's internal you can setup your own trusted certificate authority, this is especially easy with Active Directory. From that CA the server hosting the Oracle service could request a certificate and you can use AD policy to trust your internal CA's root certificate by placing it in the trusted root of the machine store. This would remove the need to manually trust or accept the certificate on the web service.
假设您是一个大型组织并且它是内部组织,您可以设置自己的可信证书颁发机构,这对于Active Directory尤其容易。托管 Oracle 服务的服务器可以从该 CA 请求证书,您可以使用 AD 策略来信任您的内部 CA 的根证书,方法是将其放置在机器存储的受信任根中。这将消除手动信任或接受 Web 服务上的证书的需要。
If the client machines are external then you're going to have to get the folks exposing the service to either purchase a "real" certificate from one of the well known CAs like Verisign, Thawte, GeoTrust etc. or as part of your install bundle the public certificate and install it into Trusted Root certificate authorities at the machine level on every machine. This has problems, for example no way to revoke the certificate, but will remove the prompt.
如果客户端机器是外部的,那么你将不得不让那些公开服务的人从 Verisign、Thawte、GeoTrust 等知名 CA 之一购买“真实”证书,或者作为安装包的一部分公共证书并将其安装到每台机器上机器级别的受信任根证书颁发机构中。这有问题,例如无法撤销证书,但会删除提示。
回答by Mat Nadrofsky
Mat,
垫,
I had such issues too and I have a way to avoid using certmgr.exe to add certificates to trusted root on a remote machine.
我也有这样的问题,我有办法避免使用 certmgr.exe 将证书添加到远程机器上的受信任根。
X509Store store;
store = new X509Store("ROOT", StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
store.Add(certificate);
The 'certificate object' can be created like this:
可以像这样创建“证书对象”:
X509Certificate2 certificate = new X509Certificate2("Give certificate location path here");
回答by Andrew Bruce
Thanks for this great tip, took a quick look around at your stuff and you have a lot of good ideas going on. Here's my little bit to add -- I'm figuring out webMethods and (surprise!) it has the same problems as the Oracle app server you connected to (SSL3 instead of TLS). Your approach worked great, here's my addendum.
感谢这个伟大的提示,快速浏览一下你的东西,你有很多好主意。这是我要补充的一点 - 我正在弄清楚 webMethods 并且(令人惊讶!)它与您连接到的 Oracle 应用程序服务器(SSL3 而不是 TLS)具有相同的问题。你的方法很有效,这是我的附录。
Given static class "Factory," provide these two handy-dandy items:
给定静态类“Factory”,提供这两个方便的项目:
/// <summary>
/// Used when dispatching code from the Factory (for example, SSL3 calls)
/// </summary>
/// <param name="flag">Make this guy have values for debugging support</param>
public delegate void CodeDispatcher(ref string flag);
/// <summary>
/// Run code in SSL3 -- this is not thread safe. All connections executed while this
/// context is active are set with this flag. Need to research how to avoid this...
/// </summary>
/// <param name="flag">Debugging context on exception</param>
/// <param name="dispatcher">Dispatching code</param>
public static void DispatchInSsl3(ref string flag, CodeDispatcher dispatcher)
{
var resetServicePoint = false;
var origSecurityProtocol = System.Net.ServicePointManager.SecurityProtocol;
try
{
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Ssl3;
resetServicePoint = true;
dispatcher(ref flag);
}
finally
{
if (resetServicePoint)
{
try { System.Net.ServicePointManager.SecurityProtocol = origSecurityProtocol; }
catch { }
}
}
}
And then to consume this stuff (as you have no doubt already guessed, but put a drum roll in here anyway):
然后消费这些东西(你肯定已经猜到了,但无论如何都要在这里放一个鼓卷):
var readings = new ArchG2.Portal.wmArchG201_Svc_fireWmdReading.wmdReading[] {
new ArchG2.Portal.wmArchG201_Svc_fireWmdReading.wmdReading() {
attrID = 1, created = DateTime.Now.AddDays(-1), reading = 17.34, userID = 2
},
new ArchG2.Portal.wmArchG201_Svc_fireWmdReading.wmdReading() {
attrID = 2, created = DateTime.Now.AddDays(-2), reading = 99.76, userID = 3
},
new ArchG2.Portal.wmArchG201_Svc_fireWmdReading.wmdReading() {
attrID = 3, created = DateTime.Now.AddDays(-5), reading = 82.17, userID = 4
}
};
ArchG2.Portal.Utils.wmArchG201.Factory.DispatchInSsl3(ref flag, (ref string flag_inner) =>
{
// creates the binding, endpoint, etc. programatically to avoid mucking with
// SharePoint web.config.
var wsFireWmdReading = ArchG2.Portal.Utils.wmArchG201.Factory.Get_fireWmdReading(ref flag_inner, LH, Context);
wsFireWmdReading.fireWmdReading(readings);
});
That does the trick -- when I get some more time I'll solve the threading issue (or not).
这就是诀窍——当我有更多时间时,我将解决线程问题(或不解决)。
回答by Ricardo Pardini
Since I have no reputation to comment, I'd like to mention that Mat Nadrofsky's answer and code sample for forcing SSL3 is also the solution for an error similar to
由于我没有评论的声誉,我想提一下,Mat Nadrofsky 的答案和用于强制 SSL3 的代码示例也是类似以下错误的解决方案
An error occurred while making the HTTP request to https://xxxx/whatever. 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.
向https://xxxx/whatever发出 HTTP 请求时发生错误。这可能是由于在 HTTPS 情况下未使用 HTTP.SYS 正确配置服务器证书这一事实。这也可能是由于客户端和服务器之间的安全绑定不匹配造成的。
Just use
只需使用
// We're using SSL here and not TLS. Without this line, nothing workie.
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
as mentioned by Mat. Tested with an SAP NetWeaver PI server in HTTPS. Thanks!
正如马特所提到的。在 HTTPS 中使用 SAP NetWeaver PI 服务器进行测试。谢谢!