程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> WCF安全系列(三) - netTCPBinding綁定之Message安全模式

WCF安全系列(三) - netTCPBinding綁定之Message安全模式

編輯:關於.NET

一、netTCPBinding.1

3、安全模式 – Message.1

3.1.客戶端驗證 – None.2

3.1.1.獲得和安裝證書...2

3.1.2.服務端代碼...2

3.1.3.客戶端代碼...3

3.1.4.測試...3

3.2.客戶端驗證 – Windows.3

3.2.1.獲得和安裝證書...4

3.2.2.服務端代碼...4

3.2.3.客戶端代碼...4

3.2.4.測試...5

3.3.客戶端驗證 – UserName.5

3.3.1.獲得和安裝證書...5

3.3.2.服務端代碼...6

3.3.3.客戶端代碼...8

3.3.4.測試...9

3.3.5.身份模擬和訪問權限控制...9

3.4.客戶端驗證:Certificate.10

3.4.1.獲得和安裝證書...10

3.4.2.服務端代碼...11

3.4.3.客戶端代碼...11

3.4.4.測試...12

3.4.5.證書映射到windows用戶...12

一、netTCPBinding

此綁定使用TCP傳輸協議,不具交互性,只適用於 WCF 到 WCF 的通信。

此綁定的傳輸安全性的實現:

l 安全模式Message

這種模式WCF中都一樣,都是使用WS-*通過對SOAP消息本身進行加密、簽名等 等的處理來保證安全性。Message模式不依賴於傳輸協議。服務端需要指定服務 端證書,用來加密服務端和客戶端相互傳送的消息。

l Transport – 客戶端windows驗證

使用windows security保證消息的安全,使用windows credential進行身份 驗證。

這種方式不需要服務端證書。

至於windows security的實現安全的原理我還不明白,這部分尚待了解。

l Transport – 客戶端其他驗證方式

使用TLS over TCP實現傳輸安全性,需要服務端證書。

一般大家對SSL比較熟悉,對TLS可能要陌生些,其實可以說TLS協議可以看作 跟SSL協議後續版本。1994年,netscape為了在internet上進行安全的數據傳輸 ,開發了的SSL協議,後來標准化組織把SSL標准化了,稍作修改改名叫TLS,在 一般的使用意義上,這兩個協議差別不大,就是在保證消息完整性的散列算法上 使用了不同的算法。

TLS over TCP 直接建立在TCP協議上,通過傳輸層TCP協議實現安全性。

netTCPBinding綁定是直接使用TCP協議,不走HTTP,所以不能使用IIS宿主。 這部分的測試實例采用自宿主的服務端console應用,基於代碼的方式。

3、安全模式 – Message

這部分測試netTCPBinding綁定的Message安全模式的各種情況。

共用測試WCF服務類

所有測試都是用同樣的服務端contract和實現這個contract的service:

[ServiceContract(Namespace = "http://chnking.com")]
public interface IGetIdentity
{
  [OperationContract]
  string Get(string ClientIdentity);
}
public class GetIdentity : IGetIdentity
{
  public string Get(string ClientIdentity)
  {
    return ("服務端Identity 是'" + ServiceSecurityContext.Current.PrimaryIdentity.Name +
      "'\n\r客戶端Identity是 '" + ClientIdentity + "'");
  }
}

代碼很簡單,一個contract提供了一個Get方法,接收一個string參數,返回 一個string參數。在後面的測試中,客戶端把客戶端安全上下文的Identity發送 到服務端,服務端返回服務端安全上下文的Identity給客戶端。

3.1.客戶端驗證 – None

這部分的測試代碼: NetTcpBinding_Message_None.rar

netTCPBinding綁定的Message安全模式,客戶端None驗證。此時將使用服務 端證書,通過WS-Trust協議建立的安全通道,原理上類似SSL或TLS的機制(但不 是通過網絡傳輸層來實現,而是通過處理SOAP中的消息)來保證消息的安全性。

這種方式的安全性:

