http://www.cnblogs.com/yang_sy/archive/2011/05/24/2054834.html


 

【摘要】

安全是任何系统至关重要的一个方面,尤其当该系统由分布式的程序和服务组成;安全还是一个非常广泛的话题。因为这些原因,你应该考虑如何在不同的场 景下实现系统的安全。这些关于安全的内容将通过三章内容进行一一介绍。在本章,我们把注意力集中在企业内部WCF服务的安全管理方面。在此场景中,运行 WCF服务的服务端和客户端之间已经存在必要的信任关系;通过客户端访问该服务的用户都来自同一个安全域。WCF服务可以直接访问该域内的信息,并直接使 用这些信息验证用户。在第五章"保护因特网上的WCF服务",你将看到客户端程序和服务分布在不同的安全域内,并且由不安全的网络分隔开。在这种情况下, 不要妄想也不可能直接验证用户。在第十七章"使用Windows CardSpace管理身份",你将看到在联合环境下如何实现一个分身元系统以帮助验证用户。  

【正文】

安全保护运行客户端的用户、服务、及客户端与服务端之间传输的消息。安全包含一系列的议题。最熟悉和广泛的方面就是验证(证明身份)和授权(允许访问基于身份的资源)。此外,在分布式系统中,安全还包含其他许多方面,它们包括:

  • 保持服务端与客户端通信的保密性。网络中被传输的数据可能被嗅探。比如,大量的软件或硬件网络可用性分析工具,许多网络管理员使用这些工具来追踪 网络中的连接问题和带宽问题,但是,恶意用户也可以使用这些工具来追踪网络中传输的包试图完成破坏的目的。这些被拦截的包可能含有财务数据、或者个人隐私 信息、甚至企业内部其他的分支机构的信息。通常,你通过加密来实现保密性。
  • 预防消息被破坏或中断。即使已经可以确保信息的保密性,恶意用户仍可以在消息被传输至目的地之前翻译消息或中断消息。此时,你可以对消息实施哈希算法,然后使用其哈希值对该消息进行数字签名,最后在服务端检查客户端传输过来的消息是否被中断或篡改。
  • 确保消息传递的可验证性。即使恶意用户未能破译消息,那么他可能翻译该消息。翻译消息意味着改变消息,或不传递消息,或不停的发送消息(重放)。 目前,已有多中Schemas用以检测重发问题。它们包括在消息上使用时间戳(当服务端收到消息时,如果消息的时间戳超出合理限制,那么服务端则丢弃该消 息),或为消息指定一个唯一的身份(如果服务收到两个相同身份的消息,那么服务端便知道这两个消息肯定是有问题的)。类似地,使用可靠的消息协议能帮助确 保消息要么在规定的时间类传输至目的地,要么在超出规定时间时向发送端发出警告。在第10章你将了解到更多细节。
  • 预防服务被模拟。在企业内部这种情况不常见。但在因特网中,一个服务可能模拟成另外一个服务以从用户那里获取保密的数据,这种现象被称之为欺骗。 客户端用户程序信任与之通信的真正服务端,但客户端却将详细信息发送至另外一个与真正服务端有相似响应的,但实际上完全不同的另外一个服务端。这意味着在 客户端也必须验证服务端,并且验证该服务端验证客户端身份的服务端是同一个服务端。在第五章你将通过"使用证书实现双向验证"获取更多信息。

应当记住没有绝对安全的系统。黑客和欺诈不断进化,并采取新的方式和手段去翻译,危害,甚至破坏消息流。应对危害的关键点是引入相对应的方法以减少 危害的影响。幸运的是,WCF提供了可扩展的模型,该模型可以吸收新的特性并不断演化,以应对当前的安全问题,并减少新危害的发生。

Windows环境下的验证和授权

验证用户,服务必须提供一种方式供用户验证自己的身份然后证明该身份。许多组织维护一个单独的用户数据库及它们的 验证方式。在Windows环境中,这种方式就是使用活动目录。在单个组织内部,所有的服务和客户端程序都访问同一个活动目录是不可取的,因此这个数据库 定义了系统的安全域。一个服务可以配置为使用活动目录数据库的信息验证用户。当用户使用应用程序访问服务时,将提示用户提供他的用户名和密码,然后将用户 名和密码传输至服务。服务通过查询活动目录验证用户名和密码是否正确。

