【问题标题】:Securing WCF service using basicHttpBinding which supports streaming使用支持流的 basicHttpBinding 保护 WCF 服务
【发布时间】:2009-05-10 14:18:37
【问题描述】:

我的问题是关于保护对仅向我们公司内部用户公开的 WCF 服务的访问的最佳(也称为“最不痛苦”)方法。目标是确保仅通过我们每个用户安装的单个 Windows 窗体应用程序访问该服务。调用服务时,我希望服务能够验证它是从允许的应用程序调用的。

要保护的服务使用支持流的basicHttpBinding,所以我相信我仅限于传输级别的安全性。

以下是我的服务配置文件中 <bindings><services> 部分的简化版本。

<bindings>
  <basicHttpBinding>
    <binding name="Service1Binding" transferMode="Streamed"/>    
  </basicHttpBinding>
</bindings>

<services>
    <service name="WCFServiceSecurity.Service1" 
        behaviorConfiguration="WCFServiceSecurity.Service1Behavior">
        <endpoint address=""
            binding="basicHttpBinding"
            contract="WCFServiceSecurity.IService1"
            bindingConfiguration="Service1Binding"/>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
    </service>
</services>

谁能提供一些详细信息,说明我需要采取哪些操作才能在此服务上实施安全性?

注意:我是 WCF 新手,完全不熟悉安全性,所以如果我没有提供足够的详细信息,请告诉我。


更新:

作为suggested by marc_s,我想使用某种用户名/密码机制来保护WCF 服务。这为答案提供了更多方向,但我仍然对 如何 实际执行此操作有些模糊。

因为我的服务需要启用流式传输,所以我必须使用 basicHttpBinding 和传输级安全性(对吗?);此外,我的服务中包含的方法只能接受 Stream 对象。

考虑到这些限制以及我使用用户名/密码验证的偏好...

  • 我应该如何修改我的服务的配置文件以强制提供用户名/密码凭据?
  • 我的服务将如何验证提供的凭据?
  • 我的客户端应用程序在拨打电话时如何将凭据传递给服务?
  • 这是否需要使用 SSL,如果需要,所有客户端计算机是否也需要证书?

更新:

在向我的老板解释了我在保护这项服务时遇到的麻烦之后,我被允许尝试 Windows 身份验证路由。可悲的是,我在使用我的 Streamed 服务 (argh) 实现这种类型的身份验证时没有运气。在进行适当的更改(如here 所述 - 唯一的例外是我的transferMode="Streamed")并访问我的服务后,我收到以下错误:

HTTP 请求流不能与 HTTP 身份验证结合使用。禁用请求流式传输或指定匿名 HTTP 身份验证。

然后我偶然发现以下引用 here 提供了一些说明:

您不能进行传输验证。使用流式传输。 如果您必须使用 HTTP 请求流式传输,则必须在没有安全性的情况下运行。

安全工作的方式是:

WCF 客户端向服务器发出 http 请求。

服务器回应说,“你没有被授权,给我一个基本/摘要/等凭据。”

客户端收到该响应并重新发送带有凭据的消息。

现在服务器收到消息,验证凭据,然后继续。 请求流不是为使用该安全模式而设计的。如果是这样,那将非常慢,因为客户端将发送整个流,从服务器获取未授权的消息,然后它必须重新发送带有凭据的整个流。

所以现在我正在寻找意见,您将如何保护启用流式传输的 WCF 服务? 如前所述,某种用户名/密码机制将是首选。随意在这个问题上跳出框框思考......

非常感谢任何帮助!

【问题讨论】:

  • 如果可能,将绑定更改为 StreamedRequest 或 StreamedResponse,您将能够启用传输身份验证。如果必须,请仅使用流式绑定,但我相信您可以将上传和下载拆分到不同的端点以启用此安全性。

标签: wcf wcf-security


【解决方案1】:

嗯,我在解决这个问题时发现了很多关于安全/流媒体的问题。我最终采用的 hack(呃……嗯……解决方法)是创建一个新的 DataContract 继承 MemoryStream 并用 BaseStream 属性(用于保存我想要流式传输的数据)以及用于的适当属性简单的身份验证。

这是生成的 DataContract:

[DataContract]
[KnownType( typeof( MemoryStream ) )] 
public class StreamWithCredentials : MemoryStream
{
    [DataMember]
    public Stream BaseStream { get; set; }

    [DataMember]
    public string Username { get; set; }

    [DataMember]
    public string Password { get; set; }
}

上面的 DataContract 最终成为我的服务方法的输入参数。我的服务采取的第一个操作是根据已知的有效值对提供的凭据进行身份验证,并酌情继续。

现在我确实知道不是最安全的选择,但我的指令是避免使用 SSL(我什至不确定这是否可行无论如何 - 如here 所述)用于此内部流程。

话虽如此,这是我能想到的上述问题的最佳解决方案,希望这可以帮助其他遇到此问题的人。

感谢所有回复的人。

