{error: (403) Forbidden."} WCF basicHttpBinding with Transport and Certificate Credential

{error: (403) Forbidden."} WCF basicHttpBinding with Transport and Certificate Credential

我收到错误消息“{"The remote server returned an error: (403) Forbidden."} 客户端身份验证方案 'Anonymous' 禁止 HTTP 请求。”将 basicHttpBinding 与传输安全和证书凭据一起使用时。我的服务在亚马逊 ec2 实例中,我的客户端应用程序通过互联网远程连接到它。如果我的传输凭据在服务的 web.config 和客户端的 app.config 中都设置为 "None",我就可以连接到 wcf 服务。我的服务证书就像 "www.example.com" 安装在 amazon ec2 "local machine store" 和 "Personal Folder" 上。我的客户端应用程序证书只是一个自签名证书,我将其安装到其 "local machine and Personal Folder" 以及我的 wcf 服务所在的 amazon ec2 实例中的 "Trusted People store"。我还为我的 IIS 站点绑定设置了 "https",我可以通过类似“https://www.example.com

的方式访问该站点

下面是 web.config、app.config 和我在客户端应用程序上的代码。

服务Web.config:

<?xml version="1.0"?>
<configuration>

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

   <bindings>
      <basicHttpBinding>
        <binding name="basicHttpBinding_Config" >
          <security mode="Transport">
            <transport clientCredentialType="Certificate"/>
          </security>
        </binding>        
      </basicHttpBinding>
  </bindings>

    <services>    
      <service name="MyProject.MyService">
        <endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicHttpBinding_Config"
          contract="MyService"  />
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
      </service>
    </services>

    <behaviors>
      <serviceBehaviors>
        <behavior>
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>          
          <serviceCredentials>
            <clientCertificate>
              <authentication certificateValidationMode="PeerOrChainTrust" trustedStoreLocation="LocalMachine"/>
            </clientCertificate>
            <serviceCertificate findValue="www.example.com" x509FindType="FindBySubjectName" storeLocation="LocalMachine" storeName="My" />
          </serviceCredentials>          
        </behavior>
      </serviceBehaviors>
    </behaviors>

    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>

</configuration>

客户app.config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>                   

      <bindings>
        <basicHttpBinding>
          <binding name="basicHttpBinding_Config" >
            <security mode="Transport">
              <transport clientCredentialType="Certificate"/>
            </security>
          </binding>
        </basicHttpBinding>
      </bindings>
      <client>
        <endpoint address="https://www.example.com/sub/Service1.svc"
          binding="basicHttpBinding" bindingConfiguration="basicHttpBinding_Config"
          contract="ServiceReference1.MyService" name="BasicHttpBinding_MyService" />
      </client>

      <behaviors>
        <endpointBehaviors>
          <behavior>
            <clientCredentials>
              <clientCertificate findValue="clientKey"
                                 storeLocation="LocalMachine"
                                 storeName="My"
                                 x509FindType="FindBySubjectName" />
            </clientCredentials>

          </behavior>
        </endpointBehaviors>
      </behaviors>

    </system.serviceModel>
</configuration>

客户端应用控制台代码:

static void Main(string[] args)
        {
            System.Net.ServicePointManager.ServerCertificateValidationCallback += delegate { return true; }; 

            ServiceReference1.MyServiceClient client = new ServiceReference1.MyServiceClient();
            string[] a = client.GetMethods(ref mh);
            foreach (string s in a)
            {
                Console.WriteLine(s);
            }
            Console.ReadKey();

        }

下面的诊断跟踪 returns:

<E2ETraceEvent xmlns="http://schemas.microsoft.com/2004/06/E2ETraceEvent">
<System xmlns="http://schemas.microsoft.com/2004/06/windows/eventlog/system">
<EventID>131077</EventID>
<Type>3</Type>
<SubType Name="Critical">0</SubType>
<Level>1</Level>
<TimeCreated SystemTime="2018-11-16T21:50:58.8220239Z" />
<Source Name="System.ServiceModel" />
<Correlation ActivityID="{00000000-0000-0000-0000-000000000000}" />
<Execution ProcessName="ConsoleApplication1" ProcessID="22220" ThreadID="1" />
<Channel />
<Computer>DESKTOP-RPNI11M</Computer>
</System>
<ApplicationData>
<TraceData>
<DataItem>
<TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Critical">
<TraceIdentifier>UnhandledException</TraceIdentifier>
<Description>Unhandled exception</Description>
<AppDomain>ConsoleApplication1.exe</AppDomain>
<Exception>
<ExceptionType>System.ServiceModel.Security.MessageSecurityException, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType>
<Message>The HTTP request was forbidden with client authentication scheme 'Anonymous'.</Message>
<StackTrace>
Server stack trace:
at System.ServiceModel.Channels.HttpChannelUtilities.ValidateAuthentication(HttpWebRequest request, HttpWebResponse response, WebException responseException, HttpChannelFactory`1 factory)
at System.ServiceModel.Channels.HttpChannelUtilities.ValidateRequestReplyResponse(HttpWebRequest request, HttpWebResponse response, HttpChannelFactory`1 factory, WebException responseException, ChannelBinding channelBinding)
at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
Exception rethrown at [0]:
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData&amp; msgData, Int32 type)
at ConsoleApplication1.ServiceReference1.IOD_V416.GetMethods(GetMethodsRequest request)
at ConsoleApplication1.ServiceReference1.OD_V416Client.ConsoleApplication1.ServiceReference1.IOD_V416.GetMethods(GetMethodsRequest request) in D:\Workfolder\Projects2\MyProject\WCF_App\MyService - Copy (3)\ConsoleApplication1\Service References\ServiceReference1\Reference.cs:line 72017
at ConsoleApplication1.ServiceReference1.OD_V416Client.GetMethods(MultiSpeakMsgHeader&amp; MultiSpeakMsgHeader) in D:\Workfolder\Projects2\MyProject\WCF_App\MyService - Copy (3)\ConsoleApplication1\Service References\ServiceReference1\Reference.cs:line 72023
at ConsoleApplication1.Program.Main(String[] args) in D:\Workfolder\Projects2\MyProject\WCF_App\MyService - Copy (3)\ConsoleApplication1\Program.cs:line 43
</StackTrace>
<ExceptionString>System.ServiceModel.Security.MessageSecurityException: The HTTP request was forbidden with client authentication scheme 'Anonymous'. ---&gt; System.Net.WebException: The remote server returned an error: (403) Forbidden.
   at System.Net.HttpWebRequest.GetResponse()
   at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
   --- End of inner exception stack trace ---

Server stack trace: 
   at System.ServiceModel.Channels.HttpChannelUtilities.ValidateAuthentication(HttpWebRequest request, HttpWebResponse response, WebException responseException, HttpChannelFactory`1 factory)
   at System.ServiceModel.Channels.HttpChannelUtilities.ValidateRequestReplyResponse(HttpWebRequest request, HttpWebResponse response, HttpChannelFactory`1 factory, WebException responseException, ChannelBinding channelBinding)
   at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
   at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
   at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]: 
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData&amp; msgData, Int32 type)
   at ConsoleApplication1.ServiceReference1.IOD_V416.GetMethods(GetMethodsRequest request)
   at ConsoleApplication1.ServiceReference1.OD_V416Client.ConsoleApplication1.ServiceReference1.IOD_V416.GetMethods(GetMethodsRequest request) in D:\Workfolder\Projects2\MyProject\WCF_App\MyService - Copy (3)\ConsoleApplication1\Service References\ServiceReference1\Reference.cs:line 72017
   at ConsoleApplication1.ServiceReference1.OD_V416Client.GetMethods(MultiSpeakMsgHeader&amp; MultiSpeakMsgHeader) in D:\Workfolder\Projects2\MyProject\WCF_App\MyService - Copy (3)\ConsoleApplication1\Service References\ServiceReference1\Reference.cs:line 72023
   at ConsoleApplication1.Program.Main(String[] args) in D:\Workfolder\Projects2\MyProject\WCF_App\MyService - Copy (3)\ConsoleApplication1\Program.cs:line 43</ExceptionString>
