閱讀188 返回首頁    go 阿裏雲 go 技術社區[雲棲]


[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: }

我們先來看看對於三種典型安全模式(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模式,消息保護都是通過來實現。從名稱就可以看出來,這是一個基於HTTPS的傳輸綁定元素,這也再次印證了BasicHttpBinding通過HTTPS實現Transport安全模式的說法。

對於Message安全模式的三個綁定元素中,很明顯和安全傳輸相關的是。從名稱我們就知道,該綁定元素通過的方式提供簽名和加密的實現。具體來說,對於請求消息來說,發送方使用自己的私鑰對消息進行簽名,使用接收方的公鑰對消息進行加密。接收方采用發送方的公鑰驗證簽名,用自己的私鑰對消息進行解密。這也是為什麼在選擇了Message安全模式的情況下,基於用戶名/密碼的客戶端憑證不被支持的真正原因。

我們按照相同的方式來分析基於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安全模式,實現了對消息的簽名和加密。而對於Message安全模式下包含的四個綁定元素,我們可以看出最終和安全傳輸相關的是一個叫做。從名稱我們都可以猜出,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安全模式方麵采用相同的機製,都是采用來實現的,最終進行簽名和加密的都是采用對稱加密的方式來實現。

我們按照之前的方式來分析另外兩個隻要應用於局域網環境中的兩個綁定,即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同樣采用實現Message模式安全。但是對於Transport安全模式的實現卻還決定於客戶端憑證類型(或者說認證方式)。在Windows認證下,用於使用Transport安全。而對於非Windows認證,對應的綁定元素變成了。對於實現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實現消息保護的機製被稱為。在這種機製下,經過編碼轉化成的二進製流在進入傳輸層之前,會被攔截。攔截得到的二進製流經過簽名和加密後再被重新流入傳輸層發送。還有一點需要特別指出的是:StreamUpgradeBindingElement並不會創建相應的信道,而是將功能實現的對象作為綁定參數傳入信道層,傳輸信道在將其取出並完成相應的簽名和加密工作。目前為止,隻有兩種麵向連接的網絡協議的傳輸信道支持Stream Upgrade,即TCP和命名管道。至於兩種具體的StreamUpgradeBindingElement,SslStreamSecurityBindingElement采用TLS/SSL協議,WindowsStreamSecurityBindingElement則基於Windows安全協議。

程序的輸出結果還反映了另一個現象:客戶憑證對最終使用的綁定協議的影響僅限於安全模式。對於模式,不論采用怎樣的客戶憑證,最終實現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,我們直接將我們定義的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安全是通過在傳輸信道中完成了,而Message安全還是通過采用對稱簽名和加密實現的。

上麵我們從橫向比較各種常見的綁定在不同安全模式下具有怎樣的綁定元素列表。由於綁定元素認識安全傳輸實現的核心,所以現在我們拋開不同綁定類型的差異,直接看看Transport和Message這兩不同的安全模式最終都是由那些具體的綁定元素實現的。

Transport安全對應以下四種綁定定元素:、和和。其中三個基於互聯網的綁定,BasicHttpBinding、WSHttpBinding和WS2007HttpBinding)因為都是采用實現的,所以最終的落實到上。兩種基於局域網的綁定,NetTcpBinding和NetNamePipeBinding采用Stream Upgrade的機製實現Transport安全,具體來說又落實到如下兩個綁定元素:和。

Message安全對應如下三種綁定元素:、和。其中TransportSecurityBindingElement使用在Mixed安全模式下。對於Message模式,除了BasicHttpBinding使用AsymmetricSecurityBindingElement外,其餘都是使用SymmetricSecurityBindingElement。


作者:蔣金楠
微信公眾賬號:大內老A
微博:www.weibo.com/artech
如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識別二維碼)關注個人公眾號(原來公眾帳號蔣金楠的自媒體將會停用)。
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁麵明顯位置給出原文連接,否則保留追究法律責任的權利。
原文鏈接

最後更新:2017-10-26 16:34:22

  上一篇:go  [WCF安全係列]消息的保護等級[下篇]
  下一篇:go  通過添加HTTP Header實現上下文數據在WCF的自動傳遞