完整性 使用服務端證書,通過WS-Trust協議建立的安全通道 保密性 使用服務端證書,通過WS-Trust協議建立的安全通道 服務端身份身份驗證 服務端證書提供 客戶端身份驗證 沒有

3.1.1.獲得和安裝證書

這裡用Makecert.exe工具生成證書,使用下面的命令:

makecert -sr localmachine -ss My -n CN=win2008 -sky exchange -pe -r

這是服務端證書,win2008是服務端的機器名。

如果做過前面BasicHttpBinding的測試,這個服務端證書就應該已經有了。

3.1.2.服務端代碼

internal static ServiceHost myServiceHost = null;
internal static void Main()
{
  NetTcpBinding myBinding = new NetTcpBinding();
  myBinding.Security.Mode = SecurityMode.Message;
  myBinding.Security.Message.ClientCredentialType = MessageCredentialType.None;
  Uri baseAddress = new Uri ("net.tcp://localhost:8056/WCFService/");
  myServiceHost = new ServiceHost(typeof(GetIdentity), baseAddress);
  ServiceEndpoint myServiceEndpoint = myServiceHost.AddServiceEndpoint
    (typeof(IGetIdentity), myBinding, "GetIdentity");
  //設置服務端證書
  myServiceHost.Credentials.ServiceCertificate.SetCertificate ("CN=win2008");
  ServiceMetadataBehavior behavior = new ServiceMetadataBehavior ();
  behavior.HttpGetEnabled = true;
  behavior.HttpGetUrl = new Uri ("http://localhost:8057/mex");
  myServiceHost.Description.Behaviors.Add(behavior);
  myServiceHost.Open();
  Console.WriteLine("Service started!");
  Console.ReadLine();
  myServiceHost.Close();
}

3.1.3.客戶端代碼

static void Main(string[] args)
{
  NetTcpBinding myBinding = new NetTcpBinding();
  myBinding.Security.Mode = SecurityMode.Message;
  myBinding.Security.Message.ClientCredentialType = MessageCredentialType.None;
  EndpointAddress ea = new EndpointAddress ("net.tcp://win2008:8056/WCFService/GetIdentity");
  GetIdentityClient gc = new GetIdentityClient(myBinding, ea);
  //不驗證服務端證書的有效性
   gc.ClientCredentials.ServiceCertificate.Authentication.CertificateVali dationMode =
     System.ServiceModel.Security.X509CertificateValidationMode.None;
  //為使用TcpTrace跟蹤消息設置的TcpTrace監聽端口
  ClientViaBehavior myClientViaBehavior = new ClientViaBehavior
    (new Uri ("net.tcp://win2008:8055/WCFService/GetIdentity"));
  gc.Endpoint.Behaviors.Add(myClientViaBehavior);
  //執行代理類Get方法
  string result = gc.Get(WindowsIdentity.GetCurrent().Name);
  Console.WriteLine(result);
  Console.ReadLine();
}

3.1.4.測試

3.2.客戶端驗證 – Windows

這部分的測試代碼: NetTcpBinding_Message_Windows.rar

netTCPBinding綁定的Message安全模式,客戶端Windows驗證。此時將使用服 務端證書,通過WS-Trust協議建立的安全通道,原理上類似SSL或TLS的機制(但 不是通過網絡傳輸層來實現,而是通過處理SOAP中的消息)來保證消息的安全性 。

這種方式的安全性:

完整性 使用服務端證書,通過WS-Trust協議建立的安全通道 保密性 使用服務端證書,通過WS-Trust協議建立的安全通道 服務端身份身份驗證 服務端證書提供 客戶端身份驗證 Windows身份驗證

3.2.1.獲得和安裝證書

這裡用Makecert.exe工具生成證書,使用下面的命令:

makecert -sr localmachine -ss My -n CN=win2008 -sky exchange -pe -r

這是服務端證書,win2008是服務端的機器名。

如果做過前面BasicHttpBinding的測試,這個服務端證書就應該已經有了。

3.2.2.服務端代碼

internal static ServiceHost myServiceHost = null;
internal static void Main()
{
  NetTcpBinding myBinding = new NetTcpBinding();
  myBinding.Security.Mode = SecurityMode.Message;
  myBinding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
  Uri baseAddress = new Uri ("net.tcp://localhost:8056/WCFService/");
  myServiceHost = new ServiceHost(typeof(GetIdentity), baseAddress);
  ServiceEndpoint myServiceEndpoint = myServiceHost.AddServiceEndpoint
    (typeof(IGetIdentity), myBinding, "GetIdentity");
  //設置服務端證書
  myServiceHost.Credentials.ServiceCertificate.SetCertificate ("CN=win2008");
  ServiceMetadataBehavior behavior = new ServiceMetadataBehavior ();
  behavior.HttpGetEnabled = true;
  behavior.HttpGetUrl = new Uri ("http://localhost:8057/mex");
  myServiceHost.Description.Behaviors.Add(behavior);
  myServiceHost.Open();
  Console.WriteLine("Service started!");
  Console.ReadLine();
  myServiceHost.Close();
}

3.2.3.客戶端代碼

static void Main(string[] args)
{
  NetTcpBinding myBinding = new NetTcpBinding();
  myBinding.Security.Mode = SecurityMode.Message;
  myBinding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
  EndpointAddress ea = new EndpointAddress ("net.tcp://win2008:8056/WCFService/GetIdentity");
  GetIdentityClient gc = new GetIdentityClient(myBinding, ea);
  //不驗證服務端證書的有效性
   gc.ClientCredentials.ServiceCertificate.Authentication.CertificateVali dationMode =
     System.ServiceModel.Security.X509CertificateValidationMode.None;
  //為使用TcpTrace跟蹤消息設置的TcpTrace監聽端口
  ClientViaBehavior myClientViaBehavior = new ClientViaBehavior
    (new Uri ("net.tcp://win2008:8055/WCFService/GetIdentity"));
  gc.Endpoint.Behaviors.Add(myClientViaBehavior);
  //執行代理類Get方法
  string result = gc.Get(WindowsIdentity.GetCurrent().Name);
  Console.WriteLine(result);
  Console.ReadLine();
}

3.2.4.測試

可以看出,客戶端windows身份被傳送到服務端。

3.3.客戶端驗證 – UserName

這部分的測試代碼: NetTcpBinding_Message_UserName.rar

netTCPBinding綁定的Message安全模式,客戶端使用UserName驗證。此時將 使用服務端證書,通過WS-Trust協議建立的安全通道,原理上類似SSL或TLS的機 制(但不是通過網絡傳輸層來實現,而是通過處理SOAP中的消息)來保證消息的 安全性。

這種方式的安全性:

完整性 使用服務端證書,通過WS-Trust協議建立的安全通道 保密性 使用服務端證書,通過WS-Trust協議建立的安全通道 服務端身份身份驗證 服務端證書提供 客戶端身份驗證 客戶端提供的用戶名和密碼

3.3.1.獲得和安裝證書

這裡用Makecert.exe工具生成證書,使用下面的命令:

makecert -sr localmachine -ss My -n CN=win2008 -sky exchange -pe -r

這是服務端證書,win2008是服務端的機器名。

如果做過前面BasicHttpBinding的測試,這個服務端證書就應該已經有了。

3.3.2.服務端代碼

Contract和Services部分的代碼:

[ServiceContract(Namespace = "http://chnking.com")]
public interface IGetIdentity
{
  [OperationContract]
  string Get(string ClientIdentity);
}
public class GetIdentity : IGetIdentity
{
  [PrincipalPermission(SecurityAction.Demand, Role = "admin")]
  public string Get(string ClientIdentity)
  {
    IPrincipal myWindowsPrincipal = (IPrincipal) Thread.CurrentPrincipal;
    return ("Identity of server is'" + myWindowsPrincipal.Identity.Name +
      "'\n\rIdentity of client is '" + ClientIdentity + "'");
  }
}

這部分代碼跟前面的測試例子一樣,只是為了測試服務端模擬身份後的權限 控制在Get方法前增加了了如下的控制訪問的attribute:

[PrincipalPermission(SecurityAction.Demand, Role = "admin")]

表示只有運行方法的當前線程安全上下文的identity屬於admin角色時才有權 限訪問這個方法。

服務宿主部分的代碼:

internal class MyServiceHost
{
  internal static ServiceHost myServiceHost = null;
  internal static void Main()
  {
    NetTcpBinding myBinding = new NetTcpBinding();
    myBinding.Security.Mode = SecurityMode.Message;
    myBinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
    Uri baseAddress = new Uri ("net.tcp://localhost:8056/WCFService/");
    myServiceHost = new ServiceHost(typeof(GetIdentity), baseAddress);
    ServiceEndpoint myServiceEndpoint = myServiceHost.AddServiceEndpoint
      (typeof(IGetIdentity), myBinding, "GetIdentity");
    //設置服務端證書
    myServiceHost.Credentials.ServiceCertificate.SetCertificate ("CN=win2008");
    //默認服務端PrincipalPermissionMode為UseWindowsGroups,將 Thread.CurrentPrincipal設置為WindowsPrincipal
    //一般是windows驗證時映射到windows用戶。
    //本例需要自己設置Thread.CurrentPrincipal,故此處設置為None
    myServiceHost.Authorization.PrincipalPermissionMode = PrincipalPermissionMode.None;
    //設置客戶端username在服務端驗證模式為Custom
     myServiceHost.Credentials.UserNameAuthentication.UserNamePasswordValid ationMode =
       System.ServiceModel.Security.UserNamePasswordValidationMode.Custom;
     myServiceHost.Credentials.UserNameAuthentication.CustomUserNamePasswor dValidator = new customUserNamePasswordValidator();
    ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
    behavior.HttpGetEnabled = true;
    behavior.HttpGetUrl = new Uri ("http://localhost:8057/mex");
    myServiceHost.Description.Behaviors.Add(behavior);
    myServiceHost.Open();
    Console.WriteLine("Service started!");
    Console.ReadLine();
    myServiceHost.Close();
  }
}
public class customUserNamePasswordValidator : System.IdentityModel.Selectors.UserNamePasswordValidator
{
  public override void Validate(string username, string password)
  {
    if (username == "chnking" && password == "jjz666")
    {
      string[] roles = { "admin", "operator" };
      Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity("chnking", "Custom"), roles);
    }
    else
    {
      throw(new SecurityTokenException("用戶名或密碼無效! "));
    }
  }
}

這部分代碼有幾處需要說明:

客戶端使用UserName驗證方式,在服務端可以使用對客戶端發送來的 UserName的驗證方式有三種:

Windows:用windows的帳號和密碼驗證客戶端送來的UserName。

MembershipProvider:提供基於已配置的MembershipProvider的密碼驗證。

Custom:由自定義的從UserNamePasswordValidator繼承來的類驗證用戶名和 密碼。

本例中選用自定義驗證,並新建了一個從UserNamePasswordValidator繼承來 的類customUserNamePasswordValidator來驗證客戶端用戶名和口令。

驗證了用戶正確後,新建一個跟此用戶對應的GenericPrincipal,包括這個 用戶的Identity,這裡叫做”chnking”,和這個identity所屬的角 色,這裡這個用戶同時屬於"admin", "operator"。還把 這個用戶的GenericPrincipal賦給了Thread.CurrentPrincipal,使本線程往下 的運行上下文切換到這個定制的GenericPrincipal。

還有一點,服務端的PrincipalPermissionMode默認是UseWindowsGroups,這 表示將Thread.CurrentPrincipal設置為WindowsPrincipal,一般是windows驗證 時映射到windows用戶。本例需要自己設置Thread.CurrentPrincipal,故此處設 置為None,否則,到了執行服務端services代碼時,Thread.CurrentPrincipal 將為空。

