1. 程式人生 > >從零開始學WCF(14)WCF安全性概述

從零開始學WCF(14)WCF安全性概述

安全性概述

常見的安全威脅:

1) 觀測網路流量以獲取敏感資訊。以線上銀行為列,某個客戶端請求將資金從一個賬戶轉賬到另一個賬戶。一個惡意使用者截獲了此訊息(具有賬號和密碼),隨後從盜用的賬戶將資金轉出。

2) 欺詐性實體在客戶端未發覺的情況下其服務的作用。在此情況下,惡意使用者(欺詐方)充當線上服務,從客戶端截獲訊息以獲取敏感訊息。然後,欺詐方使用竊取的資料將資金從盜用的賬戶轉出。此類攻擊也稱為“釣魚攻擊”。

3) 更改訊息以獲取與呼叫方所需的結果不同的結果。例如,更改用於存款的賬號以便將資金轉移到惡意賬戶。

4) 黑客重放,惡意黑客重放同一採購訂單。例如,一家網上書店收到數百張訂單並將書籍傳送給未訂購這些書籍的客戶。

5) 使某項服務無法對客戶端進行身份驗證。在此情況下,服務無法確保相應人員執行該項事務。

傳輸安全性可提供下列保障:

1) 服務終結點(響應方)身份驗證

2) 客戶端主體(發起方)身份驗證

3) 訊息完整性

4) 訊息保密性

5) 重放檢測

WCF是一個基於SOAP訊息的分散式程式設計平臺,因此保護客戶端的服務之間的訊息安全對於保護資料非常重要。

WCF基於現有安全性基礎架構和SOAP訊息的經驗證的安全標準提供可互操作的安全訊息交換通用平臺。

與現有的安全性基礎結構整合:

通常,Web服務部署都具有現成的安全性解決方案,例如,安全套接字層(SSL)或Kerberos協議。某些服務則利用已部署的安全性基礎結構,例如,使用Active Director的WIndows域。當評估和採用新服務時,通常需要與這些現有技術整合。

WCF安全性與現有傳輸安全模型整合,並且可對基於SOAP訊息安全的新傳輸安全模型使用現有的基礎結構。

與現有身份驗證模型整合

任何通訊安全模型的一個重要組成部分就是能夠識別正在通訊的實體並對其進行身份驗證。這些通訊中的實體使用“數字標識”或憑據向通訊對等方驗證自己的身份。隨著分散式通訊平臺的發展,以實現多種不同的憑據身份驗證和相關的安全模型。

1) 在Internet中,通常使用使用者名稱和密碼標識使用者。

2) 在Intranet中,使用Kerberos域控制器備份使用者和服務身份驗證變得越來越普遍。

3) 在業務合作伙伴之間,證書可用於對合作夥伴的身份進行相互驗證。

因此,在Web服務領域中,同樣的服務可向內部企業客戶公開,也可想外部合作伙伴或Internet客戶公開,重要的是基礎結構可提供與這些現有安全身份驗證模型的整合。WCF安全性支援多種憑據型別(身份驗證模型),其中包括:

1) 匿名呼叫方。

2) 使用者名稱客戶端憑據。

3) 證書客戶端憑據。

4) Windows(Kerberos協議和NT LanMan[NTLM])

WCF安全性的功能劃分:

1) 傳輸安全性:

傳輸安全性包括三項主要安全功能:完整性、保密性和身份驗證。完整性就是檢測訊息是否已被串改的能力。機密性就是保證除預期接收方之外的其他人員都無法讀取某個訊息;這可以通過加密技術實現。身份驗證就是驗證已宣告標識的能力。將這三項功能結合在一起,有助於確保訊息安全地從一個點到達另一個點。

2) 訪問控制:

訪問控制也成為身份驗證。身份驗證使得不同的使用者可以具有不同的資料檢視許可權。

3) 稽核:

稽核就是將安全事件記錄到Windows事件日誌中。可以記錄與安全相關的事件,例如身份驗證失敗(或成功)。

傳輸安全性

三項功能——完整性、保密性和身份驗證——合稱為傳輸安全:


使用WCF傳輸安全的常見方案包括:

1) 使用Windows確保傳輸安全:

WCF客戶端和服務部署在Windows域(或WIndows目錄林)中。

2) 使用Username和Https確保傳輸安全:

客戶端憑據根據資料庫(其中的內容為使用者名稱/密碼對)進行身份驗證。服務是用受信任的安全套接字層(SSL)證書部署在一個HTTPS地址的。由於訊息是通過Internet傳輸的,因此,客戶端和服務需要相互進行身份驗證,並且必須在傳輸過程中保持訊息的保密性和完整性。

3) 使用證書確保傳輸安全:

客戶端和服務都具有可用於確保訊息安全的證書。客戶端和服務通過Internet進行相互通訊,執行要求訊息完整性、保密性和相互身份驗證的重要事務。

傳輸安全模式


繫結支援的安全模式:


憑據

憑據是一些資料,用於證實已宣告表示或功能。出示憑據的操作包括,同事出示資料和對資料的所有權宣告。 例如,考慮WCF中支援的兩種憑據型別: 1) 使用者名稱 使用者名錶示已宣告的標識,密碼錶示所有權證明。這種情況下,受信任的頒發機構則是驗證使用者名稱和密碼的系統。 2) (X.509)證書憑據 在證書憑據中,主題名稱、主題備用名稱或證書中的特定欄位可用於表示已宣告標識和/或功能。憑據中的資料所有權證明的建立,是用關聯私鑰生成簽名實現的。 傳輸安全模式(Transport)的憑據型別:
訊息安全模式(Message)的憑據型別:

傳輸安全示例(Transport)DEMO

1) 新建一個WCF Application Service專案,然後定義WCF服務介面:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace Video14.Demo1.TransportSecurity
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "ICalculatorService" in both code and config file together.
    [ServiceContract]
    public interface ICalculatorService
    {
        [OperationContract]
        double Add(double n1, double n2);
        [OperationContract]
        double Subtract(double n1, double n2);
        [OperationContract]
        double Multiply(double n1, double n2);
        [OperationContract]
        double Divide(double n1, double n2);
    }
}

2) 實現該服務類
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace Video14.Demo1.TransportSecurity
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "CalculatorService" in code, svc and config file together.
    public class CalculatorService : ICalculatorService
    {
        public double Add(double n1, double n2)
        {
            return n1 + n2;
        }

        public double Subtract(double n1, double n2)
        {
            return n1 - n2;
        }

        public double Multiply(double n1, double n2)
        {
            return n1 * n2;
        }

        public double Divide(double n1, double n2)
        {
            return n1 / n2;
        }
    }
}

3) 配置配置檔案,在配置檔案裡指定安全模式為傳輸安全模式:
<?xml version="1.0"?>
<configuration>

  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>

    <services>
      <service name="Video14.Demo1.TransportSecurity.CalculatorService" behaviorConfiguration="CalculatorServiceBehavior">
        <endpoint address="" binding="wsHttpBinding" bindingConfiguration="Binding1" contract="Video14.Demo1.TransportSecurity.ICalculatorService"/>
      </service>
    </services>

    <bindings>
      <wsHttpBinding>
        <binding name="Binding1">
          <!--指定在wsHttpBinding基礎上使用安全模式為Transport的傳輸安全模式,所有的安全性都交由傳輸層來決定,傳輸層也就是部署方在IIS中進行配置-->
          <security mode="Transport">
            <!--客戶端的憑據型別:客戶端無需證明自己的身份-->
            <transport clientCredentialType="None"/>
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    
    <behaviors>
      <serviceBehaviors>
        <behavior name="CalculatorServiceBehavior">
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
  
</configuration>