不管用户在哪个地方运行客户端应用程序,上述方式都可以不错地工作。比如,用户可以在床上使用自己的电脑执行客户端应用程序,客户端程序通过互联网 连接到服务。但是,在办公室用户,已经登陆到企业的安全域后,提示他们再一次输入用户名和密码变得多余了。为什么要让用户始终登录呢? 幸运的是,Windows操作系统提供了相应的支持。如果一个用户成功登录到一个安全域,那么Windows将在用户登录过程中缓存用户凭证的详细信息。 如果用户运行客户端程序去访问一个需要身份验证的服务,Windows将为该服务提供验证方面的详细信息,然后将这些信息推送至服务。该机制就是 Windows集成身份验证。

当服务端验证了客户端用户的身份后,服务开始确定该用户是否被授权访问特定的操作。一般地,管理员授权用户相应的角色,服务的开发人员能识别每个角 色可以访问的操作。WCF可以使用.NET Framework安全性声明去赋予角色能访问的操作,还可以使用角色程序确定一个用户所拥有的角色。.NET Framework提供了三种角色程序,你可以使用它们来存储角色的信息:

  • Windows令牌角色程序,用户基于基于活动目录组
  • ASP.NET 角色程序,用户存储在SQL Server数据库中
  • 授权存储角色程序,通过Microsoft 授权管理器工具定义用户角色,该工具允许把角色信息存储在活动目录或者XML文件中

在本章,你将使用Windows令牌角色程序。该程序是在企业内部使用Windows集成身份认证的最好方式。在第五章,你将看到如何使用ASP.NET角色程序,该程序适用于在internet上发布的服务。

传输和消息的安全