【讨论】:

    【解决方案2】:

    你可以做很多事情:

    • 为每台允许使用您的服务的机器添加一个证书,并检查该证书。这只允许您排除“未经授权”的机器 - 您不能将其限制为特定的应用程序
    • 同上,但包含嵌入在您的 winforms 应用程序中的证书并从那里发送(不要将其存储在机器的证书存储中)
    • 需要一个只有您的特定应用程序知道并可以传输到您的服务的用户名/密码;例如其他人将无法出示适当的凭据

    编辑 2:好的,所以用户名/密码方法似乎失控了....在您的 SOAP 消息正文中,在标头中包含一个特定值,然后只检查您的服务中标头中是否存在该元素?

    类似的东西:

    [DataContract]
    class YourRequestData
    {
     ...
    }
    
    [MessageContract]
    public class YourRequest
    {
      [MessageBodyMember]
      public YourRequestData bodyData { get; set; }
    
      [MessageHeader]
      public string AppThumbprint { get; set; }
    }
    

    然后在您的服务器上的代码中检查该AppThumbprint 代码的存在和有效性:

    public Stream RequestStream(YourRequest request)
    {
      if(AppThumbprintIsValid(request.AppThumbprint))
      {
         .... begin your streaming
      }
    }
    

    这最终可能比用户名/密码安全方案容易得多。

    马克

    【讨论】:

    • 我想避免向客户端计算机添加证书,因为应用程序的用户经常更改。我想实现您提到的用户名/密码方法,但我不确定如何将这些值传输到实际服务。服务公开的方法已启用流式传输,因此我无法将这些值作为参数传递(由于启用流式传输的服务的方法签名限制);您能推荐一种将 un/pw 组合传递给服务并在服务内进行身份验证的方法吗?
    • 如上修改服务配置并运行服务后,我收到错误消息“BasicHttp 绑定要求 BasicHttpBinding.Security.Message.ClientCredentialType 等效于 BasicHttpMessageCredentialType.Certificate 凭据类型以获取安全消息。选择用户名凭据的传输或 TransportWithMessageCredential 安全性。”。我认为启用流式传输的端点需要传输级别的安全性?另外,在 标记中,我认为绑定值是 basicHttpBinding 而不是 basicHttpConfiguration。
    • 感谢您对 Marc 的所有帮助,但不幸的是,我认为这种方法(编辑 2)不适用于我的具体情况。被调用的服务方法必须既接受又返回一个 Stream。你的回答提出了一个有趣的想法;我想我可以继承一个 Stream 并用一些 un/pw 属性装饰它;此 Stream 可能是我的服务方法的输入参数(请注意,不要太安全)。但鉴于 WCF 明显的灵活性,我不得不假设有更好的方法......嗯。
    【解决方案3】:

    如果我错了,请纠正我,但是:

    如果您为 WCf 服务(在 asp.net 上)使用表单身份验证,只需向您的服务添加登录方法,在其中创建所需的 cookie(formsAuthentication.Authenticate())。它与响应一起自动发送,然后客户端可以调用流 API 而不需要额外的参数(要求它是 STREAM),并且您可以在触发返回流之前检查流 API 中的身份。

    至于保护对整个 WCF 的访问,我觉得在 .net 应用程序中嵌入证书是一种方法。他们将不得不 ildump 您的应用程序才能使用它。

    您可以告诉 asp.net/wcf 不要提供 wsdl,或者更准确地说,不要自动生成 wsdl。如果没有 wsdl 访问权限,他们生成代理会变得更加困难......

    【讨论】:

      【解决方案4】:

      如果您想使用basicHttpBinding(用于互操作),您只能在消息级别传递您的凭据。您必须将您的安全配置设置为TransportWithMessageCredential

      要做到这一点,您必须创建一个 SSL 通道,因此您需要在服务器端有一个证书,而客户端没有必要拥有一个。

      【讨论】:

        【解决方案5】:

        可以将 Windows 身份验证与 Streaming 和 SSL 一起使用,但您必须使用 TransportWithMessageCredential

        <basicHttpBinding>
            <binding name="FileService.FileServiceBinding" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" transferMode="Streamed">
                <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
                <security mode="TransportWithMessageCredential">
                    <transport clientCredentialType="Windows" />
                </security>
            </binding>
        </basicHttpBinding>
        

        您需要在代码中设置proxy.ClientCredentials.UserName.UserNameproxy.ClientCredentials.UserName.Password

        【讨论】:

        • 我认为 TransportWithMessageCredential 不适用于 basicHttpBinding,只能用于 wsHttpBinding?
        【解决方案6】:

        如果这将是一个驻留在 Intranet 上的应用程序,那么在您的 Active Directory 中创建一个新组并只授予该组的成员使用该服务的能力可能是最简单的。

        您可以使用以下方式添加身份验证(使用 Windows 凭据):

        <basicHttpBinding> 
         <security mode="TransportCredentialOnly"> 
          <transport clientCredentialType="Windows" /> 
         </security> 
        </basicHttpBinding> 
        

        然后可以通过将接口装饰到您的服务方法来进行授权:

        <PrincipalPermission(SecurityAction.Demand, Role:="MyAppsUsers")> _ 
        Public Function MyMethod() As String Implements IService.MyMethod 
        

        这是 WCF 中安全性的一个很好的链接。最后有很多 How To(标题为“How To - Use basicHttpBinding with Windows Authentication and TransportCreditals”的内容可能对您有用)。
        Wcf Secruity

        [免责声明:我也是 WCF 的新手,之前没有做过这个确切的案例,所以如果这有点不对劲,我深表歉意!]

        【讨论】:

        • 由于我们试图确保仅从单个应用程序访问 WCF 服务,我认为使用 Windows 凭据不会这样做,因为这些用户可能会从应用程序外部调用该服务(如果我错了纠正我)。为服务提供用户名/密码似乎是可行的方法(根据我有限的经验)。感谢您提供指向 WCF 安全指南的链接,我还将查看该链接以了解可以应用于我的方案的内容。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多