4) 編輯生成的bin及服務檔案,部署到IIS上。 5) 這裡由於使用了Transport模式的傳輸安全,所有需要開啟IIS上支援SSL安全套接字層的支援。開啟方法:
6) 我們在IIS上,可以用證書來進行安全套接字層的保障,首先我們需要證書,我們建立一個自簽名的證書:
7) 建立好證書後,所有在這臺IIS上所部署的服務也好,或者是網站應用程式也好,都可以利用這個證書來進行安全套接字層的部署,所有跟這臺IIS上面利用HTTS訪問的資料交換都會使用這個證書來加密和簽名。證書建立好後,需要在網站上新增對HTTS的支援,並且在HTTPS上指定證書為剛剛建立的TestForService證書,這也就保證了所以使用HTTPS來請求這臺上的資料都會使用這個證書來簽名和加密。
8) 進一步來看看我們具體的應用程式,需要在應用程式上來指定是否使用SSL:
9) 點選SSL設定後,我們設定客戶端證書是“忽略”的:
10) 以上設定完畢後,我們來測試一下,在IE中輸入“https://localhost/TransportSecurity/CalculatorService.svc”來開啟這個WCF服務,開啟的時候會提示一個警報,這事由於瀏覽器不認識這個證書,這時候我們點選繼續瀏覽此網站即可。開啟後我們可以看到這個WCF服務如下:由於我們沒有開啟mex的Endpoint,所以我發檢視到他的WSDL
11) 如果我們在前面的SSL設定上選中了“要求SSL”,而且是“必需的”


那麼我們在IE上開打這個WCF服務的時候就會看到“HTTP 錯誤 403.7 - Forbidden您嘗試訪問的頁面要求您的瀏覽器具有該 Web 伺服器可識別的安全套接字層(SSL)客戶證書”

12) 新增一個客戶端程式Client,然後使用SVCUTIL控制檯程式生成WCF服務的客戶端代理類及配置檔案(如果生成的時候有問題請參照:http://blog.csdn.net/eric_k1m/article/details/13770043),然後新增到該專案中。在Main方法中進行測試:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Client.ServiceReference1;
using System.Net;
using System.Security.Cryptography.X509Certificates;

namespace Client
{
    class Program
    {
        static void Main(string[] args)
        {
            // WARNING: This code is only needed for test certificates such as those created by makecert. It is 
            // not recommended for production code.
            //證書策略,需要找到CN=Eric-PC.TYCOFS.COM的證書,就相當於認可這個服務,然後才能進行方法的呼叫
            PermissiveCertificatePolicy.Enact("CN=Eric-PC.TYCOFS.COM");

            // Create a client with given client endpoint configuration
            CalculatorServiceClient client = new CalculatorServiceClient();

            // Call the Add service operation.
            double value1 = 100.00D;
            double value2 = 15.99D;
            double result = client.Add(value1, value2);
            Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result);

            // Call the Subtract service operation.
            value1 = 145.00D;
            value2 = 76.54D;
            result = client.Subtract(value1, value2);
            Console.WriteLine("Subtract({0},{1}) = {2}", value1, value2, result);

            // Call the Multiply service operation.
            value1 = 9.00D;
            value2 = 81.25D;
            result = client.Multiply(value1, value2);
            Console.WriteLine("Multiply({0},{1}) = {2}", value1, value2, result);

            // Call the Divide service operation.
            value1 = 22.00D;
            value2 = 7.00D;
            result = client.Divide(value1, value2);
            Console.WriteLine("Divide({0},{1}) = {2}", value1, value2, result);

            //Closing the client gracefully closes the connection and cleans up resources
            client.Close();

            Console.WriteLine();
            Console.WriteLine("Press <ENTER> to terminate client.");
            Console.ReadLine();
        }
    }

    // WARNING: This code is only needed for test certificates such as those created by makecert. It is 
    // not recommended for production code.
    class PermissiveCertificatePolicy
    {
        string subjectName;
        static PermissiveCertificatePolicy currentPolicy;
        PermissiveCertificatePolicy(string subjectName)
        {
            this.subjectName = subjectName;
            ServicePointManager.ServerCertificateValidationCallback +=
                new System.Net.Security.RemoteCertificateValidationCallback(RemoteCertValidate);
        }

        public static void Enact(string subjectName)
        {
            currentPolicy = new PermissiveCertificatePolicy(subjectName);
        }

        bool RemoteCertValidate(object sender, X509Certificate cert, X509Chain chain, System.Net.Security.SslPolicyErrors error)
        {
            if (cert.Subject == subjectName)
            {
                return true;
            }

            return false;
        }
    }
}

13) 執行該客戶端程式,執行成功可以獲得WCF方法的返回值。

原始碼:  http://download.csdn.net/detail/eric_k1m/6481211

訊息安全示例(Message)DEMO

1) 新建一個WCF Service Application,新建WCF服務介面類:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace Video14.Demo2.Windows
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "ICalculatorService" in both code and config file together.
    [ServiceContract(Namespace = "http://Video14.Demo2.Windows")]
    public interface ICalculatorService
    {
        [OperationContract]
        string GetCallerIdentity();
        [OperationContract]
        double Add(double n1, double n2);
        [OperationContract]
        double Subtract(double n1, double n2);
        [OperationContract]
        double Multiply(double n1, double n2);
        [OperationContract]
        double Divide(double n1, double n2);
    }
}

2) 實現該WCF介面:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace Video14.Demo2.Windows
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "CalculatorService" in code, svc and config file together.
    public class CalculatorService : ICalculatorService
    {
        public double Add(double n1, double n2)
        {
            double result = n1 + n2;
            return result;
        }

        public double Subtract(double n1, double n2)
        {
            double result = n1 - n2;
            return result;
        }

        public double Multiply(double n1, double n2)
        {
            double result = n1 * n2;
            return result;
        }

        public double Divide(double n1, double n2)
        {
            double result = n1 / n2;
            return result;
        }

        public string GetCallerIdentity()
        {
            //獲取當前呼叫服務的客戶端windows使用者名稱
            return OperationContext.Current.ServiceSecurityContext.WindowsIdentity.Name;
        }
    }
}

3) 配置檔案:
<?xml version="1.0"?>
<configuration>

  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>

    <services>
      <service name="Video14.Demo2.Windows.CalculatorService" behaviorConfiguration="CalculatorServiceBehavior">
        <endpoint address="" binding="wsHttpBinding" bindingConfiguration="Binding1" contract="Video14.Demo2.Windows.ICalculatorService"/>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
      </service>
    </services>

    <bindings>
      <wsHttpBinding>
        <binding name="Binding1">
          <!--SecurityMode設定為Message訊息安全模式,並且clientCredentialType客戶端身份憑據為windows客戶端身份驗證-->
          <security mode="Message">
            <message clientCredentialType="Windows"/>
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    
    <behaviors>
      <serviceBehaviors>
        <behavior name="CalculatorServiceBehavior">
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
  
</configuration>

4) 部署到IIS上後,新增Client客戶端程式測試:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Client
{
    class Program
    {
        static void Main(string[] args)
        {
            ServiceReference1.CalculatorServiceClient client = new ServiceReference1.CalculatorServiceClient();

            // Call the GetCallerIdentity service operation
            Console.WriteLine("Caller identity is: {0}", client.GetCallerIdentity());

            // Call the Add service operation.
            double value1 = 100.00D;
            double value2 = 15.99D;
            double result = client.Add(value1, value2);
            Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result);

            // Call the Subtract service operation.
            value1 = 145.00D;
            value2 = 76.54D;
            result = client.Subtract(value1, value2);
            Console.WriteLine("Subtract({0},{1}) = {2}", value1, value2, result);

            // Call the Multiply service operation.
            value1 = 9.00D;
            value2 = 81.25D;
            result = client.Multiply(value1, value2);
            Console.WriteLine("Multiply({0},{1}) = {2}", value1, value2, result);

            // Call the Divide service operation.
            value1 = 22.00D;
            value2 = 7.00D;
            result = client.Divide(value1, value2);
            Console.WriteLine("Divide({0},{1}) = {2}", value1, value2, result);

            //Closing the client gracefully closes the connection and cleans up resources
            client.Close();

            Console.WriteLine();
            Console.WriteLine("Press <ENTER> to terminate client.");
            Console.ReadLine();
        }
    }
}
這裡獲取到了客戶端呼叫的windows使用者名稱後,就可以後續的在伺服器端進行校驗以及授權的操作了。
原始碼: http://download.csdn.net/detail/eric_k1m/6481677

訊息安全示例(Message)DEMO 伺服器端有證書的認證

伺服器端有一個證書的認證,伺服器必須提供證書來保證這個服務是一個有效的服務。這個客戶端叫做匿名客戶端。 1) WCF服務介面:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace Video14.Demo3.Anonymous
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "ICalculatorService" in both code and config file together.
    [ServiceContract(Namespace = "http://Video14.Demo3.Anonymous")]
    public interface ICalculatorService
    {
        [OperationContract]
        bool IsCallerAnonymous();
        [OperationContract]
        double Add(double n1, double n2);
        [OperationContract]
        double Subtract(double n1, double n2);
        [OperationContract]
        double Multiply(double n1, double n2);
        [OperationContract]
        double Divide(double n1, double n2);
    }
}

2) WCF實現類:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace Video14.Demo3.Anonymous
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "CalculatorService" in code, svc and config file together.
    public class CalculatorService : ICalculatorService
    {
        public bool IsCallerAnonymous()
        {
            // ServiceSecurityContext.IsAnonymous returns true if the caller is not authenticated
            //當前安全上下文的屬性來判斷當前客戶端的請求是否是經過身份證書驗證的,如果沒有就是匿名的。
            return ServiceSecurityContext.Current.IsAnonymous;            
        }

        public double Add(double n1, double n2)
        {
            double result = n1 + n2;
            return result;
        }

        public double Subtract(double n1, double n2)
        {
            double result = n1 - n2;
            return result;
        }

        public double Multiply(double n1, double n2)
        {
            double result = n1 * n2;
            return result;
        }

        public double Divide(double n1, double n2)
        {
            double result = n1 / n2;
            return result;
        }
    }
}

3) 配置檔案:
<?xml version="1.0"?>
<configuration>

  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>

    <services>
      <service name="Video14.Demo3.Anonymous.CalculatorService" behaviorConfiguration="CalculatorServiceBehavior">
        <endpoint address="" binding="wsHttpBinding" bindingConfiguration="Binding1" contract="Video14.Demo3.Anonymous.ICalculatorService"/>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
      </service>
    </services>

    <bindings>
      <wsHttpBinding>
        <binding name="Binding1">
          <!--安全模式是訊息安全模式,並且客戶端證書憑據型別為None-->
          <security mode="Message">
            <message clientCredentialType="None"/>
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    
    <behaviors>
      <serviceBehaviors>
        <behavior name="CalculatorServiceBehavior">
          <!--指定伺服器端的證書憑據,也就是伺服器端的身份驗證-->
          <serviceCredentials>
            <!--這個服務的憑據是證書,使用證書的憑據來指定該服務進行訊息安全的保障。
            指定證書的證書憑據型別;findValue找到值,storeLocation儲存到哪個節點下,storeName就是Personal下面的證書,x509FindType的型別.
            該證書需要使用證書工具來生成才行,否則我們這個伺服器上是沒有這個證書的。-->
            <serviceCertificate findValue="localhost" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName"/>
          </serviceCredentials>
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
  
</configuration>

4)編譯部署到IIS上。部署完畢後,用IE訪問該服務—— http://localhost/Anonymous/CalculatorService.svc      會提示有錯誤:

Cannot find the X.509 certificate using the following search criteria: StoreName 'My', StoreLocation 'LocalMachine', FindType 'FindBySubjectName', FindValue 'localhost'.

這是由於沒有證書導致的。 5) 我們來生成證書,使用VS2010的makecert.exe 命令列程式來生成,我們先開啟VS Command Prompt(使用管理員身份開啟):
具體使用請參考: http://msdn.microsoft.com/zh-cn/library/e78byta0.aspx 使用此工具生成的只是臨時的工具,在開發測試中使用,最終證實部署的證書需要向第三方的頒發機構去購買。 然後再該工具裡輸入: C:\Windows\system32>makecert.exe -sr LocalMachine -ss MY -a sha1 -n CN=localhost -sky exchange -pe

引數說明:

  -sr CurrentUser:指定主題的證書儲存位置。Location 可以是 currentuser(預設值)或localmachine

  -ss MyTestContainer:指定主題的證書儲存名稱,輸出證書即儲存在那裡。

  -n CN=TestCert:指定主題的證書名稱。此名稱必須符合 X.500 標準。最簡單的方法是在雙引號中指定此名稱,並加上字首 CN=;例如,"CN=myName"

  -sky exchange:指定頒發者的金鑰型別,必須是 signatureexchange 或一個表示提供程式型別的整數。預設情況下,可傳入 1 表示交換金鑰,傳入 2 表示簽名金鑰。

  -pe:將所生成的私鑰標記為可匯出。這樣可將私鑰包括在證書中。

6) 經過以上步驟就生成了證書,那我們在哪裡確認檢視生成的證書呢:

  生成的金鑰檔案被儲存在了我們指定的MyTestContainer中,但到哪去檢視我們的證書呢?Windows沒有給我們準備好直接的管理證書的入口,但我們可以在MMC控制檯自行新增。

  1. 開始?執行? MMC,開啟一個空的MMC控制檯。
  2. 在控制檯選單,檔案?新增/刪除管理單元?新增按鈕?"證書?新增?"我的使用者賬戶?關閉?確定
  3. 在控制檯選單,檔案?新增/刪除管理單元?新增按鈕?"證書?新增?"計算機賬戶?關閉?確定

生成的證書在 證書(本地計算機)(也就是引數裡的localmachine引數)/個人(引數裡的my引數)/證書 裡的 “localhost”證書,雙擊可以檢視生成的證書:

7)我們還不能直接使用該證書,這是我們臨時生成的,該證書還沒有被信任。我們還需要把這個證書放到當前使用者的信任節點裡,才可以被我們的程式所信任。這時候就需要使用證書管理工具“cergmgr.exe”:

樣式為:

certmgr [/add | /del | /put] [options]
[/s[/r registryLocation]] [sourceStorename]
[/s[/r registryLocation]] [destinationStorename]

具體引數:

引數

引數

描述

sourceStorename

包含現有證書、CTL 或 要新增、刪除、儲存或顯示的CRL的證書儲存區。 這可以是一個儲存檔案,也可以是一個系統儲存。

destinationStorename

輸出證書儲存區或檔案。

選項

描述

/add

將證書、CTL 和 CRL 新增到證書儲存區中。

/all

當與 /add 一起使用時新增所有項。 當與 /del 一起使用時刪除所有項。 不帶 /add 或 /del 選項使用時顯示所有項。 /all 選項不能與 /put 一起使用。

/c

當與 /add 一起使用時新增證書。 當與 /del 一起使用時刪除證書。 當與 /put 一起使用時儲存證書。 不帶 /add/del 或 /put 選項使用時顯示證書。

/CRL

當與 /add 一起使用時新增 CRL。 當與 /del 一起使用時刪除 CRL。 使用 /put 後,儲存 CRL。 不帶 /add/del 或 /put 選項使用時顯示 CRL。

/CTL

當與 /add 一起使用時新增 CTL。 當與 /del 一起使用時刪除 CTL。 使用 /put 後,儲存 CTL。 不帶 /add/del 或 /put 選項使用時顯示 CTL。

/del

從證書儲存區中刪除證書、CTL 和 CRL。

/e encodingType

指定證書編碼型別。 預設值為 X509_ASN_ENCODING

/f dwFlags

指定儲存區開啟標誌。 這是傳遞到 CertOpenStore 的 dwFlags 引數。 預設值為 CERT_SYSTEM_STORE_CURRENT_USER。 僅當使用 /y 選項時才考慮此選項。

/h[elp]

顯示該工具的命令語法和選項。

/n nam

指定要新增、刪除或儲存的證書的公共名。 此選項只能用於證書,不能用於 CTL 或 CRL。

/put

將證書儲存區中的 X.509 證書、CTL 或 CRL 儲存到檔案。 檔案以 X.509 格式儲存。 /7 選項可與 /put 選項一起使用以 PKCS #7 格式儲存檔案。/put 選項後面必須有 /c/CTL 或 /CRL /all 選項不能與 /put 一起使用。

/r 位置

標識系統儲存區的登錄檔位置。 僅當指定 /s 選項時才考慮此選項。 location 必須是以下項之一:

  • currentUser 指示證書儲存區在 HKEY_CURRENT_USER 鍵下。 這是預設設定。

  • localMachine 指示證書儲存區在 HKEY_LOCAL_MACHINE 鍵下。

/s

指示證書儲存區是系統儲存區。 如果未指定此選項,則會將儲存區視為 StoreFile

/sha1 sha1Hash

指定要新增、刪除或儲存的證書、CTL 或 CRL 的 SHA1 雜湊。

/v

指定詳細模式;顯示有關證書、CTL 和 CRL 的詳細資訊。 此選項不能與 /add/del 或 /put 選項一起使用。

/y provider

指定儲存提供程式名稱。

/7

將目標儲存區儲存為 PKCS #7 物件。

/?

顯示該工具的命令語法和選項。

我們這裡輸入: C:\Windows\system32>certmgr.exe -add -r LocalMachine -s My -c -n localhost -r CurrentUser -s TrustedPeople 把生成的證書拷貝到“證書 當前使用者”裡的可信使用者裡:
可以在MMC裡看到已經被拷貝進來:
8) 這時候我們在IE裡再次開啟WCF服務的時候會出現:

Server Error in '/Anonymous' Application.

金鑰集不存在。

的錯誤資訊,這是由於

在證書受信任的前提下,主要是開啟瀏覽許可權

解決辦法:

Win Xp /2003:在C:\Documents and Settings\All Users\Application Data\Microsoft\Crypto\RSA下為資料夾 MachineKeys 新增Everyone 並賦予瀏覽許可權

Win 7 /Vista /2008: 在C:\ProgramData\Microsoft\Crypto\RSA 目錄下為資料夾 MachineKeys 新增Everyone 並賦予瀏覽許可權

即可解決這個錯誤!


經過以上設定後,再次用IE開啟該服務即可正常打開了。 9) WCF服務設定完畢後,新增一個客戶端專案來測試一下,需要在客戶端專案上新增WCF的引用,客戶端Main方法如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Client.ServiceReference1;

namespace Client
{
    class Program
    {
        static void Main(string[] args)
        {
            // Create a client with given client endpoint configuration
            CalculatorServiceClient client = new CalculatorServiceClient();

            // Call the GetCallerIdentity operation
            Console.WriteLine("IsCallerAnonymous returned: {0}", client.IsCallerAnonymous());

            // Call the Add service operation.
            double value1 = 100.00D;
            double value2 = 15.99D;
            double result = client.Add(value1, value2);
            Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result);

            // Call the Subtract service operation.
            value1 = 145.00D;
            value2 = 76.54D;
            result = client.Subtract(value1, value2);
            Console.WriteLine("Subtract({0},{1}) = {2}", value1, value2, result);

            // Call the Multiply service operation.
            value1 = 9.00D;
            value2 = 81.25D;
            result = client.Multiply(value1, value2);
            Console.WriteLine("Multiply({0},{1}) = {2}", value1, value2, result);

            // Call the Divide service operation.
            value1 = 22.00D;
            value2 = 7.00D;
            result = client.Divide(value1, value2);
            Console.WriteLine("Divide({0},{1}) = {2}", value1, value2, result);

            //Closing the client gracefully closes the connection and cleans up resources
            client.Close();

            Console.WriteLine();
            Console.WriteLine("Press <ENTER> to terminate client.");
            Console.ReadLine();
        }
    }
}

10) 修改自動生成的app.config為:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <client>
      <endpoint name=""
                address="http://localhost/Anonymous/CalculatorService.svc"
                binding="wsHttpBinding"
                behaviorConfiguration="ClientCredentialsBehavior"
                bindingConfiguration="Binding1"
                contract="ServiceReference1.ICalculatorService" />
    </client>

    <bindings>
      <wsHttpBinding>
        <!-- 
        This configuration defines the security mode as Message and 
        the clientCredentialType as None.
        -->
        <binding name="Binding1">
          <security mode = "Message">
            <message clientCredentialType="None"/>
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>

    <behaviors>
      <endpointBehaviors>
        <behavior name="ClientCredentialsBehavior">
          <clientCredentials>
            <serviceCertificate>
              <!-- 
            Setting the certificateValidationMode to PeerOrChainTrust means that if the certificate 
            is in the user's Trusted People store, then it will be trusted without performing a
            validation of the certificate's issuer chain. This setting is used here for convenience so that the 
            sample can be run without having to have certificates issued by a certificate authority (CA).
            This setting is less secure than the default, ChainTrust. The security implications of this 
            setting should be carefully considered before using PeerOrChainTrust in prod