WCF分散式安全開發實踐(12):訊息安全模式之自定義X509證書驗證

技術小胖子發表於2017-11-07
    今天繼續介紹WCF分散式安全開發實踐(12):訊息安全模式之自定義X509證書驗證,Message_CustomX509Certificate_WSHttpBinding 。本文介紹的內容主要是:主要是訊息安全模式的自定義證書身份驗證方式,基於WSHttpBinding繫結協議的實現過程。主要內容:基本概念,然後是製作證書、服務端配置、客戶端配置、總結。這裡應該和Transport傳輸安全模式之自定義證書身份驗證對應,但是訊息安全模式這裡不使用https。安全基於TLS,傳輸層安全連線。  

    和WCF分散式安全開發實踐(11):訊息安全模式之Certificate身份驗證:Message_Certificate_WSHttpBinding大部分過程相同。差別在於客戶端證書的驗證過程由我們自己提供。而不是有WCF框架自己完整。

【0】訊息安全模式之自定義證書客戶端身份驗證:

       訊息安全模式之自定義證書身份驗證需要伺服器需要一個有效的可用於TLS 加密和向客戶端驗證服務身份的 X.509 證書,並且客戶端必須信任此伺服器證書。而客戶端同樣要提供一個有效的證書,來證明自己的身份。 這裡使用http協議。建議安全上下文以後,使用共享安全上下文對SOAP訊息進行加密和簽名。使用證書對客戶端和服務進行身份驗證。也就是客戶端提供有效證書才可以訪問此服務。
1.身份驗證(伺服器):提供證書,(使用 HTTP)用於初始會話協商和證明服務身份。 

2.身份驗證(客戶端):客戶端證書進行身份驗證,自定義驗證程式碼
   WCF訊息安全模式之自定義證書身份驗證的架構如下:
    客戶端建立TLS安全上下文以後,會使用商定的密碼對訊息簽名,客戶端使用證書加密資料,服務端使用證書解密資料,保證資料的安全和機密性,訊息簽名放置被篡改。

   這裡客戶端提供的是有效的證書,伺服器端使用自定義程式碼對客戶端證書進行驗證。而不是有WCF框架自動完成。

   下面是製作證書的過程,和傳輸安全模式的過程一樣,這裡直接使用相同證書製作工具,新啟用埠8001。

【1】製作證書:

(1)使用makecert 工具:Microsoft Visual Studio 2008–>Visual Studio Tools–>Visual Studio 2008 命令提示行。

輸入:makecert -sr localmachine -ss My -n CN=WCFServerPK -sky exchange -pe -r



輸入:makecert -sr localmachine -ss My -n CN=WCFClientPK -sky exchange -pe -r。
-這裡製作了連個證書,主要只使用一個WCFServerPK,可以到出金鑰檔案pfx,後續我們要匯入到其他儲存區,設定為信任的證書。WCFClientPK -是為以後文章準備的,也是可以設定為信任的證書。

 (2) 開啟瀏覽器—->Internet 選項—–>內容—–>證書—–>個人,預設是儲存到當前使用者CurrentUser,你會看到剛才製作的證書。這個可以檢視部分證書,但是功能有限。我們還是使用控制檯證書管理工具。

 (3)使用MMC建立證書控制單元檢視證書的資訊:

  開始–執行–MMC–控制檯–新增刪除單元–證書–當前使用者和計算機各新增一個。能檢視和管理CurrentUser和LocalMachine的證書。如圖:
(4)匯入證書到信任的人和信任的CA機構裡。步驟如下:

    1.匯出證書檔案,帶金鑰的pfx檔案。使用mmc,儲存到桌面位置(方便查詢)。這裡記住你製作證書的密碼。要使用。

    2.匯入證書到信任的人。使用任務-匯入嚮導–選擇證書檔案,匯入即可。

    3.匯入證書到信任的機構,使用任務-匯入嚮導–選擇證書檔案,匯入即可。這個證書就被信任了。
