1. Transfer Security
Transfer Security 主要包括三个方面: "消息完整性(Message Integrity)"、"消息机密性 (Message Confidentiality)" 和 "交互验证(Mutual Authentication)"。
消息完整性必须确保消息在传输过程中没有被篡改,接收的消息是完整且正确的;消息机密性必须确保消息不会被任何第三方查阅,消息内容不会泄漏给任何非相关人员;而交互认证则是指客户端和服务器必须通过某种信任机制才能建立正确的连接,同时交互认证还要监测并阻止拒绝服务攻击(DOS)。通常的做法是对消息进行数字签名来确保其完整性,使用非对称加密算法来阻止消息内容外泄,而用户名/密码、X.509 数字证书等方式则可以用来验证对方身份,在这里我们主要讲述如何在WCF中使用用户名/密码的身份验证方式.
2. x.509数字证书验证:
在上一篇blog中我们讲述了使用userName/password方式来验证身份,http://www.cnblogs.com/liujiang/archive/2008/11/21/1338384.html.现在我们来讲述一下如何使用X.509证书的方式来验证.首先让我们先了解一下X.509证书的相关技术.。X.509是由国际电信联盟(ITU-T)制定的数字证书标准。X.509是一种基于公开密钥体制的鉴别业务密钥管理,拥有证书的用户都有两把密钥,一把叫公钥,一把叫私钥.私钥的保密性很高,一般情况下只用户本人知道.公钥是是其他用户都可利用的公共密钥.比如说我们的server有Temp的数字证书.我们Client端就可以使用Server的公钥对消息进行加密并发送消息给Server端,然后server端通过私钥来解密消息.凡是被公钥加密过的消息一般情况下只
能由私钥来解密,可见私钥的重要性所在.在WCF userName/password中就是使用公钥来加密用户名和密码的.下面我们谈谈在WCF中使用X.509认证方式。WCF的服务端和客户端之间,如果不作任何安全处理(即服务端的<security mode="None">),则所有传输的消息将以明文方传输,在internet/intranet环境下是很不安全的,这就是用证书的目。当我们使用UserName方式,通常每次都要从数据库读取用户名/密码信息进行验证,比较麻烦,开销也大.所以在我们也可以使用x.509方式来验证.下面我们以一个Demo来说明如何使用x.509的身份验证方式.使用vs2008的tool中的command命令下执行:
makecert -r -pe -n "CN=MyServer" -ss My -sky exchange .
makecert -r -pe -n CN=client" -ss My -sky exchange.我们就可以为服务器生成client的证书.如下图所示.
首先我们查看一client的序列号.每个客户端的数字证书名称和序号的组合都是唯一的,因为我需要客户端的序列号在服务端进行验证.验证通过才能访问operation.
至所以我们需要使用序列号是因为在我服务端我们需要验证客端的序列号的正确性,当然这些序列号在服务端是已知的,否则的话服务端也就无法正确验证了。该验证确保client端是否有权限访问service的操作。当客户端的序列号与服务端已有的序列号(可以存在config文件里,也可以存在数据库里)相同的话就可以通过验证。
由此可以看出X509的验证比userName/passoword的系统开销小。因为userName/Password需要读取用户数据并进行配对,用户数据一般存储在数据库中。对于X.529这种验证个人觉的这种验证适合B/S结构的。
3.Solution 结构如下图:
solution:WCFValidationContract WCF contract.
WCFValidationClient WCF client端. WCFValidationServices 主要是实现contract的类 WCFValidationHost..用于启动WCF.创建服务
[ServiceContract]
public interface IX509//对应solution中的WCFValidationContract.IX509
{
[OperationContract]
bool test();
}
public class X509:IX509//对应solution中的WCFValidationServices.X509
{
#region IX509 Members
public bool test()
{
return true;
}
#endregion
}
我们通过继承 X509CertificateValidator来创建一个自定义验证器。//对应solution中的WCFValidationServices.X509Validation
class X509Validation :X509CertificateValidator{
public override void Validate(System.Security.Cryptography.X509Certificates.X509Certificate2 certificate)
{
//we can use Thumbprint SignatureAlgorithm subject name and so one for validation.
//the sample only use SerialNumber.
//如果客户端序列号与此不同的话,就报异常,通常情况我们会在客户端进行异常处理的.
//The socket connection was aborted. This could be caused by an error processing your message or a
// receive timeout being exceeded by the remote host, or an underlying network resource issue.
//Local socket timeout was '00:00:59.9844000'
//这是因为WCF没有将服务实例释放而导致辞的。
//我们可以判断客户端的SerialNumber和服务端存储的客户端是否相同
if (certificate.SerialNumber.ToLower() != "6bfa829a7453219e402c534671154e4e")
throw new Exception("Certificate Error!");
}
}
服务端的配置文件如下:(host的配置文件)
<system.serviceModel><behaviors>
<serviceBehaviors>
<behavior name="X509Behavior">
<serviceMetadata httpGetEnabled="true" httpGetUrl="http://localhost/X509"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<clientCertificate>
<authentication customCertificateValidatorType= "WCFValidationServices.X509Validation,WCFValidationServices"
certificateValidationMode="Custom" />
</clientCertificate>
<serviceCertificate findValue="MyServer" storeLocation="CurrentUser" x509FindType="FindBySubjectName"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<netTcpBinding>
<binding name="x509Binding" >
<security mode="Transport">
<transport clientCredentialType ="Certificate"/>
</security>
</binding>
</netTcpBinding>
</bindings>
<services>
<service behaviorConfiguration="X509Behavior" name="WCFValidationServices.X509">
<endpoint address="" binding="netTcpBinding" bindingConfiguration="x509Binding" name ="X509" contract="WCFValidation.IX509">
</endpoint>
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:8082/X509"/>
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel> 4. 创建客户端
启动服务器后,创建客户端代理文件。注意自动生成的客户端配置文件中包含了服务器数字证书的相关信息。 <system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="NewBehavior">
<clientCredentials>
<clientCertificate storeLocation="CurrentUser" findValue="client" x509FindType="FindBySubjectName" />
<serviceCertificate>
<authentication certificateValidationMode="None"/>//因为我们使用的是非信任证书
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors> <bindings>
<netTcpBinding>
<binding name="X509" >
<security mode="Transport">
<transport clientCredentialType="Certificate" protectionLevel="EncryptAndSign" />
<message clientCredentialType="Windows" />
</security>
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint address="net.tcp://localhost:8082/X509" binding="netTcpBinding" behaviorConfiguration="NewBehavior"
bindingConfiguration="X509" contract="IX509" name="X509">
<identity>
<dns value="MyServer" />
</identity>
</endpoint>
</client> 客户端由Svcutil工具生成的,在这里就不贴出来了。
客户端代码:
X509Client validate = new X509Client("X509");
bool result=validate.test();
validate.Close();
Console.WriteLine(result.ToString());
Console.ReadKey();
如果能成功能过验证的话:ConsoleApplication将会输入正确的结果:True,否则的话会报异常。
如果SerialNumber匹对的话,我们就可以成功的验证了.