实现使用SSL上的Web服务的C#客户端?

时间:2009-05-12 17:25:44

标签: c# visual-studio web-services ssl console-application

所以我已经将一个ServiceReference添加到C#控制台应用程序中,该应用程序调用从Oracle公开的Web服务。

我已经完成了所有设置,当它不使用SSL(http)时它就像桃子一样。我现在正尝试使用SSL进行设置,并且我遇到了将其添加到服务引用(甚至Web引用)的问题。例如,当我尝试将该服务添加到Visual Studio中时,该服务所在的URL(https)未返回相应的Web方法。

  

基础连接已关闭:发送时发生意外错误。   从传输流中收到意外的EOF或0字节。   元数据包含无法解析的引用:“https://srs204.mywebsite.ca:7776/SomeDirectory/MyWebService?WSDL

我遇到的另一个窘境是关于证书管理和部署。我有大约1000个外部客户端站点需要使用这个小实用程序,他们需要安装在相应的证书库中的证书才能连接到Web服务。不确定处理此问题的最佳方法。他们需要在根店吗?

我花了几个小时在网上查看各种选项,但无法在任何地方得到一个干净的答案。

总结一下,我在这里有几个问题:

1)有人在Visual Studio中使用SSL设置Web服务有一些很好的链接吗?

2)我应该如何注册证书?应该存在哪个商店?我可以使用像CertMgr这样的东西进行注册吗?

必须有一本好的书/教程/任何能够向我展示设置此类内容的常见良好实践。我似乎无法找到它!

5 个答案:

答案 0 :(得分:30)

嗯,我已经弄明白了。我花了很长时间来讨论,但我想分享我的解决方案,因为看到标准是我的一个巨大的诱惑。 “哦,我修好了!谢谢!”这些帖子让每个人都挂在实际发生的事情上。

所以

根本问题是默认情况下,Visual Studio 2008使用TLS进行SSL握手,而我尝试连接的基于Oracle / Java的Web服务使用SSL3。

在Visual Studio 2008中使用“添加服务引用...”时,服务点管理器的no way to specify that the security protocol应为SSL3。

除非

您获取静态WSDL文档和use wsdl.exe to generate a proxy class

wsdl /l:CS /protocol:SOAP /namespace:MyNamespace MyWebService.wsdl

然后,您可以使用C Sharp Compiler将该代理类转换为库(.dll)并将其添加到.Net项目“References”中。

csc /t:library /r:System.Web.Services.dll /r:System.Xml.dll MyWebService.cs

此时您还需要确保您在“参考”中也包含了System.Web.Services。

现在,您应该能够在代码中没有问题的情况下调用您的Web服务。要使其工作,在实例化服务之前,您将需要添加一行神奇的代码。

// We're using SSL here and not TLS. Without this line, nothing workie.
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;

好的,所以我对自己印象非常深刻,因为我的开发盒测试很棒。然后我部署到另一个客户端框,由于权限/权限问题它将无法再次连接。这闻起来像我的证书(无论它们闻起来像什么)。要解决此问题,我used certmgr.exe将站点的证书注册到本地计算机上的受信任根目录。

certmgr -add -c "c:\someDir\yourCert.cer" -s -r localMachine root

这允许我将证书分发到我们的客户端站点并自动为用户安装。我仍然不确定不同版本的Windows对于像这样的自动化证书注册有多“安全友好”,但它到目前为止工作得很好。

希望这个答案可以帮助一些人。感谢blowdart也为您提供了所有帮助,并提供了一些见解。

答案 1 :(得分:4)

听起来Web服务正在使用自签名证书。坦率地说,这不是最好的方法。

假设您是一个大型组织而且它是内部的,您可以设置自己的可信证书颁发机构,Active Directory这一点尤为简单。从该CA,托管Oracle服务的服务器可以请求证书,您可以使用AD策略通过将其置于计算机存储的受信任根目录中来信任内部CA的根证书。这将消除手动信任或接受Web服务上的证书的需要。

如果客户端计算机是外部的,那么您将不得不让公开服务的人员从Verisign,Thawte,GeoTrust等知名CA购买“真实”证书,或者作为其中一部分您的安装捆绑了公共证书,并将其安装到每台计算机上的计算机级别的受信任的根证书颁发机构中。这有问题,例如无法撤销证书,但会删除提示。

答案 2 :(得分:1)

垫,

我也有这样的问题,我有办法避免使用certmgr.exe将证书添加到远程计算机上的受信任root。

X509Store store;
store = new X509Store("ROOT", StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
store.Add(certificate);

可以像这样创建“证书对象”:

X509Certificate2 certificate = new X509Certificate2("Give certificate location path here");

答案 3 :(得分:1)

感谢您提供这个精彩的提示,快速浏览一下您的内容,并且您有很多好主意。这是我的一点点补充 - 我正在弄清楚webMethods和(惊喜!)它与你连接的Oracle应用服务器(SSL3而不是TLS)有同样的问题。你的方法很有效,这是我的附录。

给定静态类“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 { }
    }
  }
}

然后消耗这些东西(你毫无疑问已经猜到了,但无论如何都要在这里放一个鼓):

    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);
    });

这就是诀窍 - 当我得到更多时间时,我会解决线程问题(或不是)。

答案 4 :(得分:1)

由于我没有评论的声誉,我想提一下,Mat Nadrofsky的答案和强制SSL3的代码示例也是类似于

的错误的解决方案
  

制作时出错   对https://xxxx/whatever的HTTP请求。   这可能是因为这个事实   未配置服务器证书   适当地使用HTTPS中的HTTP.SYS   案件。这也可能是由a引起的   安全绑定不匹配   在客户端和服务器之间。

只需使用

// We're using SSL here and not TLS. Without this line, nothing workie.
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;

如Mat所述。使用HTTPS中的SAP NetWeaver PI Server进行测试。谢谢!