[WCF安全系列]通过绑定元素看各种绑定对消息保护的实现
对消息进行签名和加密分别解决了消息的一致性和机密性问题。而最终是仅仅采用签名还是签名与加密共用取决于契约中对消息保护级别的设置。但是具体的签名和加密在整个WCF框架体系中如何实现?是采用对称加密还是非对称加密?密钥如何而来?相信这些问题在本篇文章中你会找到答案。
目录
一、BasicHttpBinding
二、WSHttpBinding、WS2007HttpBinding和WSDualHttpBinding
三、NetTcpBinding和NetNamedPipeBinding
四、NetMsmqBinding
五、总结
在本系列中我不断在强调这么一个要点:整个安全传输的实施最终是在信道层实现的。而信道层是根绝终结点绑定创建的,而绑定从结构上是一系列绑定元素的有序集合。当绑定的安全开启的时候,决定最终安全传输实现方式的必然是某一个或者多个绑定元素。了解相关绑定元素可以帮助读者从本质上理解安全传输实现原理。
为了演示方便,我写了如下一个针对Binding类型的扩展方法ListAllBindingElements,该方法会将绑定所有的绑定元素的类型打印出来。接下来,我们就利用这个扩展方法应用了那些常见的绑定,看看最终决定安全传输的是哪些绑定元素。
1: public static class BindingExtension
2: {
3: public static void ListAllBindingElements(this Binding binding)
4: {
5: int i = 0;
6: foreach (var bindingElement in binding.CreateBindingElements())
7: {
8: Console.WriteLine("\t{0}.{1}", ++i, bindingElement.GetType().FullName);
9: }
10: }
11: }
一、BasicHttpBinding
我们先来看看对于三种典型安全模式(Transport、Message和Mixed)下的BasicHttpBinding具体由哪些绑定元素构成,为了我编写了如下的程序。
1: BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
2: Console.WriteLine("Transport:");
3: binding.ListAllBindingElements();
4:
5: binding = new BasicHttpBinding(BasicHttpSecurityMode.Message);
6: binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.Certificate;
7: Console.WriteLine("Message:");
8: binding.ListAllBindingElements();
9:
10: binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportWithMessageCredential);
11: Console.WriteLine("Mixed:");
12: binding.ListAllBindingElements();
输出结果:
1: Transport:
2: 1.System.ServiceModel.Channels.TextMessageEncodingBindingElement
3: 2.System.ServiceModel.Channels.HttpsTransportBindingElement
4: Message:
5: 1.System.ServiceModel.Channels.AsymmetricSecurityBindingElement
6: 2.System.ServiceModel.Channels.TextMessageEncodingBindingElement
7: 3.System.ServiceModel.Channels.HttpTransportBindingElement
8: Mixed:
9: 1.System.ServiceModel.Channels.TransportSecurityBindingElement
10: 2.System.ServiceModel.Channels.TextMessageEncodingBindingElement
11: 3.System.ServiceModel.Channels.HttpsTransportBindingElement
我们来具体分析一下最终在不同安全模式下输出的绑定元素列表。对于Mixe安全模式下对服务的验证、消息签名和加密都是基于Transport安全,Message安全仅仅用于对客户端的认证。所以对于Transport和Mixed模式,消息保护都是通过HttpsTransportBindingElement来实现。从名称就可以看出来,这是一个基于HTTPS的传输绑定元素,这也再次印证了BasicHttpBinding通过HTTPS实现Transport安全模式的说法。
对于Message安全模式的三个绑定元素中,很明显和安全传输相关的是AsymmetricSecurityBindingElement。从名称我们就知道,该绑定元素通过非对称加密的方式提供签名和加密的实现。具体来说,对于请求消息来说,发送方使用自己的私钥对消息进行签名,使用接收方的公钥对消息进行加密。接收方采用发送方的公钥验证签名,用自己的私钥对消息进行解密。这也是为什么在选择了Message安全模式的情况下,基于用户名/密码的客户端凭证不被支持的真正原因。
二、WSHttpBinding、WS2007HttpBinding和WSDualHttpBinding
我们按照相同的方式来分析基于WS的绑定,由于WSHttpBinding和WS2007HttpBinding仅仅在实现WS-*协议上面有所不同之外,整个设计基本相同。所以我们仅仅分析WS2007HttpBinding和WSDualHttpBinding。首先来分析WS2007HttpBinding,我们对前面的分析程序略加修改,将绑定类型替换成WS2007HttpBinding。
1: WS2007HttpBinding binding = new WS2007HttpBinding(SecurityMode.Transport);
2: Console.WriteLine("Transport:");
3: binding.ListAllBindingElements();
4:
5: binding = new WS2007HttpBinding(SecurityMode.Message);
6: Console.WriteLine("Message:");
7: binding.ListAllBindingElements();
8:
9: binding = new WS2007HttpBinding(SecurityMode.TransportWithMessageCredential);
10: Console.WriteLine("Mixed:");
11: binding.ListAllBindingElements();
输出结果:
1: Transport:
2: 1.System.ServiceModel.Channels.TransactionFlowBindingElement
3: 2.System.ServiceModel.Channels.TextMessageEncodingBindingElement
4: 3.System.ServiceModel.Channels.HttpsTransportBindingElement
5: Message:
6: 1.System.ServiceModel.Channels.TransactionFlowBindingElement
7: 2.System.ServiceModel.Channels.SymmetricSecurityBindingElement
8: 3.System.ServiceModel.Channels.TextMessageEncodingBindingElement
9: 4.System.ServiceModel.Channels.HttpTransportBindingElement
10: Mixed:
11: 1.System.ServiceModel.Channels.TransactionFlowBindingElement
12: 2.System.ServiceModel.Channels.TransportSecurityBindingElement
13: 3.System.ServiceModel.Channels.TextMessageEncodingBindingElement
14: 4.System.ServiceModel.Channels.HttpsTransportBindingElement
WS2007HttpBinding和BasicHttpBinding实现Transport安全都是基于HTTPS,所以在对于Transport和Mixed安全模式,HttpsTransportBindingElement实现了对消息的签名和加密。而对于Message安全模式下包含的四个绑定元素,我们可以看出最终和安全传输相关的是一个叫做SymmetricSecurityBindingElement。从名称我们都可以猜出,SymmetricSecurityBindingElement采用了对称加密的实现了对消息的签名和加密。这就意味着,客户端和服务在进行正式的功能性消息交换之前,会相互协商生成一个仅限于双方知道的密钥。
接着来看用户双向通信的WSDualHttpBinding。通过前面的接收,我们已经知道了该邦绑定仅仅支持Message安全模式。我们同样调用ListAllBindingElements扩展方法列出WSDualHttpBinding在Message安全模式下的所有绑定元素。
1: WSDualHttpBinding binding = new WSDualHttpBinding(WSDualHttpSecurityMode.Message);
2: Console.WriteLine("Message:");
3: binding.ListAllBindingElements();
输出结果:
1: Message:
2: 1.System.ServiceModel.Channels.TransactionFlowBindingElement
3: 2.System.ServiceModel.Channels.ReliableSessionBindingElement
4: 3.System.ServiceModel.Channels.SymmetricSecurityBindingElement
5: 4.System.ServiceModel.Channels.CompositeDuplexBindingElement
6: 5.System.ServiceModel.Channels.OneWayBindingElement
7: 6.System.ServiceModel.Channels.TextMessageEncodingBindingElement
8: 7.System.ServiceModel.Channels.HttpTransportBindingElement
从输出结果我们可以看到,WSDualHttpBinding和WS2007HttpBinding(WSHttpBinding)在实现Message安全模式方面采用相同的机制,都是采用SymmetricSecurityBindingElement来实现的,最终进行签名和加密的都是采用对称加密的方式来实现。
三、NetTcpBinding和NetNamedPipeBinding
我们按照之前的方式来分析另外两个只要应用于局域网环境中的两个绑定,即NetTcpBinding和NetNamedPipeBinding。这两个绑定和之前介绍的机遇HTTP/HTTPS传输协议的绑定有所不同。不论是BasicHttpBinding还是WSHttpBinding、WS2007HttpBinding和WSDualHttpBinding,当绑定的安全模式确定之后,绑定元素集合就确定了。但是对于NetTcpBinding和NetNamedPipeBinding来说,如果采用Transport安全模式,最终的绑定元素集合还和采用的认证方式有关。
下面是针对于NetTcpBinding的分析程序,对于Transport和Mixed安全模式,我们又分两种情况:将客户端凭证类型分别设置成Windows和Certificate。
1: NetTcpBinding binding = new NetTcpBinding(SecurityMode.Transport);
2: binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Windows;
3: Console.WriteLine("Transport(Windows):");
4: binding.ListAllBindingElements();
5:
6: binding = new NetTcpBinding(SecurityMode.Transport);
7: binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Certificate;
8: Console.WriteLine("Transport(Certificate):");
9: binding.ListAllBindingElements();
10:
11: binding = new NetTcpBinding(SecurityMode.Message);
12: Console.WriteLine("Message:");
13: binding.ListAllBindingElements();
14:
15: binding = new NetTcpBinding(SecurityMode.TransportWithMessageCredential);
16: binding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
17: Console.WriteLine("Mixed(Windows):");
18: binding.ListAllBindingElements();
19:
20: binding = new NetTcpBinding(SecurityMode.TransportWithMessageCredential);
21: binding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
22: Console.WriteLine("Mixed(Certificate):");
23: binding.ListAllBindingElements();
输出结果:
1: Transport(Windows):
2: 1.System.ServiceModel.Channels.TransactionFlowBindingElement
3: 2.System.ServiceModel.Channels.BinaryMessageEncodingBindingElement
4: 3.System.ServiceModel.Channels.WindowsStreamSecurityBindingElement
5: 4.System.ServiceModel.Channels.TcpTransportBindingElement
6: Transport(Certificate):
7: 1.System.ServiceModel.Channels.TransactionFlowBindingElement
8: 2.System.ServiceModel.Channels.BinaryMessageEncodingBindingElement
9: 3.System.ServiceModel.Channels.SslStreamSecurityBindingElement
10: 4.System.ServiceModel.Channels.TcpTransportBindingElement
11: Message:
12: 1.System.ServiceModel.Channels.TransactionFlowBindingElement
13: 2.System.ServiceModel.Channels.SymmetricSecurityBindingElement
14: 3.System.ServiceModel.Channels.BinaryMessageEncodingBindingElement
15: 4.System.ServiceModel.Channels.TcpTransportBindingElement
16: Mixed(Windows):
17: 1.System.ServiceModel.Channels.TransactionFlowBindingElement
18: 2.System.ServiceModel.Channels.TransportSecurityBindingElement
19: 3.System.ServiceModel.Channels.BinaryMessageEncodingBindingElement
20: 4.System.ServiceModel.Channels.SslStreamSecurityBindingElement
21: 5.System.ServiceModel.Channels.TcpTransportBindingElement
22: Mixed(Certificate):
23: 1.System.ServiceModel.Channels.TransactionFlowBindingElement
24: 2.System.ServiceModel.Channels.TransportSecurityBindingElement
25: 3.System.ServiceModel.Channels.BinaryMessageEncodingBindingElement
26: 4.System.ServiceModel.Channels.SslStreamSecurityBindingElement
27: 5.System.ServiceModel.Channels.TcpTransportBindingElement
从输出结果我们看出这样的问题:NetTcpBinding同样采用SymmetricSecurityBindingElement实现Message模式安全。但是对于Transport安全模式的实现却还决定于客户端凭证类型(或者说认证方式)。在Windows认证下,WindowsStreamSecurityBindingElement用于使用Transport安全。而对于非Windows认证,对应的绑定元素变成了SslStreamSecurityBindingElement。对于实现NetTcpBinding基于Transport安全的两个绑定元素WindowsStreamSecurityBindingElement和SslStreamSecurityBindingElement,它们具有相同的基类:StreamUpgradeBindingElement。
1: public abstract class StreamUpgradeBindingElement : BindingElement
2: {
3: //省略成员
4: }
5: public class WindowsStreamSecurityBindingElement : StreamUpgradeBindingElement
6: {
7: //省略成员
8: }
9: public class SslStreamSecurityBindingElement : StreamUpgradeBindingElement
10: {
11: //省略成员
12: }
StreamUpgradeBindingElement实现消息保护的机制被称为Stream Upgrade。在这种机制下,经过编码转化成的二进制流在进入传输层之前,会被拦截。拦截得到的二进制流经过签名和加密后再被重新流入传输层发送。还有一点需要特别指出的是:StreamUpgradeBindingElement并不会创建相应的信道,而是将功能实现的对象作为绑定参数传入信道层,传输信道在将其取出并完成相应的签名和加密工作。目前为止,只有两种面向连接的网络协议的传输信道支持Stream Upgrade,即TCP和命名管道。至于两种具体的StreamUpgradeBindingElement,SslStreamSecurityBindingElement采用TLS/SSL协议,WindowsStreamSecurityBindingElement则基于Windows安全协议。
程序的输出结果还反映了另一个现象:客户凭证对最终使用的绑定协议的影响仅限于Transport安全模式。对于Mixed模式,不论采用怎样的客户凭证,最终实现Transport安全的绑定元素总是SslStreamSecurityBindingElement。也就是说Mixed模式下的NetTcpBinding总是采用TLS/SSL实现Transport安全。换句话说,如果你使用Mixed模式下的NetTcpBinding,你必须为服务指定一个X.509证书作为服务的凭证。
由于NetNamedPipeBinding只支持Transport安全模式,并且在该安全模式下默认使用Windows认证。所以最终实现Transport安全的总是WindowsStreamSecurityBindingElement。
1: NetNamedPipeBinding binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.Transport);
2: binding.ListAllBindingElements();
输出结果:
1: 1.System.ServiceModel.Channels.TransactionFlowBindingElement
2: 2.System.ServiceModel.Channels.BinaryMessageEncodingBindingElement
3: 3.System.ServiceModel.Channels.WindowsStreamSecurityBindingElement
4: 4.System.ServiceModel.Channels.NamedPipeTransportBindingElement
四、 NetMsmqBinding
我们来接着分析最后一种类型的绑定,即NetMsmqBinding,我们直接将我们定义的ListAllBindingElements扩展方法应用三个具有不同安全模式(Transport、Message和Both)的NetMsmqBinding对象上。
1: NetMsmqBinding binding = new NetMsmqBinding(NetMsmqSecurityMode.Transport);
2: Console.WriteLine("Transport:");
3: binding.ListAllBindingElements();
4:
5: binding = new NetMsmqBinding(NetMsmqSecurityMode.Message);
6: Console.WriteLine("Message:");
7: binding.ListAllBindingElements();
8:
9: binding = new NetMsmqBinding(NetMsmqSecurityMode.Both);
10: Console.WriteLine("Both:");
11: binding.ListAllBindingElements();
输出结果:
1: Transport:
2: 1.System.ServiceModel.Channels.BinaryMessageEncodingBindingElement
3: 2.System.ServiceModel.Channels.MsmqTransportBindingElement
4: Message:
5: 1.System.ServiceModel.Channels.SymmetricSecurityBindingElement
6: 2.System.ServiceModel.Channels.BinaryMessageEncodingBindingElement
7: 3.System.ServiceModel.Channels.MsmqTransportBindingElement
8: Both:
9: 1.System.ServiceModel.Channels.SymmetricSecurityBindingElement
10: 2.System.ServiceModel.Channels.BinaryMessageEncodingBindingElement
11: 3.System.ServiceModel.Channels.MsmqTransportBindingElement
输出结果反映了这样一个结论:基于NetMsmqBinding的Transport安全是通过MsmqTransportBindingElement在传输信道中完成了,而Message安全还是通过SymmetricSecurityBindingElement采用对称签名和加密实现的。
五、 总结
上面我们从横向比较各种常见的绑定在不同安全模式下具有怎样的绑定元素列表。由于绑定元素认识安全传输实现的核心,所以现在我们抛开不同绑定类型的差异,直接看看Transport和Message这两不同的安全模式最终都是由那些具体的绑定元素实现的。
Transport安全对应以下四种绑定定元素:HttpsTransportBindingElement、WindowsStreamSecurityBindingElement和SslStreamSecurityBindingElement和MsmqTransportBindingElement。其中三个基于互联网的绑定,BasicHttpBinding、WSHttpBinding和WS2007HttpBinding)因为都是采用HTTPS实现的,所以最终的落实到HttpsTransportBindingElement上。两种基于局域网的绑定,NetTcpBinding和NetNamePipeBinding采用Stream Upgrade的机制实现Transport安全,具体来说又落实到如下两个绑定元素:WindowsStreamSecurityBindingElement和SslStreamSecurityBindingElement。
Message安全对应如下三种绑定元素:AsymmetricSecurityBindingElement、SymmetricSecurityBindingElement和TransportSecurityBindingElement。其中TransportSecurityBindingElement使用在Mixed安全模式下。对于Message模式,除了BasicHttpBinding使用AsymmetricSecurityBindingElement外,其余都是使用SymmetricSecurityBindingElement。