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=client" -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匹對的話,我們就可以成功的驗證了.