Windows Communication Foundation 可以执行大量繁重的任务,以便使您的服务能够更轻松地提供大多数分布式系统所需的基本安全功能。大多数标准 Windows? Communication Foundation 绑定都提供三大保护功能:保密性、完整性和身份验证(或称 CIA,因为我喜欢这样称呼)。如果您不需要这些保护,您必须将其关闭,因为它们在默认情况下处于打开状态。 CIA 和授权可以为您做什么那么每种保护各具有什么作用呢?保密性可确保对消息进行加密,使窃听者无法阅读消息的内容。完整性可确保您使用密钥哈希对每个消息的内容执行校验和操作,以便知道消息仍保持原样,未被篡改,也没有被攻击者成批注入到消息流中。当然,如果连接的另一端是敌人,则对连接进行加密将毫无意义!因此,为了交换用于提供保密性和完整性的密钥,Windows Communication Foundation 使用了一种身份验证握手机制,它不仅可帮助客户端和服务发现这些密钥,还可以帮助他们发现彼此的标识。 一旦服务知道了客户端的标识,它即可以授权客户端执行各种操作。授权是通过检查客户端提供的声明来进行的。Windows Communication Foundation 提供了多种可扩展性挂钩,允许您应用所选择的授权策略,并检查声明的有效性。您可以使用现有的组件,比如 ASP.NET 成员身份、角色提供程序和授权管理器 (AzMan),有关它们的更多信息,您可以在 msdn.microsoft.com/msdnmag/issues/03/11/AuthorizationManager 上找到。您还可以结合 Thread.CurrentPrincipal、IPrincipal.IsInRole 和 PrincipalPermissionAttribute 一起使用基于标准 .NET 角色的安全基础结构。或者,您可以在 Windows Communication Foundation 中以 IAuthorizationPolicy 接口为中心使用授权策略框架,该接口可以对声明实施精细的控制。您也可以审核客户端的操作。您会发现,Windows Communication Foundation 本身已经可以为您审核许多安全事件。 构建安全系统时,透明性很重要。如果您内置于系统中的安全功能相对并不透明,用户会失去兴趣,并通常会避免使用这些功能。作为从事安全工作的人,我的最得意之作总是看不见摸不着的,这虽然让人有点伤感,但却是事实!Windows Communication Foundation 可帮助您以多种方式实现透明性,但最重要的方式之一是通过单一登录。通过紧紧绑定到 Windows 域身份验证,您可以利用用户的域登录,并减少其需要跟踪的凭据的数量。Windows Communication Foundation 还使得可以方便地使用联合标识,即使合作伙伴组织使用您公司提供的 Web Services,他们也可以获得同样的单一登录体验。 安全性的另一个重要方面是在面对输入错误时所表现出的可靠性。Windows Communication Foundation 对此也没有有效的应对手段,因此,您仍然有责任预先假定所有输入都是错误的,直到事实证明并非如此。同时也不要想当然地认为,已通过身份验证的用户不会向您发送不正确的输入!即使您仅为内部客户端提供服务,您也必须保持可靠性。我在这里谈论的是抵御攻击的能力,比如 SQL 注入、格式不正确的资源名称(如文件路径),在某些情况下甚至包括跨网站编写脚本。当您听到有人说“Windows Communication Foundation 默认情况下是安全的”这样的话时,您应理解为他们可能说的是 CIA。 Windows Communication Foundation 中的选择Windows Communication Foundation 将我们以前单独使用的无数通信堆栈的最佳功能融汇在了一起。这意味着您在提供服务时,可以有许多种选择,其中的一些选择会影响安全性。最重要的选择涉及使用什么绑定。您是否想让消息排队?您是否需要互操作性或原始性能? 时刻记住您不需要仅仅做出一种选择。您可以通过您希望的任意数量的绑定提供一个单一的服务合同;仅需为每个绑定提供一个不同的端点即可。例如,您可以通过 HTTPS 提供一个非常简单的 WS-I Basic Profile 绑定,以便与供应链中现有的合作伙伴进行互操作。同时,您可以提供一个为域中的本地客户端使用 Windows 身份验证的 TCP 端点。但只有在用户未在合同中指定 ProtectionLevel 属性(使用 ServiceContract、OperationContract、MessageHeader 等)时,此方式才有效。 典型的标准绑定具有大量用于调节安全设置的不同“旋钮”,但每个绑定都已经过仔细调整,可以为您会遇到的大多数情形提供安全的默认设置。您需要最频繁切换的两个“旋钮”是安全模式(传输与消息安全性)和客户端凭据类型。这些“旋钮”非常重要,因此,让我们研究一下如何正确使用。 传输安全性在为 Windows Communication Foundation 绑定配置安全性时,您需要做出的第一个选择,是需要在传输级别还是在消息级别提供 CIA。每种选择各有其优缺点。 如果您为传输安全性配置 wsHttpBinding,Windows Communication Foundation 将不会为您的消息提供 CIA。您需要通过 HTTPS 运行,以便安全套接字层 (SSL) 可以提供这些保证。事实上,除非提供 HTTPS URI,否则 Windows Communication Foundation 将会拒绝设置连接。如果您正在 IIS 内部托管,您将需要为网站安装一个 SSL 证书。另一方面,如果您正在自己的进程中托管,并直接使用 HTTP.SYS,您将需要以编程方式或通过命令行工具 HTTPCFG.EXE 向 HTTP.SYS 注册一个证书。 使用 SSL 有充分的理由。因为 SSL 已经存在了这么多年,密码员已经以它为对象做过大量分析,而且管理员已经弄清了如何对它进行部署。还有现成的硬件可以对其进行加速,以减轻您的服务器的 CPU 负荷。最重要的是,如果您的目标是实现跨平台的广泛访问,则如今再没有比通过 SSL 使用 WS-I Basic Profile 更好的选择了(当然,这也意味着使用 basicHttpBinding 替代 wsHttpBinding)。 对于客户端和服务都使用 Windows Communication Foundation 的域环境中的内部通信,具有传输安全性的 netTcpBinding 可能是一种更好的选择。由于它具有二进制编码,所以性能当然要好得多;又因为默认情况下它只使用 Kerberos,因此,尽管要配置服务主体名称,也无需证书(请参阅“配置服务主体名称”提要栏)。 消息安全性可以不在传输级别提供 CIA,而选择通过使用消息安全性将这些细节向下推入到 SOAP 消息自身中。这种方式的主要优点是灵活性。WS-Security 和用于确保 SOAP 消息安全的相关规范非常灵活;只要客户端和服务都允许,您可以使用所希望的任何安全凭据类型,在很大程度上不受传输影响。实际上,您甚至可以发送多个凭据,在涉及中间方的委派方案中,这很有意义。 以 wsHttpBinding 为例。默认情况下,它使用消息级别的安全性,假定服务和客户端使用 Windows 凭据对其自身进行身份识别和身份验证。默认情况下,对正文和大部分标头都进行签名,以维护消息的完整性(具体而言,它会对所有 WS-Addressing 标头进行签名,并对所有应用程序标头进行加密和签名),并对正文加密。查看消息跟踪信息的攻击者可以毫无阻碍地看到 SOAP 信封,但 SOAP 正文会包含一个 <EncryptedData> 元素,其中填满 base64 编码加密文本。 Windows Communication Foundation 还允许您混合使用传输和消息安全性。在这种模式下,会在传输级别提供保密性和完整性以及服务器的身份验证(因此会加密整个字节流,而不仅仅加密消息正文),而客户端身份验证会在消息级别执行。然后,客户端可以使用 WS-Security 来发送它所需要的任何形式的凭据。这种模式可以使您获得传输安全性所具有的性能和成熟度,并可提高选择凭据的灵活性。 凭据选择了传输安全性或消息安全性或其混合模式后,假定您未选择“None”(无)安全模式,下一个主要决策就是客户端和服务将要使用的凭据的形式。Windows Communication Foundation 只向您提供一个“旋钮”(即客户端凭据类型),从而简化了此决策过程,该“旋钮”还决定每种方案下有意义的服务凭据类型。客户端凭据至少有五个选项,虽然在某些环境下有些选项可能会不可用。 第一个选项为“None”(无),选定时,客户端为匿名客户端。在这种情况下,服务会使用证书来确保服务客户端的标识。这与您通过 HTTPS 访问标准网站时遇到的情况类似。 第二个选项为“UserName”(用户名),选定时,客户端将提供用户名和密码。同样,在这种情况下,服务会使用证书向客户端验证其标识。此证书还将用于加密客户端的凭据,以便传输给服务。 下一个选项是“Windows”,选定时,客户端和服务都会使用 Windows 帐户进行身份验证。Windows Communication Foundation 将会就 Kerberos 或 NTLM 进行协商,如果存在域,则优先选择 Kerberos(NTLM 实际上不会向客户端验证服务的身份,而只会向服务验证客户端的身份)。如果您想要使用 Kerberos,则必须让客户端根据配置中的服务主体名称验证服务的身份。如果您要在域环境中为客户端构建服务,您应明确地为其提供发送 Windows 凭据的选项。这将允许客户端使用其现有的 Windows 登录信息,从而让您免费实现单一登录! “Certificate”(证书)是另一个选项,选定时,服务将具有一个证书,客户端也具有一个其自己的证书。这在当今的许多企业对企业方案中十分常见。 最后,“IssuedToken”允许您的服务从安全性令牌服务 (STS) 接受一组签名的声明。虽然开始时您对此会不易接受,但此选项在以后将会很重要,因为它可以启用联合标识方案和 InfoCard。当您与某个合作伙伴组织联合时,您将允许该合作伙伴通过任何合适的技术对其自己的用户进行身份验证。在最理想的情况下,这将允许该合作伙伴组织中的用户通过单一登录使用您的服务,即便他们并不与您使用同一个 Active Directory 域,或不受您的信任。该合作伙伴组织中的用户需要使用 STS 进行身份验证,而 STS 可以发出一个签名的安全声明标记语言 (Security Assertion Markup Language, SAML) 令牌。您既可以直接接受该令牌,也可以要求将该令牌呈送给您组织中的 STS,以便让其评估该合作伙伴的声明,并发出第二个您可以使用的 SAML 令牌。 在任何一种情况下,您的服务都会收到您信任的 STS 发出的一个安全令牌。Windows Communication Foundation 将会验证该签名和此信任关系,并将该令牌中的声明通过 ServiceSecurityContext 的实例呈送给您的服务。只需读取 ServiceSecurityContext.Current 静态属性,您的服务即可以在对请求进行处理的同时访问此对象。之后,您可以使用此信息来执行授权和审核。 联合的好处在于,它可以自动验证合作伙伴之间现有的信任关系:进行联合时,无需向合作伙伴组织中的每个用户都发布影子 Windows 帐户或证书。自动验证这些关系还有很多好处。自动化可以减少错误和延迟,这意味着您所获得的有关该合作伙伴组织中的用户的信息将更准确和更新。这还可以降低 IT 人员的成本,因为他们不再需要为合作伙伴提供用户帐户。联合标识是一个重要的主题,在以后的专栏文章中,我将花费更多的时间进行探讨。 标准绑定中的默认安全性三种最为流行的标准绑定分别为 basicHttpBinding、wsHttpBinding 和 netTcpBinding。最简单且最具互操作性的是 basicHttpBinding,它支持 WS-I Basic Profile。必须注意的是,这一特定的绑定和其他大多数绑定一样,默认情况下并不提供 CIA。由于 SSL 的普及,确保此绑定安全的最流行的方法是只在 HTTPS 上运行。为此,您将需要调整该绑定,以便让 Windows Communication Foundation 知道您将要使用传输安全性: <bindings> <basicHttpBinding> <binding name="MyBindingTweaks"> <security mode="Transport"> <transport clientCredentialType="None"/> </security> </binding> </basicHttpBinding> </bindings> 完成此操作后,最简单的部署方法是在 IIS 中进行托管,并为您的虚拟目录打开 SSL 支持(这意味着,如果尚未为网站安装证书,则将安装证书)。请注意,在这种特定的绑定中,我已经允许了匿名客户端。如果您要在 IIS 中进行部署,并计划要求提供客户端证书,请将 clientCredentialType 更改为 Certificate。 下一个绑定 wsHttpBinding 默认情况下会对 WS-Security 和 WS-SecureConversation 使用消息安全性。默认的客户端凭据类型为 Windows,这使得起步非常容易;它仅使用客户端和服务的 Windows 登录信息作为凭据。此绑定上最常用的安全性调整,是将其切换为使用 TransportWithMessageCredential。下面您将使用 HTTPS 端点来实现加速的服务器身份验证、完整性和保密性,同时,客户端凭据会留在 SOAP Security 标头中以保持灵活性。这项技术的优点之一,是通过传输对整个 SOAP 信封加密,包括所有标头。它还允许您使用硬件加速,从服务器的 CPU 中卸载安全套接字层/传输层安全性 (SSL/TLS)。不过,也存在着一些缺点,比如缺乏消息级别的端对端安全性。下面显示如何运用此绑定调整在消息级别接受 SAML 令牌,例如: <binding name="MyBindingTweaks"> <security mode="TransportWithMessageCredential"> <transport clientCredentialType="None"/> <message clientCredentialType="IssuedToken"/> </security> </binding> 如果您想让基于 Windows 的 Intranet 上的 Web Services 具有原始速度,则您应认真考虑使用 netTcpBinding,它可以使用 XML Infoset 的专用二进制编码对每个 SOAP 信封进行编码,而不使用传统的尖括号编码。默认情况下,此绑定会将传输安全性与 Windows 凭据结合使用,并且非常高效。这也许是您最接近于 DCOM 的性能和安全模型的情况。默认绑定会将传输安全性与协商的身份验证结合使用。该协商会尝试使用 Kerberos,但如果行不通,它会回退并使用较旧的 NTLM 协议。Kerberos 是域环境下的理想选择;为了使用它,您需要让服务和客户端均在域帐户下运行。您还需要为您的服务配置一个服务主体名称 (SPN),如本页的提要栏中所示。客户端将需要调整其端点说明,以包括服务的标识,即服务所注册的 SPN。(并不总是需要此 SPN。如果服务托管于 IIS 中并在 NetworkService 帐户下运行,则会自动提供 SPN。Windows Communication Foundation 会从客户端上的 URL 中准确推断出该 SPN。)下面是在配置中实现这一目的语法。请注意 servicePrincipalName 元素: <client> <endpoint name="MyEndpoint" address="net.tcp://..." binding="netTcpBinding" contract="IFoo" > <identity> <servicePrincipalName value=‘MyService/MyMachine‘ /> </identity> </endpoint> </client> 当客户端的 Windows Communication Foundation 的探测功能让域控制器为服务提供 Kerberos 票证时,它将使用 MyService/MyMachine 名称来请求该票证,而且,只要此 SPN 已经在 Active Directory 中为该服务的域帐户注册,就会给客户端发布票证,并会使用 Kerberos。否则,如果 Kerberos 可用,但 SPN 不正确,则会引发一个异常。如果不能使用 Kerberos 向服务进行身份验证,则客户端将不会获得票证(白白浪费到域控制器的往返操作),并且您将进入 NTLM 回退模式,这意味着会为回退协商进行更多的往返操作。另外,您将无法获得 Kerberos 的功能,比如委托客户端凭据的潜在能力。 发现客户端标识在用于发现客户端标识的各种方法中,最简单的方法是利用 Thread.CurrentPrincipal,它是用于探测的 .NET 中(比如 ASP.NET 中)的标准方法,而 Windows Communication Foundation 会将已经过身份验证的客户端的标识传递到您的代码中。这个颇为神奇的静态属性会根据向它提出请求的线程返回不同的值。这将允许您通过多个线程为不同的客户端提供服务,其中每个线程都可以看到所服务的客户端的标识而不会相互干扰。 如果您已经将 Windows 指定为 clientCredentialType,则 Thread.CurrentPrincipal 将指向 WindowsPrincipal,并且您可以通过调用 WindowsPrincipal.IsInRole 来查看用户属于哪个组。此处唯一的一个小问题是,由于安全方面的原因,您应该指定完全限定的组名称,其中包括对该组进行定义的域或计算机,如下所示: IPrincipal client = Thread.CurrentPrincipal; if (client.IsInRole(@"MyMachine\Managers")) { // 允许客户端进行管理 } 我在构建基于这样的组进行授权的系统时,通常会添加某一级别的间接寻址,它可以通过查看配置提供所使用的组的计算机名或域名。这样做会大大简化部署过程。 我将在以后的专栏文章中进一步讨论授权 — 关于这个主题,要说的内容很多。请注意:Windows Communication Foundation 并不总会设置 Thread.CurrentPrincipal。只有在使用 PrincipalPermissionAttribute 时或在配置要求时,才会进行设置。您应该使用 ServiceSecurityContext.Current.WindowsIdentity 来获取客户端的标识(如果可用),而不应依赖于 Thread.CurrentPrincipal。下面显示了在需要记录客户端操作的情况下如何获取客户端的名称: string clientAccountName = ServiceSecurityContext.Current.WindowsIdentity.Name; 如果客户端在使用已发布的令牌凭据进行身份验证,您将需要使用 ServiceSecurityContext.AuthorizationContext 来拾取这些详细信息。如果客户端在使用未映射到 Windows 帐户的证书进行身份验证,则可以使用 ServiceSecurityContext.Current.PrimaryIdentity。我打算以后进一步探讨这些主题。 通过 HTTPCFG 安装证书如果您想要使用 SSL,但并不打算将您的服务托管于 IIS 中,则您可以使用 HTTP.SYS 来提供 SSL 支持。为了使用 HTTP.SYS 中的 SSL 支持,您需要告诉 HTTP.SYS 在何处查找其 SSL 证书;您可以使用 HTTP API 实现这一目的,或使用 HTTPCFG.EXE 从命令行调用这些 API。默认情况下并不安装 HTTPCFG.EXE,但您可以通过安装操作系统安装磁盘的 SUPPORT\TOOLS 目录中的支持工具,来获得该工具。 如果您想将证书与 HTTP.SYS 结合使用,您需要在本地计算机存储中而不是在用户存储中安装 HTTP.SYS。您可以通过运行“证书”Microsoft? 管理控制台 (MMC) 管理单元来执行此操作;添加该管理单元时,请确保在询问时选择“计算机帐户”,然后选择部署了该服务的计算机,或者,如果您已经登录部署了该服务的计算机,则选择“本地计算机”。然后将证书导入到该计算机的“个人”存储中。“个人”存储是您通常放置您拥有其私钥的证书的位置。 查看证书的属性并获取证书的 SHA-1 指纹(请参阅图 1)。这是 HTTP.SYS 查找证书的方式,因此您将需要此值。现在,在部署了该服务的计算机的命令提示符下执行以下命令,这是您使用 HTTP.SYS 注册证书时要使用的命令: HTTPCFG add ssl -i 0.0.0.0:4242 31883a61892d8c... ![]() 图 1 证书指纹 您看到的第一个数字是一个 IP 地址 0.0.0.0,它表示该计算机可能具有的所有 IP 地址。如果要绑定到特定的 IP 地址,您应该使用那个 IP 地址的值来代替。接下来是服务要侦听的端口号。最后是指纹(如果是从证书查看器中复制此内容,您需要删除字节之间的空格)。为简便起见,我只显示了该哈希的第一部分,因为它有 20 个字节长。
|
|