2014-09-04 50 views
4

在我的WCF自託管WebService使用相互證書來驗證客戶端,我設置CertificateValidationMode = PeerTrust,但它似乎被忽略,因爲我仍然可以執行某些客戶端的方法,至此我已刪除相應的證書TrustedPeople服務器商店。Wcf證書作爲ClientCredentials

赫雷什宿主例如:

static void Main() 
    { 
     var httpsUri = new Uri("https://192.168.0.57:xxx/HelloServer"); 
     var binding = new WSHttpBinding 
     { 
      Security = 
      { 
       Mode = SecurityMode.Transport, 
       Transport = {ClientCredentialType = HttpClientCredentialType.Certificate} 
     };   

     var host = new ServiceHost(typeof(HelloWorld), httpsUri); 

     //This line is not working 
     host.Credentials.ClientCertificate.Authentication.CertificateValidationMode =X509CertificateValidationMode.PeerTrust; 

     host.AddServiceEndpoint(typeof(IHelloWorld), binding, string.Empty, httpsUri); 

     host.Credentials.ServiceCertificate.SetCertificate(
      StoreLocation.LocalMachine, 
      StoreName.My, 
      X509FindType.FindBySubjectName, 
      "server.com"); 

     // Open the service. 
     host.Open(); 
     Console.WriteLine("Listening on {0}...", httpsUri); 
     Console.ReadLine(); 

     // Close the service. 
     host.Close(); 
    } 

的客戶端應用程序:

static void Main(string[] args) 
    { 
     try 
     { 
      var c = new HelloWorld.HelloWorldClient(); 
      ServicePointManager.ServerCertificateValidationCallback = (sender, cert, chain, error) => true; 
      c.ClientCredentials.ClientCertificate.SetCertificate(
       StoreLocation.LocalMachine, 
       StoreName.My, 
       X509FindType.FindBySubjectName, 
       "client.com"); 

      Console.WriteLine(c.GetIp()); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine(ex.Message); 
     } 
     Console.ReadKey();   
    } 

我生成server.comclient.com根CA證書。此RootCA證書安裝在客戶端和服務器的受信任根存儲中。 現在的問題是,我不應該執行GetIp()方法,如果我的client.com證書不在TrustedPeople存儲的服務器,對不對?但即時執行它沒有任何問題。

問題是,在這種情況下,如何驗證客戶端證書將其公鑰置於服務器的TrustedPeople上?

ps:在this MSDN運輸安全與客戶端證書的文章,theres報價爲The server’s certificate must be trusted by the client and the client’s certificate must be trusted by the server.但我可以從客戶端執行webmethods,即使客戶端證書沒有在服務器TrustedPeople商店。

回答

2

我的建議是使用custom validation。通過這種方式,您可以設置一些斷點並觀察驗證過程,並根據整個驗證過程中可用的數據查看您可以提出哪些驗證選項。

首先確保您的綁定需要證書消息客戶端證書。如果您只使用運輸證書,則我的測試中的客戶端無法驗證。只有這一點可以解決你的問題。

binding.Security.Mode = SecurityMode.TransportWithMessageCredential; 
binding.Security.Message.ClientCredentialType = 
     MessageCredentialType.Certificate; 

要設置自定義驗證器,請遵循其餘步驟。

替換:

host.Credentials.ClientCertificate.Authentication.CertificateValidationMode 
     =X509CertificateValidationMode.PeerTrust; 

有了:

host.Credentials.ClientCertificate.Authentication.CertificateValidationMode 
     =X509CertificateValidationMode.Custom; 

host.Credentials.ClientCertificate.Authentication.CustomCertificateValidator = 
     new IssuerNameCertValidator("CN=client.com"); 

然後添加它來創建自定義驗證,並根據需要調整(這一個驗證基於對發行人):

public class IssuerNameCertValidator : X509CertificateValidator 
{ 
    string allowedIssuerName; 

    public IssuerNameCertValidator(string allowedIssuerName) 
    { 
     if (allowedIssuerName == null) 
     { 
      throw new ArgumentNullException("allowedIssuerName"); 
     } 

     this.allowedIssuerName = allowedIssuerName; 
    } 

    public override void Validate(X509Certificate2 certificate) 
    { 
     // Check that there is a certificate. 
     if (certificate == null) 
     { 
      throw new ArgumentNullException("certificate"); 
     } 

     // Check that the certificate issuer matches the configured issuer. 
     if (allowedIssuerName != certificate.IssuerName.Name) 
     { 
      throw new SecurityTokenValidationException 
       ("Certificate was not issued by a trusted issuer"); 
     } 
    } 
}