<InnerException>
<ExceptionType>System.Net.WebException, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType>
<Message>The remote server returned an error: (403) Forbidden.</Message>
<StackTrace>
at System.Net.HttpWebRequest.GetResponse()
at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
</StackTrace>
<ExceptionString>System.Net.WebException: The remote server returned an error: (403) Forbidden.
   at System.Net.HttpWebRequest.GetResponse()
   at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)</ExceptionString>
</InnerException>
</Exception>
</TraceRecord>
</DataItem>
</TraceData>
</ApplicationData>
</E2ETraceEvent>

我确实查看了其他类似问题,但 none 已经解决了,我一直在寻找正确的解决方案,感谢社区提供的任何帮助或建议。

编辑:

使用 sha2 证书可能更好:

makecert -len 2048 -r -a sha256 -sv private.pvk -n CN=yoursubjectname cert.cer
pvk2pfx -spc cert.cer -pvk private.pvk -pfx out.pfx

在主机上安装私人证书(.pfx),在IIS应用程序中设置,并在客户端(.cer)上安装public证书,您必须同时安装个人和受信任的人商店。

编辑:我认为您还需要在主机和客户端配置中为您的行为命名,并将该行为分配给您的端点。

主持人:

<behavior name="serviceBahavior"> 
<service name="MyProject.MyService" behaviorConfiguration="serviceBahavior">

客户:

<behavior name="clientBahavior">
<endpoint address="https://www.example.com/sub/Service1.svc"
          binding="basicHttpBinding" bindingConfiguration="basicHttpBinding_Config"
          contract="ServiceReference1.MyService" name="BasicHttpBinding_MyService" behaviorConfiguration="clientBahavior" />

我认为既然您使用的是 <security mode="Transport">,您需要将 mex 设为 HTTPS:

 <endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />

同时在您的行为中设置 serviceMetadata

来自: <serviceMetadata httpGetEnabled="true"/>

<serviceMetadata httpsGetEnabled="true"/>

此外,请确保客户端配置中的传输与主机配置相匹配:

<transport clientCredentialType="Certificate"/>

我发现以下解决方案适用于我遇到的这个错误。

首先我创建了一个证书如下:

makecert -n "CN=MyRootSigningKey" -r -sv MyRootSigningKey.pvk MyRootSigningKey.cer

其次,我将其视为我的根密钥,并使用 mmc 将其安装在证书存储 "Trusted Root Certification Authorities" 下的我的 AWS 服务中。

第三,我使用根密钥 "MyRootSigningKey" 创建了一个自签名证书,如下所示:

makecert -sk MySignedKeyName -iv MyRootSigningKey.pvk -n "CN=MySignedKey" -ic MyRootSigningKey.cer -sr localmachine -ss my -sky exchange -pe

最后,我在我的客户端应用程序配置中引用了自签名证书 "MySignedKey",如下所示:

<client>        
        <endpoint address="https://www.example.com/sub/Service1.svc" behaviorConfiguration="clientBehavior"
          binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_MyService"
          contract="ServiceReference1.MyService"  />

      </client>

      <behaviors>
        <endpointBehaviors>
          <behavior name="clientBehavior">
            <clientCredentials>
              <clientCertificate findValue="MySignedKey"
                                 storeLocation="LocalMachine"
                                 storeName="My"
                                 x509FindType="FindBySubjectName" />
            </clientCredentials>

          </behavior>
        </endpointBehaviors>
      </behaviors>