【问题标题】:{error: (403) Forbidden."} WCF basicHttpBinding with Transport and Certificate Credential{error: (403) Forbidden."} 带有传输和证书凭据的 WCF basicHttpBinding
【发布时间】:2018-11-13 14:43:28
【问题描述】:

我收到错误“{“远程服务器返回错误:(403) Forbidden。”} HTTP 请求被客户端身份验证方案“匿名”禁止。”将 basicHttpBinding 与传输安全性和证书凭据一起使用时。我的服务在亚马逊 ec2 实例中,我的客户端应用程序通过互联网远程连接到它。如果我的传输凭据在服务的 web.config 和客户端的 app.config 中都设置为“无”,我就能够连接到 wcf 服务。我的服务证书就像“www.example.com”安装在 amazon ec2“本地机器存储”和“个人文件夹”上。我的客户端应用程序证书只是一个自签名证书,我安装到它的“本地机器和个人文件夹”以及我的 wcf 服务所在的亚马逊 ec2 实例中的“受信任的人存储”中。我还为我的 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();

        }

诊断跟踪返回如下:

<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>

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

【问题讨论】:

    标签: wcf basichttpbinding


    【解决方案1】:

    编辑:

    使用 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)上安装公共证书,您必须在个人和受信任的人员商店中安装。

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

    主持人:

    <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" />
    

    我认为由于您使用的是&lt;security mode="Transport"&gt;,因此您需要将 mex 设置为 HTTPS:

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

    还在你的行为中设置 serviceMetadata

    来自: &lt;serviceMetadata httpGetEnabled="true"/&gt;

    &lt;serviceMetadata httpsGetEnabled="true"/&gt;

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

    &lt;transport clientCredentialType="Certificate"/&gt;

    【讨论】:

    • 感谢您的回复 Popo,我将 mex 更改为 https,将 serviceMetadata 更改为 httpsGetEnabled,客户端配置中的 clientCredentialsType 也更改为 Certificate,但是错误仍然存​​在。
    • @user2717643 我更新了我的答案,看看能不能解决你的问题。
    • 再次感谢 Popo,我听从了您的建议,现在我的服务配置如下所示:
    • example.com/sub/Service1.svc" behaviorConfiguration="clientBehavior" binding="basicHttpBinding" bindingConfiguration="basicHttpBinding_Config" contract="ServiceReference1.MyService" name="BasicHttpBinding_MyService" />
    【解决方案2】:

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

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

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

    其次,我将此视为我的根密钥,并使用 mmc 将其安装在我的 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>
    

    【讨论】:

      猜你喜欢
      • 2020-07-20
      • 1970-01-01
      • 2011-08-10
      • 2011-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-27
      相关资源
      最近更新 更多