[No0000127]WCF安全体系netTCPBinding绑定
netTCPBinding绑定之Transport安全模式
一、netTCPBinding
此绑定使用TCP传输协议,不具交互性,只适用于 WCF 到 WCF 的通信。
此绑定的传输安全性的实现:
安全模式Message
这种模式WCF中都一样,都是使用WS-*通过对SOAP消息本身进行加密、签名等等的处理来保证安全性。Message模式不依赖于传输协议。服务端需要指定服务端证书,用来加密服务端和客户端相互传送的消息。
Transport – 客户端windows验证
使用windows security保证消息的安全,使用windows credential进行身份验证。
这种方式不需要服务端证书。
至于windows security的实现安全的原理我还不明白,这部分尚待了解。
Transport – 客户端其他验证方式
使用TLS over TCP实现传输安全性,需要服务端证书。
一般大家对SSL比较熟悉,对TLS可能要陌生些,其实可以说TLS协议可以看作跟SSL协议后续版本。1994年,netscape为了在internet上进行安全的数据传输,开发了的SSL协议,后来标准化组织把SSL标准化了,稍作修改改名叫TLS,在一般的使用意义上,这两个协议差别不大,就是在保证消息完整性的散列算法上使用了不同的算法。
TLS over TCP 直接建立在TCP协议上,通过传输层TCP协议实现安全性。
netTCPBinding绑定是直接使用TCP协议,不走HTTP,所以不能使用IIS宿主。这部分的测试实例采用自宿主的服务端console应用,基于代码的方式。
测试环境
服务端:
服务器名:win2008
操作系统:Windows server 2008
开发环境:visual studio 2008
运行环境:.net framework 3.5
Web服务器: IIS 7.0
浏览器:IE 7.0
客户端:
服务端机器同时充当测试客户端机器,同时准备了一台win2003的机器做测试客户端:
计算机名:win2003base2
操作系统:Windows server 2003
运行环境:.net framework 3.5
浏览器:IE 7.0
共用测试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给客户端。
1、安全模式 – None
这部分的测试代码:NetTcpBinding_None.rar
netTCPBinding绑定默认的安全模式是Transport,提供传输层的安全性,但是也提供None安全模式的选择,None安全模式不提供任何安全性和身份验证。
这种方式的安全性:
完整性 |
不提供 |
保密性 |
不提供 |
服务端身份身份验证 |
不提供 |
客户端身份验证 |
无,并忽略客户端验证的其他方式设置,固定为None |
本例采用全代码方式,不使用配置文件。
服务端代码:
internal static void Main()
{
NetTcpBinding myBinding = new NetTcpBinding();
myBinding.Security.Mode = SecurityMode.None;
myBinding.Security.Transport.ClientCredentialType = TcpClientCredentialType.None;
Uri baseAddress = new Uri("net.tcp://localhost:8056/WCFService/");
myServiceHost = new ServiceHost(typeof(GetIdentity), baseAddress);
ServiceEndpoint myServiceEndpoint = myServiceHost.AddServiceEndpoint
(typeof(IGetIdentity), myBinding, "GetIdentity");
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();
}
客户端代码:
static void Main(string[] args)
{
NetTcpBinding myBinding = new NetTcpBinding();
myBinding.Security.Mode = SecurityMode.None;
myBinding.Security.Transport.ClientCredentialType = TcpClientCredentialType.None;
EndpointAddress ea = new EndpointAddress("net.tcp://localhost:8056/WCFService/GetIdentity");
GetIdentityClient gc = new GetIdentityClient(myBinding, ea);
//为使用TcpTrace跟踪消息设置的TcpTrace监听端口
ClientViaBehavior myClientViaBehavior = new ClientViaBehavior
(new Uri("net.tcp://localhost:8055/WCFService/GetIdentity"));
gc.Endpoint.Behaviors.Add(myClientViaBehavior);
//执行代理类Get方法
string result = gc.Get(WindowsIdentity.GetCurrent().Name);
Console.WriteLine(result);
Console.ReadLine();
}
客户端设置了ClientVia的Vehavior,设置8055为监听端口,8056为实际端口,同时运行TcpTrace来跟踪通讯数据,客户端运行结果:
TCPTrace工具抓客户端和服务端的通讯数据:
从TcpTrace的截获的通讯数据可以看出:
netTCPBinding绑定采用binary编码。
netTCPBinding的None安全模式不对消息加密,从截获的数据可以看到返回的消息中文本部分是明文。
2、安全模式 - Transport
2.1.客户端验证:Windows
这部分的测试代码: NetTcpBinding_Transport_Windows.rar
netTCPBinding绑定的Transport安全模式,提供传输层的安全性,客户端Windows验证,此时将采用windows security在传输层来保证消息的安全性。
这种方式的安全性:
完整性 |
由windows security提供 |
保密性 |
由windows security提供 |
服务端身份身份验证 |
Windows集成验证 |
客户端身份验证 |
客户端Windows credential通过Windows继承验证客户端身份 |
本例采用全代码方式,不使用配置文件。代码部分是在前面None安全模式代码基础上在服务端和客户端的代码中将安全模式改为Transport,客户端验证方式改为Windows即可。
myBinding.Security.Mode = SecurityMode.Transport;
myBinding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Windows;
客户端运行结果:
TCPTrace工具抓客户端和服务端的通讯数据:
从TcpTrace的截获的通讯数据可以看出:
netTCPBinding绑定式采用binary编码。
netTCPBinding的Transport安全模式对消息加密,从截获的数据可以看到返回的消息中也看不到明文。
2.2.客户端验证:None
这部分的测试代码: NetTcpBinding_Transport_None.rar
netTCPBinding绑定的Transport安全模式,客户端None验证,此时将采用TLS协议在传输层来保证消息的安全性。
这种方式的安全性:
完整性 |
由TLS提供 |
保密性 |
由TLS提供 |
服务端身份身份验证 |
服务端证书提供 |
客户端身份验证 |
没有 |
2.2.1.获得和安装证书
TLS跟SSL一样,需要设置服务端证书。
这里用Makecert.exe工具生成证书,使用下面的命令:
makecert -sr localmachine -ss My -n CN=win2008 -sky exchange -pe -r
这是服务端证书,win2008是服务端的机器名。
如果做过前面BasicHttpBinding的测试,这个服务端证书就应该已经有了。
2.2.2.服务端代码
internal static ServiceHost myServiceHost = null;
internal static void Main()
{
NetTcpBinding myBinding = new NetTcpBinding();
myBinding.Security.Mode = SecurityMode.Transport;
myBinding.Security.Transport.ClientCredentialType = TcpClientCredentialType.None;
Uri baseAddress = new Uri("net.tcp://win2008: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://win2008:8057/mex");
myServiceHost.Description.Behaviors.Add(behavior);
myServiceHost.Open();
Console.WriteLine("Service started!");
Console.ReadLine();
myServiceHost.Close();
}
2.2.3.客户端代码
static void Main(string[] args)
{
NetTcpBinding myBinding = new NetTcpBinding();
myBinding.Security.Mode = SecurityMode.Transport;
myBinding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Certificate;
EndpointAddress ea = new EndpointAddress("net.tcp://win2008:8056/WCFService/GetIdentity");
GetIdentityClient gc = new GetIdentityClient(myBinding, ea);
//设置不验证服务端证书有效性
gc.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode =
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();
}
2.2.4.测试
客户端运行结果:
TCPTrace工具抓客户端和服务端的通讯数据:
从TcpTrace的截获的通讯数据可以看出:
netTCPBinding绑定式采用binary编码。
netTCPBinding的Transport安全模式对消息加密,从截获的数据可以看到返回的消息中也看不到明文。
2.3.客户端验证:Certificate
这部分的测试代码: NetTcpBinding_Transport_Certificate.rar
netTCPBinding绑定的Transport安全模式,客户端Certificate验证,此时将采用TLS协议在传输层来保证消息的安全性。
这种方式的安全性:
完整性 |
由TLS提供 |
保密性 |
由TLS提供 |
服务端身份身份验证 |
服务端证书提供 |
客户端身份验证 |
客户端证书提供 |
2.3.1.获得和安装证书
TLS跟SSL一样,需要设置服务端证书。
同时客户端验证设置为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
这是客户端证书。
2.3.2.服务端代码
internal static ServiceHost myServiceHost = null;
internal static void Main()
{
NetTcpBinding myBinding = new NetTcpBinding();
myBinding.Security.Mode = SecurityMode.Transport;
myBinding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Certificate;
Uri baseAddress = new Uri("net.tcp://win2008: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.CertificateValidationMode =
System.ServiceModel.Security.X509CertificateValidationMode.None;
ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
behavior.HttpGetEnabled = true;
behavior.HttpGetUrl = new Uri("http://win2008:8057/mex");
myServiceHost.Description.Behaviors.Add(behavior);
myServiceHost.Open();
Console.WriteLine("Service started!");
Console.ReadLine();
myServiceHost.Close();
}
2.3.3.客户端代码
static void Main(string[] args)
{
NetTcpBinding myBinding = new NetTcpBinding();
myBinding.Security.Mode = SecurityMode.Transport;
myBinding.Security.Transport.ClientCredentialType = TcpClientCredentialType.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.CertificateValidationMode =
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();
}
2.3.4.测试
由于客户端是Certificate身份验证,到了服务端ServiceSecurityContext.Current.WindowsIdentity.Name获得的是证书的subject name和证书指纹。
2.3.5.证书映射到windows用户
有时需要把客户端证书映射为服务端的windows用户,这样可以使用windows权限控制客户端在服务端的权限。
在本例的情况,可以设置客户端证书跟服务端windows用户的映射,首先在服务端的代码或配置文件中设置允许客户端证书到服务端windows用户的映射。
代码中将客户端验证MapClientCertificateToWindowsAccount设为True:
myServiceHost.Credentials.ClientCertificate.Authentication.MapClientCertificateToWindowsAccount = true;
配置文件中将服务端Behavior的客户端证书验证MapClientCertificateToWindowsAccount设为True:
<serviceBehaviors>
<behavior>
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="None" mapClientCertificateToWindowsAccount="True" />
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
然后根据不同的服务端不同的宿主分别设置映射,分两种情况:
宿主为IIS 7.0
在IIS中设置客户端证书到windows用户的映射,可以一对一的映射,也可以多对一的映射,具体参考文章:IIS 7 Walkthrough: One to One Client Certificate Mapping Configuration
宿主为console应用或服务
这是直接在操作系统上把客户端的证书与windows用户作映射,这必须是要在安装了Active Directory的服务器上做。
具体步骤参考文章:Map certificates to user accounts
netTCPBinding绑定之Message安全模式
一、netTCPBinding
此绑定使用TCP传输协议,不具交互性,只适用于 WCF 到 WCF 的通信。
此绑定的传输安全性的实现:
安全模式Message
这种模式WCF中都一样,都是使用WS-*通过对SOAP消息本身进行加密、签名等等的处理来保证安全性。Message模式不依赖于传输协议。服务端需要指定服务端证书,用来加密服务端和客户端相互传送的消息。
Transport – 客户端windows验证
使用windows security保证消息的安全,使用windows credential进行身份验证。
这种方式不需要服务端证书。
至于windows security的实现安全的原理我还不明白,这部分尚待了解。
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.CertificateValidationMode =
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.CertificateValidationMode =
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.UserNamePasswordValidationMode =
System.ServiceModel.Security.UserNamePasswordValidationMode.Custom;
myServiceHost.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = 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.CertificateValidationMode =
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.CertificateValidationMode =
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.CertificateValidationMode =
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.MapClientCertificateToWindowsAccount = 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
[No0000127]WCF安全体系netTCPBinding绑定的更多相关文章
- [No0000125]WCF安全体系
WCF的安全体系主要包括三个方面:传输安全(Transfer Security).授权或者访问控制(Authorization OR Access Control)以及审核(Auditing).而传输 ...
- WCF(五) 深入理解绑定
适用于本机WCF-WCF交互性能最佳的绑定: 允许跨主机,但只能用于部署同一台主机上,不能访问命名管道 netNamePipeBinding总结 一 WCF与SOA SOA是一种通过为所有软件提供服务 ...
- WCF 服务编程 - 常用绑定
WCF 定义了5中常用的绑定. 一. 绑定 1.基本绑定: 对应于BasicHttpBinding类.基本绑定能够将WCF服务公开为传统的ASMX Web服务,使得原客户端能够与新的服务协作.如果客 ...
- WCF系列_WCF常用绑定选择
一.五种常用绑定常用绑定的传输协议以及编码格式 名称 传输协议 编码格式 互操作性 BasicHttpBinding HTTP/HTTPS Text,MTOM Yes NetTcpBinding TC ...
- WCF : 如何将NetTcpBinding寄宿在IIS7上
摘要 : 从IIS 7 开始, IIS增加了对非HTTP协议的支持. 因此, 自IIS 7之后, 可以将NetTcpBinding等非HTTP协议的Bindings直接寄宿在IIS上面. 本文将介绍如 ...
- 十五天精通WCF——第八天 对“绑定”的最后一点理解
转眼已经中断10几天没有写博客了,也不是工作太忙,正好碰到了端午节,然后最近看天津台的爱情保卫战入迷了...太好看了,一直都是回味无穷...而且 涂磊老师话说的真是tmd的经典,然后就这样耽搁了,好了 ...
- WCF中的标准绑定
使用过WCF的童鞋们都很清楚,绑定是必须的.我将这些绑定总结了下. 一.标准绑定简要说明 1.basicHttpBinding 基于WS-I Basic Profile 1.1 的web服务,所需的. ...
- WCF使用net.tcp绑定的配置实例
<system.serviceModel> <bindings> <basicHttpBinding> <!--默认http绑定的配置,这里提高了最大传输信息 ...
- WCF使用net.tcp绑定时的注意事项
IIS Express没有net.tcp绑定功能,本地测试的话只能使用本机的IIS进行承载,并且需要相应的配置(参见上一篇文章). 算了,直接举一个配置例子吧,懒得写了... <system.s ...
随机推荐
- Kotlin VS Java:基本语法差异(转载)
5月18号,goole宣布Kotlin成为官方支持的开发语言以来,Kotlin语言社区,公众号,qq群等全面轰炸,本文是一篇译文,来自国外的一个用户,将给大家介绍,基础语法部分Kotlin和java之 ...
- ios开发:一个音乐播放器的设计与实现
github地址:https://github.com/wzpziyi1/MusicPlauer 这个Demo,关于歌曲播放的主要功能都实现了的.下一曲.上一曲,暂停,根据歌曲的播放进度动态滚动歌词, ...
- nginx配置http为1.0到1.1
转载自:https://blog.csdn.net/u014558668/article/details/79237020 需求:接口通过nginx转发服务器,接收不到数据,但是测试环境是好的: 环境 ...
- 【原】为DevExpress的ChartControl添加Y轴控制 和 GridControl中指定列添加超级链接
一.控制ChartControl的Y轴范围 使用Devexpress中的CharControl控件,需要控制AxisY轴的显示范围,需要使用该控件的BoundDataChanged事件,具体代码如下: ...
- centos7环境安装rabbitMQ
使用专业的消息队列产品rabbitmq之centos7环境安装 http://www.cnblogs.com/huangxincheng/p/6006569.html [源码安装,适用GNOME + ...
- segMatch:基于3D点云分割的回环检测
该论文的地址是:https://arxiv.org/pdf/1609.07720.pdf segmatch是一个提供车辆的回环检测的技术,使用提取和匹配分割的三维激光点云技术.分割的例子可以在下面的图 ...
- 8 -- 深入使用Spring -- 5...3 使用@CacheEvict清除缓存
8.5.3 使用@CacheEvict清除缓存 被@CacheEvict注解修饰的方法可用于清除缓存,使用@CacheEvict注解时可指定如下属性: ⊙ value : 必须属性.用于指定该方法用于 ...
- 通信原理之UDP协议(四)
1.UDP简要介绍 UDP是传输层协议,和TCP协议处于一个分层中,但是与TCP协议不同,UDP协议并不提供超时重传,出错重传等功能,也就是说其是不可靠的协议. 2.UDP协议头 2.1.UDP端口号 ...
- 【中间件安全】Nginx 安全加固规范
1. 适用情况 适用于使用Nginx进行部署的Web网站. 2. 技能要求 熟悉Nginx配置,能够Nginx进行部署,并能针对站点使用Nginx进行安全加固. 3. 前置条件 1. 根据站点开放端口 ...
- JS编程题
1.计算给定数组 arr 中所有元素的总和 (数组中的元素均为 Number 类型) function sum(arr) { var sum=0; for (var i=arr.length-1; i ...