【3】服務端配置:
   伺服器證書配置完成以後,我們來配置服務端相關的檔案,這裡簡單。也可以使用程式碼來完成。

    (1)服務類定義:

    重複使用以前定義的服務類程式碼。 這裡服務類就一個方法就是更具使用者的name來列印呼叫時間,程式碼如下:
 //1.服務契約
    [ServiceContract(Namespace = http://www.cnblogs.com/frank_xl/)]

    
public interface
 IWCFService

    {

        
//操作契約

        [OperationContract]

        
string SayHello(string
 name);


    }

    
//2.服務類,繼承介面。實現服務契約定義的操作

    public class WCFService : IWCFService

    {

        
//實現介面定義的方法

        public string SayHello(string name)

        {

            Console.WriteLine(
Hello! {0},Calling at {1} 
, name,DateTime.Now.ToLongTimeString());

            
return Hello!  +
 name;

        }

    }
    (2)訊息安全模式配置:

       使用訊息安全模式,採用客戶端證書身份驗證策略,Message安全模式下的證書驗證方式配置資訊如下:
    <wsHttpBinding>
      
<binding name=BindingConfigration>
        
<security mode=Message>
          
<transport clientCredentialType=None/>
          
<message clientCredentialType=Certificate negotiateServiceCredential=true establishSecurityContext=true/>
        
</security>
      
</binding>
    
</wsHttpBinding>
   這裡允許啟用安全協商和建立安全上下文。這個配置要應用到服務的終結點配置上。才會生效。

    (1)服務驗證程式碼:

    證書製作完整以後,就需要來實現自定義使用者名稱和密碼的驗證程式。這裡要重寫X509CertificateValidator類的 Validate(X509Certificate2 certificate)方法。具體程式碼如下:
  //證書驗證程式,這裡可以訪問證書資料庫或者其他證書儲存機構,來驗證客戶端證書的真偽。
        public class CustomX509CertificateValidator : X509CertificateValidator

        {

            
public override void
 Validate(X509Certificate2 certificate)

            {

                Console.WriteLine(
Certificate Subject is :{0}
, certificate.Subject);

                Console.WriteLine(
Certificate Thumbprint is :{0}
, certificate.Thumbprint);

                
//This is the Client  Certificate Thumbprint,In Production,We can validate the Certificate With CA

                if (certificate.Thumbprint != 748e3f8d07f14750460244045e21633cf1f5b211)

                {


                    Console.WriteLine(
CertificateValidatation is failed !{0}
, certificate.Subject);

                    
throw new SecurityTokenException(Unknown Certificate
);

                }

                
else

                {

                    Console.WriteLine(
CertificateValidatation is sucessfully !:{0}, certificate.Subject);

                }

            } 

        }
    這裡客戶端證書的指紋是748e3f8d07f14750460244045e21633cf1f5b211。如果客戶端提供的證書資訊不對,就直接丟擲異常,驗證失敗,實際應用我們可以到CA證書機構或者證書資料庫查詢資料,來判定客戶端證書的有效性。傳輸安全保證了使用者名稱密碼的機密性,而驗證程式碼可以靈活地訪問我們系統的資料庫或者CA來判定客戶端是否是有效的客戶端。可以很好的保護WCF服務。與自定義使用者名稱密碼的方式一樣,驗證程式比較靈活。伺服器不需要匯入客戶端證書。

    自定義客戶端程式碼我們在配置檔案裡設定。程式碼如下:
            <clientCertificate >

              
<authentication   certificateValidationMode=Custom  customCertificateValidatorType=WCFService.CustomX509CertificateValidator,WCFService/>

            
</clientCertificate>


    (4)伺服器證書使用:

        伺服器端證書主要是在建立TLS連線會話的時候,證明服務端的身份合法性。

    在服務行為節點屬性裡配置使用證書WCFServerPK,其它設定採用預設方式。這裡和WCF分散式安全開發實踐(7):訊息安全模式之匿名客戶端:Message_None_WSHttpBinding 配置一樣。具體程式碼如下:
<serviceBehaviors> 

                <behavior name=”WCFService.WCFServiceBehavior”> 

                    <serviceMetadata httpGetEnabled=”true” /> 

                    <serviceDebug includeExceptionDetailInFaults=”false” /> 

                    <serviceCredentials> 

                            <serviceCertificate    storeName=”My”    x509FindType=”FindBySubjectName” findValue=”WCFServerPK” storeLocation=”LocalMachine”/> 

                        <clientCertificate > 

                            <authentication     certificateValidationMode=”Custom”    customCertificateValidatorType=”WCFService.CustomX509CertificateValidator,WCFService”/> 

                        </clientCertificate> 

                    </serviceCredentials> 

                </behavior> 

                

            </serviceBehaviors>
    這裡指定了服務端證書的查詢位置和查詢條件,我們證書儲存在LocalMachine 個人區域。使用標題進行查詢。如果相同標題,需要制定唯一的查詢條件。保證查詢證書的唯一性。否則會出異常。

   (5)這裡我們不需要使用Https傳輸協議,直接使用http協議即可,服務終結點的配置資訊如下:
    <services>
      
<service behaviorConfiguration=WCFService.WCFServiceBehavior name=WCFService.WCFService >
        
<endpoint 

          address
=WCFService
 

          binding
=wsHttpBinding
 

          bindingConfiguration
=BindingConfigration

          contract
=WCFService.IWCFService>
        
</endpoint>
        
<endpoint address=mex binding=mexHttpBinding contract=IMetadataExchange />
        
<host>
          
<baseAddresses>
            
<add baseAddress=http://localhost:8001//>
          
</baseAddresses>
        
</host>
      
</service>
    
</services>
   我們的服務後設資料終結點使用基地址:http://localhost:8001/。訊息安全模式基本使用的都是相同的埠。
【4】客戶端配置:

    這個過程和之前的傳輸安全模式下,參考WCF分散式安全開發實踐(11):訊息安全模式之Certificate身份驗證:Message_Certificate_WSHttpBinding , 新增服務的過程一樣。直接引用。
    (1)引用後設資料:

    因為服務的後設資料交換節點啟用了Http協議,我們在客戶端專案新增後設資料地址http://localhost:8001/mex查詢服務資訊的時候,介面如下:
   繼續就會新增完畢服務引用。過程和普通的新增服務後設資料引用一樣,會產生客戶端相關程式碼檔案。輸入名稱空間,現在我們點選Ok。等待完成即可。   

    (2)配置檔案:

    客戶端配置檔案使用預設設定,主要是安全模式的設定要如下,與服務端匹配。使用證書驗證方式。
bindings>
            
<wsHttpBinding>
                
<binding name=WSHttpBinding_IWCFService>
                    
<security mode=Message>
                        
<transport clientCredentialType=None proxyCredentialType=None
                            realm
=“” />
                        
<message clientCredentialType=Certificate negotiateServiceCredential=true
                            algorithmSuite
=Default establishSecurityContext=true />
                    
</security>
                
</binding>
            
</wsHttpBinding>
        
</bindings>
    (3)客戶端證書:

        這裡我們要在配置檔案裡提供客戶端的證書,也可以採用程式碼方式提供客戶端證書。配置檔案的方式比較簡單。

直接在endpointBehaviors裡設定以後,應用到終結點行為配置上就可以了。程式碼如下:
      <behaviors>
        
<endpointBehaviors>
          
<behavior name=endpointBehavior>
            
<clientCredentials>
              
<clientCertificate storeName=My
                                 x509FindType
=FindBySubjectName
                                 findValue
=WCFClientPK
                                 storeLocation
=CurrentUser/>
            
</clientCredentials>
          
</behavior>
        
</endpointBehaviors>
      
</behaviors>
    (4)測試程式碼:

      等待程式碼生成結束,我們這裡就直接生成客戶端代理類的例項來呼叫服務進行測試。這裡客戶端在呼叫服務以前,必須信任證書,這裡我們使用了一段通用的程式碼,來建立TLS使用。這裡會信任伺服器的證書。程式碼如下:
 public static class Util

    {

        
/// <summary>

        
/// Sets the cert policy.

        
/// </summary>

        public static void SetCertificatePolicy()

        {

            ServicePointManager.ServerCertificateValidationCallback

                       
+=
 RemoteCertificateValidate;

        }


        
/// <summary>

        
/// Remotes the certificate validate.

        
/// </summary>

        private static bool RemoteCertificateValidate(

           
object
 sender, X509Certificate cert,

            X509Chain chain, SslPolicyErrors error)

        {

            
// trust any certificate!!!

            System.Console.WriteLine(Warning, trust any certificate);

            
return true
;

        }

    }
   客戶端測試程式碼很簡單,我們不需要提供客戶端證書了,因為配置檔案裡已經設定完畢。接下來就是通過客戶端代理來呼叫WCF服務。程式碼如下:
       static void Main(string[] args)

        {


            
try

            {

                Console.ForegroundColor 
= ConsoleColor.Green;

                WCFClient.ClientProxy.WCFServiceClient wcfServiceProxy 
= new WCFClient.ClientProxy.WCFServiceClient(WSHttpBinding_IWCFService
);

                
//通過代理呼叫SayHello服務

                string sName = Frank Xu Lei  Message Certificate WSHttpBinding;

                
string sResult = string
.Empty;

                Util.SetCertificatePolicy();

                sResult 
=
 wcfServiceProxy.SayHello(sName);

                Console.WriteLine(
Returned Result is {0}
, sResult);

            }

            
catch
 (Exception e)

            {

               Console.WriteLine(
Exception : {0}
, e.Message);

            }

            
//For Debug

            Console.WriteLine(Press any key to exit);

            Console.Read();

            

        }
    這裡也可以使用程式碼來設定證書wcfServiceProxy.ClientCredentials.ClientCertificate.Certificate = new X509Certificate2(“WCFClientPK.pfx”, “password”);WCFClientPK.pfx是匯出的客戶端證書的檔案,包含金鑰,密碼為保護密碼。
  (4)測試結果:

   啟動宿主程式,然後啟動客戶端程式,客戶端成功呼叫服務,宿主列印的訊息。如圖:
【5】總結

     Windows Communication Foundation (WCF) 服務和客戶端。WCF安全機制都是依賴現有的安全體系和框架來完成的。這裡的訊息安全模式下的客戶端證書身份驗證,其實沒有太大的變化。就是使用證書來驗證客戶端的有效性,合法性。

   (1)伺服器需要一個證明伺服器身份和有效的可用於TLS傳輸層安全的 X.509 證書,並且客戶端必須信任此伺服器證書。

   (2)客戶端提交證書的方式與傳輸安全之證書驗證方式一樣,伺服器端需要提供證書,但是不需要httpcfg.exe設定。

   (3)初始協商需要伺服器證書來建立TLS連線,協商完畢以後,建立共享安全上下文,這裡使用商定的加密演算法對SOAP訊息進行加密和簽名。

   (4)如果你啟用協商,而不把伺服器證書在客戶端設定信任,匯入信任的辦法機構,會出現SOAP安全協商失敗的異常。

   (5)和訊息安全模式的客戶端證書驗證,過程基本一樣。差別只是在於客戶端證書有效性驗證,前者使用的是WCF框架自定來驗證,這裡我們使用的是自定義驗證程式,重新實現了CustomX509CertificateValidator : X509CertificateValidator的Validate(X509Certificate2 certificate)方法。這裡我們可以方便的定義具體的驗證策略,也可以把證書資訊存在特定的資料庫,或者直接程式碼從證書存貯區域獲取證書資訊進行驗證。

   (6)參考程式碼: 
/Files/frank_xl/6.5.WCFServiceSecurityDemoFrankXuLei_Message_CustomX.509Certificate_WSHttpBinding.rar   

     以上就是訊息安全模式下的自定義X509證書的驗證過程。這個安全系列的Demo程式基本結束。我會再整理一個總結性的文章給《WCF分散式安全開發實踐》做個總結。 這些例子都可以擴充套件,比如更換繫結,等等,但是開發過程基本類似。。有什麼建議可以提出,歡迎留言交流~

參考文章:
1.WCF分散式安全開發實踐(11):訊息安全模式之Certificate身份驗證:Message_Certificate_WSHttpBinding 

2.WCF分散式安全開發實踐(6):傳輸安全模式之自定義X509Certificate證書驗證:Transport_X509Certificate_WSHttpBinding 

3.http://social.microsoft.com/Forums/zh-CN/wcfzhchs/thread/e1aa7bea-90d8-41e6-b91b-7addba44f8e3

4.WSE3.0構建Web服務安全(2):非對稱加密、公鑰、金鑰、證書、簽名的區別和聯絡以及X.509 證書的獲得和管理





 本文轉自 frankxulei 51CTO部落格,原文連結:http://blog.51cto.com/frankxulei/320884,如需轉載請自行聯絡原作者




相關文章