使用支持流的 basicHttpBinding 保护 WCF 服务
-
21-08-2019 - |
题
我的问题是关于安全访问仅向我们公司内部用户公开的 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 新手,对安全性一点也不熟悉,所以如果我没有提供足够的详细信息,请告诉我。
更新:
作为 由 marc_s 建议, ,我想使用某种用户名/密码机制来保护 WCF 服务。这为答案提供了更多方向,但我仍然有点模糊 如何 真正做到这一点。
因为我的服务需要启用流式传输,所以我必须使用 basicHttpBinding 和传输级别安全性(对吗?);除此之外,我的服务中包含的方法只能接受 Stream 对象。
考虑到这些限制以及我对使用用户名/密码验证的偏好......
- 我应该如何修改服务的配置文件以强制提供用户名/密码凭据?
- 我的服务将如何验证提供的凭据?
- 拨打电话时,我的客户端应用程序将如何向服务传递凭据?
- 这是否需要使用 SSL,如果需要,所有客户端计算机是否也需要证书?
更新:
在向老板解释了我在确保这项服务安全方面遇到的麻烦后,我获准尝试 Windows 身份验证途径。遗憾的是,我没能用我的流服务实现这种类型的身份验证(唉)。进行适当的更改后(如概述 这里 - 唯一的例外是我的 transferMode="Streamed"
)并访问我的服务时,出现以下错误:
HTTP 请求流不能与 HTTP 身份验证结合使用。禁用请求流或指定匿名 HTTP 身份验证。
然后我偶然发现了以下引用 这里 其中提供了一些澄清:
您无法进行传输身份验证。与流媒体。 如果必须使用 HTTP 请求流,则必须在没有安全性的情况下运行。
安全性的工作方式是:
WCF 客户端向服务器发出 http 请求。
服务器回复说:“您未获得授权,请向我发送基本/摘要/等凭据。”
客户端收到该响应并重新发送带有附加凭据的消息。
现在,服务器收到消息,验证凭据,然后继续。请求流并非旨在与该安全模式配合使用。如果这样做,速度会非常慢,因为客户端将发送整个流,从服务器获取未经授权的消息,然后必须使用凭据重新发送整个流。
所以现在我正在寻求意见, 您将如何保护支持流式传输的 WCF 服务? 如前所述,某种用户名/密码机制将是首选。请随意跳出框框思考这个问题......
任何帮助都是 大大地 赞赏!
解决方案
嗯,在解决这个问题时,我发现了很多有关安全/流媒体的问题。我最终采用的黑客(呃...嗯...解决方法)是创建一个继承 MemoryStream 的新 DataContract 并用 BaseStream 属性(用于保存我想要流式传输的数据)以及用于的适当属性来装饰它简单的身份验证。
这是生成的数据契约:
[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 (我什至不确定这是否可能 - 正如所述 这里)对于这个内部过程。
话虽这么说,这是我能想到的解决上述问题的最佳解决方案,希望这可以帮助其他遇到此问题的人。
感谢所有回复的人。
其他提示
您可以做很多事情:
- 向每台允许使用您的服务的计算机添加证书,并检查该证书。这只允许您排除“未经授权”的机器 - 您不能将其限制为特定应用程序
- 与上面相同,但包含嵌入到 winforms 应用程序中的证书并从那里发送它(不要将其存储在计算机的证书存储中)
- 需要只有您的特定应用程序知道并可以传输到您的服务的用户名/密码;例如其他人将无法出示适当的凭证
编辑2:好吧,所以用户名/密码方法似乎失控了......如果您只有基本传输安全 (SSL) 来进行基本保护,然后使用 MessageContract
要定义 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
}
}
这最终可能比用户名/密码安全场景容易得多。
马克
如果我错了请纠正我,但是:
如果您正在为 WCF 服务(在 asp.net 上)使用表单身份验证,只需向您的服务添加登录方法,在其中创建所需的 cookie (formsAuthentication.Authenticate())。它会自动与响应一起发送,然后客户端可以调用流 API,而不需要额外的参数(要求它是 STREAM),并且您可以在触发返回流之前检查流 api 中的身份。
至于保护对整个 WCF 的访问,我感觉在 .net 应用程序中嵌入证书是一种方法。他们必须通过 ildump 你的应用程序才能获得它。
您可以告诉 asp.net/wcf 不要提供 wsdl,或者更准确地说,不要自动生成 wsdl。如果没有 wsdl 访问权限,他们生成代理就会变得更加困难......
如果你想使用 basicHttpBinding
(对于互操作)您只能在消息级别传递您的凭据。您必须将安全配置设置为 TransportWithMessageCredential
.
为此,您必须创建一个 SSL 通道,因此您需要在服务器端获得一个证书,而客户端则不需要拥有一个证书。
可以将 Windows 身份验证与流式传输和 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.UserName
和 proxy.ClientCredentials.UserName.Password
.
如果这将是一个驻留在 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 安全性的一个很好的链接。最后有很多“操作方法”(标题为“操作方法 - 将 basicHttpBinding 与 Windows 身份验证和 TransportCreditals 一起使用”的内容可能对您有用)。
WCF安全
[免责声明:我也是 WCF 的新手,之前没有做过这个确切的案例,所以如果略有偏差,我深表歉意!]