3.3.3.客戶端代碼

static void Main(string[] args)
{
  NetTcpBinding myBinding = new NetTcpBinding();
  myBinding.Security.Mode = SecurityMode.Message;
  myBinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
  EndpointAddress ea = new EndpointAddress ("net.tcp://jinjz2008:8056/WCFService/GetIdentity");
  GetIdentityClient gc = new GetIdentityClient(myBinding, ea);
  //不驗證服務端證書的有效性
   gc.ClientCredentials.ServiceCertificate.Authentication.CertificateVali dationMode =
     System.ServiceModel.Security.X509CertificateValidationMode.None;
  //提供UserName客戶端用戶憑據
  gc.ClientCredentials.UserName.UserName = "chnking";
  gc.ClientCredentials.UserName.Password = "jjz666";
  //為使用TcpTrace跟蹤消息設置的TcpTrace監聽端口
  ClientViaBehavior myClientViaBehavior = new ClientViaBehavior
    (new Uri ("net.tcp://jinjz2008:8055/WCFService/GetIdentity"));
  gc.Endpoint.Behaviors.Add(myClientViaBehavior);
  //執行代理類Get方法
  string result = gc.Get(WindowsIdentity.GetCurrent().Name);
  Console.WriteLine(result);
  Console.ReadLine();
}

客戶端沒有太多需要特別說明的。設置客戶端驗證方式為UserName後用以下 代碼提供用戶名和口令:

//提供UserName客戶端用戶憑據
  gc.ClientCredentials.UserName.UserName = "chnking";
  gc.ClientCredentials.UserName.Password = "jjz666";

3.3.4.測試

可以看出,客戶端的chnking身份被傳送到服務端。並且,有權限執行服務端 的Get方法。

3.3.5.身份模擬和訪問權限控制

如果在服務端的Get方法中設置一個斷點,如下圖:

可以看到當代碼運行到Get方法中時,當前線程的Principal就是在 customUserNamePasswordValidator定制類中賦給的chnking,並且這個chnking 屬於admin角色。

如果把Get的權限改一下,改成只有叫”manager”的角色可以方 法此方法:

[PrincipalPermission(SecurityAction.Demand, Role = " manager ")]
  public string Get(string ClientIdentity)

再看運行結果:

Chning不屬於”manager”角色,也就沒有執行Get方法的權限。

3.4.客戶端驗證:Certificate

這部分的測試代碼: NetTcpBinding_Message_Certificate.rar

netTCPBinding綁定的Message安全模式,客戶端Certificate驗證,此時將使 用服務端證書,通過WS-Trust協議建立的安全通道,原理上類似SSL或TLS的機制 (但不是通過網絡傳輸層來實現,而是通過處理SOAP中的消息)來保證消息的安 全性。

這種方式的安全性:

完整性 使用服務端證書,通過WS-Trust協議建立的安全通道 保密性 使用服務端證書,通過WS-Trust協議建立的安全通道 服務端身份身份驗證 服務端證書提供 客戶端身份驗證 客戶端證書提供

3.4.1.獲得和安裝證書

同時客戶端驗證設置為Certificate,就需要提供客戶端證書以驗證客戶端身 份。

所有這裡需要在服務端和客戶端分別安裝證書。

這裡用Makecert.exe工具生成證書,使用下面的命令:

makecert -sr localmachine -ss My -n CN=win2008 -sky exchange -pe -r

這是服務端證書,win2008是服務端的機器名。

如果做過前面BasicHttpBinding的測試,這個服務端證書就應該已經有了。

makecert -sr currentuser -ss My -n CN=TestClient -sky exchange -pe -r

這是客戶端證書。

3.4.2.服務端代碼

