由一个需求聊聊WCF(三)

安全问题

WCF提供了通道安全和消息安全两种方式保证消息安全,为了保证服务的通用性,WCF提供的安全方案都基于公共标准的安全规范,比如ITU-T的X.509等。遵守公共安全规范可以保证WCF的通用性,不过有时候这些通用安全方式并不适合我们。在一些简单的场合,我们仅仅就是想对消息加一下密,使用X.509证书就显得过重了。

如果要弄证书,合法证书当然是最好的了。但弄个合法X.509证书是需要费用的,而且每年都要交费,很少客户会乐意。弄个非法的X509证书凑合用也是问题多多,首先证书需要在服务器上安装,还需要找个妥当的方式为客户端分发,证书的安装会带来额外的配置工作。就算安装配置都不是问题,在silverlight中使用假证书也会很麻烦,在普通.net客户端中,至少还能有System.Net.ServicePointManager.ServerCertificateValidationCallback属性可以让你选择性的去信任自己创建的假证书,但silverlight就不提供这个机制,它太安全了,现在安全得让人头疼。

为了避开证书实现silverlight可用的WCF消息加密,看来要自已动手了。WCF提供了丰富的扩展机制(参考:http://msdn.microsoft.com/zh-cn/library/ms733848),通过自定义消息的编码器(参考:http://msdn.microsoft.com/zh-cn/library/ms751486),在消息编码解码的过程中加入自己的加密解密运算可以达到目的。注意这个做法将破坏服务的通用性,你无法公开这样的服务给大众,因为他们不了解你的服务消息格式,不过在这里,我们的服务是为我们自己的客户端服务的,我们反倒期望这样的效果。

决定了努力的方向,下一步就是设计一个自己的加解密算法了,这个听住似乎不难,其实并不是很简单,由于处理目标是通过网络传输的消息,下面几件事情就需要考虑:

1.机密性。除了发送者和接收者外,别人应看不懂消息。
2.完整性。如果消息传输过程中被别人篡改过,要能识别并拒绝该消息。
3.抗重放。如果消息被别人原样记下并重新发送,要能识别并拒绝该消息。
4.身份认证。传输的消息到底是谁发送出去的。
5.抗抵赖。消息发送者不能否认自己发送过某个消息。
6.乱序。消息间的顺序被别人重新排列或消息发送时机被变更。
7.行为分析。分析消息的大小,时间段,目标及频率等特征,以判断并得知消息代表的意义。
8.拒绝服务攻击。发送大量恶意消息,使服务器或网络不堪重负,或直接破坏服务器或网络设施。

由于不是银行、军事等重要场景,这里不考虑拒绝服务、行为分析和乱序问题,身份认证和抗抵赖也可以放松。但机密性、完整性、抗重放是必须要保证,如果连这三条都保证不了,可以认为这套加密机制根本就不可用。

还有一个额外问题,那就是自定的编码器要能通过配置来处理过大的数据,在实际应用时,WCF数据超过默认限制大小的事情并不少见。

加密内容就可以解决机密性问题,这里使用普通的对称密钥加密,使用系统用户密码的哈希值做为密钥,因为只有用户自己和服务器知道这个哈希值,所以不用把密钥在网络上传输,降低了密钥泄露风险。

使用内容摘要做为签名可以解决完整性问题,这里使用键控哈希算法计算摘要,在一定程序上保证签名不会被其它用户伪造。

建立了时间窗口,不在时间窗口范围的消息不处理,在时间窗口范围的消息做记录,根据记录检查出的重复消息也不处理。这样可以解决重放问题。

具体算法流程在本文的示例中有文档,这里只谈谈如何复用本文示例。

本文的示例和微软给出的示例有些不同。微软的示例把编码解码逻辑封装了一个程序集中,可供服务端和客户端共同引用,但本文的的客户端是silverlight,它无法引用普通的.net类库,所以没有封装dll,分别在服务端和客户端写代码。这个方法适应性较文,在非silverlight的普通场合也可以使用。

在服务端安装自定义编码器:

1.把本文示例服务端的CustomTextEncoder.cs、CustomTextEncoderBindingElement.cs、CustomTextEncoderBindingElementSection.cs、CustomTextEncoderFactory.cs复制到程序中,在程序配置文件中注册自定义的编码器:

<system.serviceModel> 
  <extensions>
    <bindingElementExtensions>
      <add name="customTextCodeEncoding" type="SilverlightWcfExample.Web.CustomTextEncoderBindingElementSection, SilverlightWcfExample.Web"/>
    </bindingElementExtensions>
  </extensions>
</system.serviceModel>

注意根据实际修改命名空间、程序集名等。
2.建立自定义绑定:

<customBinding>
  <binding name="CustomTextBinding_MessageSecurityService" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" >
    <customTextCodeEncoding maxReadPoolSize="64000" maxWritePoolSize="16000">
      <readerQuotas maxArrayLength="16384000" maxBytesPerRead="4096000" maxDepth="32000" maxNameTableCharCount="16384000" maxStringContentLength="8192000" />
    </customTextCodeEncoding>
    <httpTransport  maxReceivedMessageSize="65536000" maxBufferSize="65536000" />
  </binding>
</customBinding>

本文的自定义编码器支持配置readerQuotas等参数,以支持大数据和长处理时间的服务。
3.修改服务的配置,把binding和bindingConfiguration设为自定义的项。

<service name="SilverlightWcfExample.Web.Services.SqlDataService">
  <endpoint address="" binding="customBinding" bindingConfiguration="CustomTextBinding_MessageSecurityService"
          contract="SilverlightWcfExample.Web.Services.SqlDataService" />
  <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>

到此服务端改造完成。

在客户端使用自定义编码器,如果是普通.net客户端,可参考微软示例配置。这里介绍silverlight客户端,由于silverlight不支持某些配置,所以使用起来有些不同:

1.把本文示例客户端CustomTextEncoder.cs、CustomTextEncoderBindingElement.cs、CustomTextEncoderFactory.cs复制到程序中,可以发现silverlight不支持CustomTextEncoderBindingElementSection.cs。

2.像引用普通服务那样引用服务端的服务,生成代码和配置项。为了提高服务适应性,可以把openTimeout等值调大些:

<customBinding>
    <binding name="CustomBinding_SqlDataService" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00">
        <textMessageEncoding />
        <httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" />
    </binding>
</customBinding>

3.在silverlight生成的配置项里,编码器用的是textMessageEncoding,我们无法通过配置改变它,所以要使用代码在调用服务时替换成自己的编码器。把替换编码器的代码封装到下面这个方法中:

internal static class WcfServiceHelper
{
    internal static void ReplaceEndpoint(ServiceEndpoint endpoint)
    {
        BindingElementCollection bindingCollection = endpoint.Binding.CreateBindingElements();
        bindingCollection[0] = new CustomTextEncoderBindingElement();
        Binding binding = new CustomBinding(bindingCollection);
        endpoint.Binding = binding;
    }
}

4.所有服务的引用在调用服务前都需要用上步的方法处理一下:

SqlDataServiceClient client = new SqlDataServiceClient();
WcfServiceHelper.ReplaceEndpoint(client.Endpoint);
client.DoSomethingAsync();

到此,供silverlight使用的WCF的无证书消息加密工作已经完成。上面的方法并不优雅,但起码是有效的。如果大家有更好的方法,请指教,谢谢。

本文示例下载地址:http://download.csdn.net/detail/wantalcs/4494183

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下 4载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下载 4使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下载 4使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值