用户身份信息必须从客户端程序传输至服务。但是该信息是敏感的,因此它应该尽可能使用安全方式传输,一般情况下,你需要加密这些信息。当验证完用 户,应该确定客户端和服务之间传输的消息的内容是否也需要加密,这取决于这些消息包含信息的敏感程度。可以在客户端和服务采用多种方式来完成这个目的,但 是关键的是,客户端程序和服务必须协商采取统一的加密机制,并且能互相解密友对方发送过来的加密消息。使用公钥/私钥密码体系可以保证传输安全。(关于公 钥体系,请参考http://technet.microsoft.com/en-us/library /aa998077(EXCHG.65).aspx)

若构建Web服务,当发送和接收消息,你可以在传输和消息这两个级别执行验证和加密。

(1)传输安全

传输级别验证发生在客户端应用程序或服务接收到消息之时,或者在知道将要接收一个消息之时在操作系统层实现。服务可以指定其所需的凭据,但是正确的凭据由操作系统负责提供和验证。

许多通信协议协可以加密和解密其接收和发送的数据。最常见的例子比如HTTPS,它使用安全套接字层(SSL)技术,通过证书所提供的密钥来加密和 解密数据。当客户端使用HTTPS协议连接到该Web服务时,基础传输架构协调客户端和服务端执行加密的程度。然后两者交换含有密钥的证书,该密钥用于双 方加密和解密数据。因为这些都发生在传输层,对客服端和服务都是透明的;所以你需要做的仅仅是指定HTTPS为其通信传输协议。当然,管理员必须为服务的 宿程序安装和配置适当的证书。

注意:在本章,你将在一个自我寄宿WCF服务的程序上配置HTTPS;如果你在IIS中寄宿WCF服务,配置HTTPS的过程将有所不同,具体信息将在第五章中介绍。

你还可以在基于TCP协议上实现传输安全;Windows操作系统在TCP上实现了传输安全(TLS)。TLS是SSL的继承者,并提供与SSL相似的功能。但是,与SSL使用HTTP绑定不一样,在WCF下,TCP绑定自动使用TLS。

命名管道也支持传输安全,但其支持消息安全。

(2)消息安全

服务负责消息级别的验证。用户凭证包含在消 息中,并发送至服务端,服务端必须验证这些凭证是有效的。此外,服务端和客户端都负责消息保密性和一致性。它们使用两者认可的加密算法和一组协商后的密钥 对消息进行加密和解密。WS-Security规范描述了消息层的安全结构,该规范在许多Web服务上已经实现。遵循WS-Security推荐,你能确 保服务和客户端的互操作,因此你应该使用WS-Security规定的技术而不是WCF。

传输安全比消息安全有优势,因为传输安全可以基于硬件支持并且这种支持非常高效。加密和解密数据是一个与资源相关的过程,所以任何能改进性能的方法 都是非常值得尝试的。此外,传输级别的验证检查在客户端程序实际发送应用层的消息前是强制执行的,因此此时执行验证能以较少的网络流量快速识别验证成功亦 或失败。

传输安全最主要的优点在于其基于点对点执行操作。当服务收到消息时,该消息已经被基础传输机制解码。如果一个服务只是简单地传递消息至另外一个服 务,而不是处理该消息。那么该中转服务有足够的权限读取转发消息的内容,这意味着该中间服务在传递消息之前能修改消息或提取消息的保密内容。此时,使用消 息安全能够消除该安全问题。

消息安全提供点对点加密。客户端程序和服务分别做为终点目的地,两者同意对消息使用相同的加密密钥和加密算法。当消息达到中转服务时,消息仍旧是加密了的。如果中间服务无权读取密钥或者不知道加密的算法,那么它就不能轻易地解密消息。

实施消息安全看起来似乎需要对服务做很多开发工作。实际上,WCF简化了很多事请,并且减少了服务端点上标准绑定与这些绑定对应的代码的开发工作。要实现消息层安全, 你所需要做是选择合适的绑定。

在Windows域内实现安全

在下面的练习中,你将了解到在单个企业中的一般场景下如何实现传输安全和消息安全。由于按照顺序来介绍这些概念,大家比较容易的理解。所以,首先你 将会了解到如何通过加密消息以实现消息的保密性;然后,你将了解到如何在Windows环境下实现用户验证;最后,你将了解到如何使用Windows口令 角色程序来授权对服务的访问。

在消息层级别保护基于TCP协议的服务

NetTcpBinding绑定自动在传输级别使用TLS加密数据。NetTcpBinding绑定还支持在消息层加密,让你可以进一步控制你使用的算法。下面的例子展示了如使用消息层安全实现加密消息。

在使用NetTcpBinding绑定的服务上启动消息加密

1. 复制第三章的ProductsServiceFault解决方案到文件夹Chapter4,然后打开该方案,并重命名为ProductsService。

2. 使用WCF配置工具打开ProductsServcieHost下的app.config文件:

WCF4.0进阶系列--第四章 保护企业内部的WCF服务(转)

3. 创建一个新的使用NetTcpBinding的绑定。

WCF4.0进阶系列--第四章 保护企业内部的WCF服务(转)

4. 设置该绑定的名字为"ProductsServiceTcpBindingConfig",然后切换到"安全"标签下。

WCF4.0进阶系列--第四章 保护企业内部的WCF服务(转)

5. 设置安全模式为"Message",加密采用为"Basic128"。该设置将使绑定使用消息层安全;用户将提示输入用户名和密码,所有的消息将使用 128位算法的高级加密标准(AES)来加密。该算法被广泛采用,是因为其执行速度相对很快,而且在企业内部为消息提供了足够的保密性。但是,当你在互联 网上发送消息时,请使用256位的算法(默认算法)。

WCF4.0进阶系列--第四章 保护企业内部的WCF服务(转)

注意:如果你先择安全模式为"None",那么该绑定将不会加密数据,其他传输层和消息层的相关设置将被忽略。如果选择"Transport"模 式,那么绑定将采用传输层安全而非消息层安全。如果选择"TransportWithMessageCredential"模式,那么在消息层实现用户身 份验证,在传输层执行加密。传输层加密比消息曾加密更有效,尽管传输层加密需要管理员做更多的设置,在本章后面内容你将了解到这些设置的细节内容。

6. 选择该服务的端点,然后选择"NetTcp_IProductsService",设置该端点的绑定设置的值为"ProductsServiceTcpBindingConfig"

WCF4.0进阶系列--第四章 保护企业内部的WCF服务(转)

7. 保存配置文件。

8.在Visual Studio开发app.config,你将看到该文件如下面所示:

WCF4.0进阶系列--第四章 保护企业内部的WCF服务(转)

此时,该服务将要求客户端使用相同的消息层全设置,那么我们将在下一步配置客户端。 【关于凭据类型更多消息,请参考http://msdn.microsoft.com/zh-cn/library/ms733836.aspx

在使用NetTcpBinding绑定的客户端上启动消息加密

1.使用WCF配置工具 打开ProductsClient项目下的app.config

WCF4.0进阶系列--第四章 保护企业内部的WCF服务(转)

2. 找到绑定下的NetTcpBinding_IProductsServcie,然后修改安全模式为"Message",加密算法使用"Basic128"

WCF4.0进阶系列--第四章 保护企业内部的WCF服务(转)

3. 保存并退出。

4. 修改program.cs,使其使用NetTcpBinding与服务ProductsService进行通信

ProductsServcieClient proxy = new ProductsServcieClient("NetTcpBinding_IProductsServcie");
Console.WriteLine(
"Test 1: List all products");
string[] procutNumbers = proxy.ListProducts();
foreach (string productNumber in procutNumbers)
{
Console.WriteLine(
"Number: {0}", productNumber);
}

Console.WriteLine(
"\nBinding address:{0}", proxy.Endpoint.Address);

配置WCF服务跟踪消息

1. 使用WCF配置工具打开ProductsServiceHost下的app.config文件,然后设置该服务的诊断信息:

WCF4.0进阶系列--第四章 保护企业内部的WCF服务(转)

LogEntireMessage属性指定追踪是否包括接收和发送消息的body部分;如果为true,那么将包含body部分。如果为false(默认值),那么将只包含Header部分。
LogMessageAtServiceLevel如果设置为true,那么当消息到达服务和离开服务时开始追踪消息。如果你使用消息安全模式;在消息级别,当收到消息时,追踪将显示解密前的消息;当发送消息时,追踪将显示加密前的消息。
LogMessageAtTransportLevel 如果设置为true,在传输级别,接收和发送消息的消息将被追踪。如果你使用消息安全,在传输级别收发的消息是加密后的消息。如果你使用传输层安全,那么 在接收消息时,将显示解密前的消息;在发送消息是,追踪将显示加密前的信息。  

2. 选择诊断下的追踪源,然后点击右键—创建新的追踪源。

WCF所有的追踪信息来自一个或多个追踪源。在本例中,你将使用WCF提供的MessageLogging源,其追踪消息。你还可以指定其他追踪 源。比如ServcieModel源去追踪所有发生在服务上的事件(服务开始监听请求事件,接收请求事件,发送响应事件)。你甚至还可以实现你自定义的追 踪源,尽管它超出本书讨论的范围。

WCF4.0进阶系列--第四章 保护企业内部的WCF服务(转)

3. 选择"System.ServiceModel.MessageLogging"为追踪源。并设置追踪级别为"Verbose"

WCF4.0进阶系列--第四章 保护企业内部的WCF服务(转)

4. 选择诊断下的侦听器,然后右键,创建新的侦听器:

WCF4.0进阶系列--第四章 保护企业内部的WCF服务(转)

5. 设置侦听器的名字为"MessageLog",设置初始数据的存放地址

WCF4.0进阶系列--第四章 保护企业内部的WCF服务(转)

6. 设置TraceOutputOptions为None,设置方法为点击下拉箭头,然后情况所有复选框。

WCF4.0进阶系列--第四章 保护企业内部的WCF服务(转)

7. 确保TypeName为System.Diagnostics.XmlWriterTraceListener

WCF4.0进阶系列--第四章 保护企业内部的WCF服务(转)

8. 把在第三部设置的追踪源添加到该侦听器中来,操作方法:点击侦听器右下角的添加按钮,然后在添加追踪源对话框中选择"System.ServcieModel.MessageLogging",在点击确定按钮。

WCF4.0进阶系列--第四章 保护企业内部的WCF服务(转)

9. 保存app.config,然后退出WCF配置工具

运行WCF服务和客户端,并检查追踪输出结果

1. 启动ProdctsServiceHost,点击开始按钮,启动服务

2. 启动ProductsClient

WCF4.0进阶系列--第四章 保护企业内部的WCF服务(转)3. 退出ProductsClient,停止ProductsService服务,然后退出ProductsServcieHost。

4. 启动Visual Studio自带的服务追踪查看器(Service Trace Viewer)  

5. 打开服务追踪查看器之后,选择文件—打开,打开之前存放追踪的文件

WCF4.0进阶系列--第四章 保护企业内部的WCF服务(转)

6. 在服务追踪查看器中左边面板中,却换到"消息"标签,列出了ProductsService服务收发的消息,它们根据其动作加以区分。 在这些消息的前半 部分,处于http://schemas.xmlsoap.org/ws/2005/02/trust/命名空间下。它们关注发送和审核用户身份,协商客 户端和服务发送和接收消息时使用的加密机制和加密密钥。这些消息的后半部分,是WCF服务收发的消息,它们使用http://tempuri.prg命名 空间区别。

7. 点击第一个名字为http://tempuri.prg/IProductsService/ListProducts的动作,你可以发现每个动作发生了两次。这是因为你追踪了每个消息两次:一次发生在消息级别,另外一次发生在传输级别。

8. 点击右下部分的"消息"标签,对应的窗口将显示整个SOAP消息。该消息是由传输级别发送至消息级别。该消息header的内容相当长,如果你不忙,你可 以查看其内容。有趣的是处于该消息尾部的body内容。其内容是来自客户端的加密后的ListProducts请求。元 素<e:ClipherValue>包含了该请求的数据,在下图使用黄色强调了该部分:

WCF4.0进阶系列--第四章 保护企业内部的WCF服务(转)

9. 从左边面板,点击第二个http://tempuri.prg/IProductsService/ListProducts,然后点击右边的对应的"消息"标签,该消息是解密后的请求,在黄色选区内,你可以看到解密后的请求内容。

WCF4.0进阶系列--第四章 保护企业内部的WCF服务(转)

10. 你从左边面板中选择第一个http://tempuri.prg/IProductsService/ListProductsResponse,你可以 看到未加密的消息,该消息包含了ListProdusts的响应;该消息是由消息层级别送至传输级别,因此该消息还没有被加密

WCF4.0进阶系列--第四章 保护企业内部的WCF服务(转)

11. 在左边面板,点击第二个http://tempuri.prg/IProductsService/ListProductsResponse, 你可以看到消息已经加密。该消息将由传输级别发送至客户端。

WCF4.0进阶系列--第四章 保护企业内部的WCF服务(转)

12. 关闭服务追踪查看器。

在传输级别保护基于HTTP协议的服务

你应该记得,ProductsServiceHost程序对外暴露了两个端点允许客户端连接:一个基于TCP协议,另外一个基于HTTP协议。基于 HTTP协议的端点配置为使用BasicHttpBinding绑定。BasicHttpBinding绑定遵守WS-basic profile 1.1规范,其目的是为了使用传统的Web服务和客户端。 该协议完全能与ASP.NET Web服务互操作。默认情况下,该绑定提供最小的安全性;比如,它不支持消息基本加密或者验证。为了实现消息保密并保留与ASP.NET互操作,你应该使用传输安全。这要求你将该服务配置为使用HTTPS协议。这就是我们下面练习将做的事情。

为使用BasicHttpBing绑定的服务指定传输安全

1. 在Visual Studio,使用WCF配置管理工具,打开ProductsServiceHost项目下的app.config;并在WCF配置管理工具的左边面板中,点击Binding,然后点击右边的"创建一个新的绑定配置"

WCF4.0进阶系列--第四章 保护企业内部的WCF服务(转)

2. 设置名称为ProductServcieBasicHttpBindingConfig;

WCF4.0进阶系列--第四章 保护企业内部的WCF服务(转)

3.切换到"安全"标签,设置模式为"Transport"。

WCF4.0进阶系列--第四章 保护企业内部的WCF服务(转)

4. 转到端点下的BasicHttpBinding_IProductService,确认Address为https://localhost:8000/ProductsService/Service.svc; 并选择绑定配置为"ProductServcieBasicHttpBindingConfig"

WCF4.0进阶系列--第四章 保护企业内部的WCF服务(转)

5. 保存配置文件,退出WCF服务配置管理工具,然后编译该项目,确认没有警告和错误。

为使用BasicHttpBinding绑定的客户端指定传输安全

1. 使用WCF配置管理工具,打开ProductsClient项目下的app.config;并在WCF配置管理工具的左边面板中,展开绑定文件夹,然后点击右边的"创建一个新的绑定配置"

WCF4.0进阶系列--第四章 保护企业内部的WCF服务(转)

2. 设置名称为ProductClientBasicHttpBindingConfig;

WCF4.0进阶系列--第四章 保护企业内部的WCF服务(转)

3. 切换到"安全"标签,设置模式为"Transport"。

WCF4.0进阶系列--第四章 保护企业内部的WCF服务(转)

4. 转到端点下的BasicHttpBinding_IProductService,确认Address为https://localhost:8000 /ProductsService/Service.svc; 并选择绑定配置为"ProductClientBasicHttpBindingConfig"

WCF4.0进阶系列--第四章 保护企业内部的WCF服务(转)

5. 保存配置文件,退出WCF服务配置管理工具

6. 修改productsClient下的program.cs文件,使其使用BasicHttpBinding绑定与服务ProductsServcie通信:

static void Main(string[] args)

{

try

{

ProductsServcieClient proxy
= new ProductsServcieClient("BasicHttpBinding_IProductsService");



}



}

相关文章: