【问题标题】:WCF: Attempting to set up Two-way mutual SSL Authentication with self-signed certificates and 'PeerTrust'WCF:尝试使用自签名证书和“PeerTrust”设置双向相互 SSL 身份验证
【发布时间】:2012-08-05 02:55:07
【问题描述】:

我正在尝试在同一台机器上使用相互 SSL 身份验证设置 WCF 服务和客户端。

我有:

  • 为服务器和客户端创建证书并将它们放入 LocalMachine 证书存储区。服务器和客户端私钥在“个人”存储中,而公钥在“受信任的人”存储中。

  • 我已经配置了一个 WCF 服务和客户端,每个服务和客户端都从商店中指定了他们自己的证书引用,并且还设置了要使用

  • 验证的其他方证书引用

<authentication certificateValidationMode="PeerTrust" trustedStoreLocation="LocalMachine" />

注意:服务器证书颁发给机器名,客户端调用的服务url为'https:\tokenservice\tokenservice.svc

使用此配置,我希望客户端安全地连接到服务,任一端解析来自“受信任的人”存储的证书,但我收到以下错误,表明证书验证失败:

[AuthenticationException:根据验证程序,远程证书无效。]

所以这并没有像我预期的那样工作。任何人都可以指出任何错误吗?还是我的预期不正确?

WCF 配置如下:

    <?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="CertificateForClient">
          <security mode="Transport">
            <transport clientCredentialType="Certificate"/>
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="CertificateBehaviour">
          <!-- 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="true"/>
          <serviceCredentials>
            <clientCertificate>
              <authentication certificateValidationMode="PeerTrust"
                              trustedStoreLocation="LocalMachine" />
            </clientCertificate>
            <serviceCertificate findValue="CN='ServerCertificate which is machine name'"
            storeLocation="LocalMachine" storeName="My"
            x509FindType="FindBySubjectDistinguishedName" />
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service name="TokenService.TokenService" behaviorConfiguration="CertificateBehaviour">
        <endpoint contract="TokenService.ITokenService"
            binding="wsHttpBinding" />
        <endpoint contract="IMetadataExchange"
            binding="mexHttpBinding" address="mex">
        </endpoint>
        <host>
          <baseAddresses>
            <add baseAddress="https://tokenservice" />
          </baseAddresses>
        </host>
      </service>
    </services>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>

</configuration>

客户端配置:

  <system.serviceModel>
<behaviors>
  <endpointBehaviors>
    <behavior name="ClientBehaviour">
      <clientCredentials>
        <clientCertificate storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectDistinguishedName" findValue="CN=TokenClient"/>
        <serviceCertificate>
          <authentication certificateValidationMode="PeerTrust" trustedStoreLocation="LocalMachine"></authentication>
        </serviceCertificate>
      </clientCredentials>
    </behavior>
  </endpointBehaviors>
</behaviors>
<bindings>
  <wsHttpBinding>
    <binding name="ClientBinding">
      <security mode="Transport">
        <transport clientCredentialType="Certificate"/>
      </security>
    </binding>
  </wsHttpBinding>
</bindings>
<client>
  <endpoint address="https://tokenservice/TokenService.svc"
    behaviorConfiguration="ClientBehaviour"
    binding="wsHttpBinding" bindingConfiguration="ClientBinding"
    contract="TokenService.ITokenService" name="ToolClient">
    <identity>
      <dns value="MachineName" />
    </identity>
  </endpoint>
</client>

【问题讨论】:

  • 这个运气好吗?我很想看看你是怎么做到的。

标签: wcf ssl certificate


【解决方案1】:

服务的基本 URL 应该是服务器证书名称。

例如:

如果我的服务器证书名称是 test.cer,那么我的服务 URL 应该 是https://test/MyService/MyService.svc

这是您设置服务的方式吗?

【讨论】:

    【解决方案2】:

    当使用双向 SSL 在传输层进行身份验证时,PeerTrust 和 ChainTrust 提供的内置授权不起作用。

    老实说,PeerTrust 在许多情况下并不能控制所需的授权过程。

    解决此问题的一种非常常见的方法是插入自定义 ServiceAuthorizationManager 并覆盖其 OnAccess 方法。

    <behavior name="ServerCertificateBehavior">
      <serviceCredentials>
        <serviceCertificate ....  />
      </serviceCredentials>
      <serviceAuthorization serviceAuthorizationManagerType="MyCustomCertificateAuthorizationManager, MyWCFExtensions.Security" />
    </behavior>
    

    ServiceAuthorizationManager 可以在几行代码中完成,用于非常静态的简单证书检查,或者根据需要进行更复杂的检查。

    这个简单的概念验证希望可以帮助您入门:

    public class MyCustomCertificateAuthorizationManager : ServiceAuthorizationManager
    {
    
        public override bool CheckAccess(OperationContext operationContext, ref Message message)
        {
            base.CheckAccess(operationContext, ref message);
            string action = operationContext.IncomingMessageHeaders.Action;
    
            List<string> approvedActions = new List<string> 
            { 
                "http://kramerica.lan/namespace/MySpecialMethod",
                "http://kramerica.lan/namespace/AnotherMethod"
            };
    
            List<string> approvedThumbprints = new List<string> 
            { 
                "‎1aaffe105b31b79b66c31de3389203d42351683a",
                "‎f1bcfbc6383bcbfa736473bcaf109987bbc2121a"
            };
    
    
            //One way is do the authorization based on the action if the endpoint is used for more than one operation with different ACL needs
            if (approvedActions.Contains(action))
            {
                foreach (ClaimSet claimSet in OperationContext.Current.ServiceSecurityContext.AuthorizationContext.ClaimSets)
                {
                    X509CertificateClaimSet certificateClaimSet = claimSet as X509CertificateClaimSet;
                    if (certificateClaimSet != null)
                    {
                        //Get the actual certificate used by the client
                        X509Certificate2 certificate = certificateClaimSet.X509Certificate;
    
                        //Here a real validation of certificate issuer chain etc. could be made
                        if (certificate != null)
                        {
                            //This proof-of-concept does authorization based on a static list of thumbprints but about anything os possible here.
                            //One could easily check if this certificate
                            //is present in the TrustedPeople store or some database backend
                            if (approvedThumbprints.Contains(certificate.Thumbprint))
                                return true;
                        }
                    }
                }
            }
            return false;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2017-03-31
      • 1970-01-01
      • 1970-01-01
      • 2020-01-13
      • 2014-10-08
      • 1970-01-01
      • 2016-02-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多