internal static ServiceHost myServiceHost = null;
internal static void Main()
{
  NetTcpBinding myBinding = new NetTcpBinding();
  myBinding.Security.Mode = SecurityMode.Message;
  myBinding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
  Uri baseAddress = new Uri ("net.tcp://localhost:8056/WCFService/");
  myServiceHost = new ServiceHost(typeof(GetIdentity), baseAddress);
  ServiceEndpoint myServiceEndpoint = myServiceHost.AddServiceEndpoint
    (typeof(IGetIdentity), myBinding, "GetIdentity");
  //設置服務端證書
  myServiceHost.Credentials.ServiceCertificate.SetCertificate ("CN=win2008");
  //設置不驗證客戶端證書的有效性
   myServiceHost.Credentials.ClientCertificate.Authentication.Certificate ValidationMode =
     System.ServiceModel.Security.X509CertificateValidationMode.None;
  ServiceMetadataBehavior behavior = new ServiceMetadataBehavior ();
  behavior.HttpGetEnabled = true;
  behavior.HttpGetUrl = new Uri ("http://localhost:8057/mex");
  myServiceHost.Description.Behaviors.Add(behavior);
  myServiceHost.Open();
  Console.WriteLine("Service started!");
  Console.ReadLine();
  myServiceHost.Close();
}

3.4.3.客戶端代碼

static void Main(string[] args)
{
  NetTcpBinding myBinding = new NetTcpBinding();
  myBinding.Security.Mode = SecurityMode.Message;
  myBinding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
  EndpointAddress ea = new EndpointAddress ("net.tcp://win2008:8056/WCFService/GetIdentity");
  GetIdentityClient gc = new GetIdentityClient(myBinding, ea);
  //設置客戶端證書
  gc.ClientCredentials.ClientCertificate.SetCertificate ("CN=TestClient",
    StoreLocation.CurrentUser, StoreName.My);
  //設置不驗證服務端證書有效性
   gc.ClientCredentials.ServiceCertificate.Authentication.CertificateVali dationMode =
     System.ServiceModel.Security.X509CertificateValidationMode.None;
  //為使用TcpTrace跟蹤消息設置的TcpTrace監聽端口
  ClientViaBehavior myClientViaBehavior = new ClientViaBehavior
    (new Uri ("net.tcp://win2008:8055/WCFService/GetIdentity"));
  gc.Endpoint.Behaviors.Add(myClientViaBehavior);
  //執行代理類Get方法
  string result = gc.Get(WindowsIdentity.GetCurrent().Name);
  Console.WriteLine(result);
  Console.ReadLine();
}

3.4.4.測試

由於客戶端是Certificate身份驗證,到了服務端 ServiceSecurityContext.Current.PrimaryIdentity.Name獲得的是證書的 subject name和證書指紋。

3.4.5.證書映射到windows用戶

有時需要把客戶端證書映射為服務端的windows用戶,這樣可以使用windows 權限控制客戶端在服務端的權限。

在本例的情況,可以設置客戶端證書跟服務端windows用戶的映射,首先在服 務端的代碼或配置文件中設置允許客戶端證書到服務端windows用戶的映射。

代碼中將客戶端驗證MapClientCertificateToWindowsAccount設為True:

myServiceHost.Credentials.ClientCertificate.Authentication.Ma pClientCertificateToWindowsAccount = true;

配置文件中將服務端Behavior的客戶端證書驗證 MapClientCertificateToWindowsAccount設為True:

<serviceBehaviors>
   <behavior>
     <serviceCredentials>
       <clientCertificate>
          <authentication certificateValidationMode="None" mapClientCertificateToWindowsAccount="True" />
       </clientCertificate>
     </serviceCredentials>
   </behavior>
</serviceBehaviors>

然後在服務端設置映射,在操作系統上把客戶端的證書與windows用戶作映射 ,這必須是要在安裝了Active Directory的服務器上做。

具體步驟參考文章:Map certificates to user accounts: http://technet2.microsoft.com/WindowsServer/f/?en/library/0539dcf5- 82c5-48e6-be8a-57bca16c7e171033.mspx

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved