我在使用HTTPS获取MVC Web应用程序以调用也使用HTTPS的WCF服务时遇到问题。 MVC Web应用程序必须使用WCF服务的证书进行身份验证。
我使用的是Windows 7,IIS 7.5,VS 2010与C#和.NET Framework 4.0。
我创建了一个名为' Development Authority':
的证书颁发机构makecert -pe -n "CN=Development Authority" -ss my -sr LocalMachine -a sha1 -sky signature -r "c:\Development Authority.cer"
我使用MMC工具在“受信任的根证书颁发机构”中导入了新创建的证书。文件夹和第三方根证书颁发机构'文件夹(本地计算机)。此证书也可以在“个人”中找到。文件夹中。
我看到,如果我仅在“受信任的根CA”中导入CA'它仍然会给予一个不被信任的'警告。在第三方根CA'中导入CA后文件夹,警告消失了。
我使用以下命令创建了另外两个证书(由新创建的CA签名):
makecert -pe -n "CN=mvc.localhost" -ss my -sr LocalMachine -a sha1 -sky exchange -eku 1.3.6.1.5.5.7.3.1 -in "Development Authority" -is MY -ir LocalMachine -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12 c:\mvc.localhost.cer
通过这种方式,我创建了“mvc.localhost”#39;和' wcf.localhost'证书。我将它们导入了“个人”中。文件夹(对于本地计算机),使用MMC工具。
在我的Windows主机文件中,我为将要使用IIS(MVC应用程序和WCF服务应用程序)托管的两个应用程序创建了两个别名。我用以下几行更新了我的hosts文件:
#development
127.0.0.1 mvc.localhost
127.0.0.1 wcf.localhost
在IIS下,我映射了一个新网站' mvc.localhost'到一个非常简单的MVC网络应用程序。 我还绘制了一个新网站' wcf.localhost'到新创建的基本WCF服务。
应用程序池:使用' ApplicationPoolIdentity'正在运行的.NET Framework 4.0。
匿名身份验证:启用并设置为'特定用户' :' IUSR'。
绑定:
HTTP(主机名' mvc.localhost',端口80) - >可以使用' http://mvc.localhost/'
访问HTTPS(主机名' mvc.localhost',端口1234) - >可以使用' https://mvc.localhost:1234 /'进行访问。添加了' mvc.localhost'证书。
应用程序池:使用' ApplicationPoolIdentity'正在运行的.NET Framework 4.0。
匿名身份验证:启用并设置为'特定用户' :' IUSR'。
绑定:
HTTP(主机名' wcf.localhost',端口80) - >可以使用' http://wcf.localhost/'
进行访问HTTPS(主机名' wcf.localhost',端口443) - >可以使用' https://wcf.localhost/'进行访问。添加了' wcf.localhost'证书。
要修改HTTPS绑定的主机名,我使用以下命令:
c:\Windows\System32\inetsrv>appcmd set site /site.name:"wcf.localhost" /bindings.[protocol='https',bindingInformation='*:443:'].bindingInformation:*:443:wcf.localhost
我使用HTTPS分别对这两个网站进行了测试,并且它们没有问题(除了具有严格策略的Firefox,当我找到为测试目的而创建的本地证书时,会给你一个' sec_error_unknown_issuer'警告,但现在这不是我的问题。)
WCF服务配置:
<bindings>
<wsHttpBinding>
<binding name="wsHttpEndpointBinding">
<security mode="Transport">
<transport clientCredentialType="Certificate"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="wcf.localhost.WelcomeService" behaviorConfiguration="wcf.localhost.WelcomeServiceBehavior">
<endpoint address="https://wcf.localhost/WelcomeService.svc" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding" contract="wcf.localhost.IWelcomeService">
</endpoint>
<!--<endpoint address="mex" binding="mexHttpsBinding"
name="mexEndpoint" contract="IMetadataExchange"/>-->
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="wcf.localhost.WelcomeServiceBehavior">
<serviceMetadata httpsGetEnabled="true" httpGetEnabled="false"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceCredentials>
<clientCertificate>
<authentication revocationMode="NoCheck" certificateValidationMode="PeerOrChainTrust" />
</clientCertificate>
<serviceCertificate findValue="<<wcf.localhost Certificate Thumbprint inserted here>>" storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
在IIS中,对于SSL设置,我设置了“要求SSL&#39;与'要求&#39;选项。
服务WelcomeService公开了一个名为&#39; SayHello(string)&#39;的方法。那个连接'你好'&#39;输入参数并返回新字符串。
我可以联系到https://wcf.localhost/welcomeservice.svc'没有问题。
MVC网络应用配置:
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IWelcomeService" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text"
textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="false" />
<security mode="Transport">
<transport clientCredentialType="Certificate"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://wcf.localhost/WelcomeService.svc"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IWelcomeService"
contract="WelcomeService.IWelcomeService" name="WSHttpBinding_IWelcomeService" behaviorConfiguration="CustomBehavior">
</endpoint>
</client>
<behaviors>
<endpointBehaviors>
<behavior name="CustomBehavior" >
<clientCredentials>
<clientCertificate findValue="<<mvc.localhost Certificate Thumbprint inserted here>>"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindByThumbprint"/>
<serviceCertificate>
<authentication certificateValidationMode="PeerOrChainTrust" revocationMode="NoCheck"></authentication>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
现在出现问题: 使用MVC应用程序调用WCF服务后,我收到以下错误:
描述:执行当前Web请求期间发生了未处理的异常。请查看堆栈跟踪以获取有关错误及其源自代码的位置的更多信息。
Exception Details: System.Net.WebException: The remote server returned an error: (403) Forbidden.
Source Error:
Line 48:
Line 49: public void SayHello(string name) {
Line 50: base.Channel.SayHello(name);
Line 51: }
Line 52: }
Source File: C:\Projects\ssl.research\mvc.localhost\Service References\WelcomeService\Reference.cs Line: 50
Stack Trace:
[WebException: The remote server returned an error: (403) Forbidden.]
System.Net.HttpWebRequest.GetResponse() +7859156
System.ServiceModel.Channels.HttpChannelRequest.WaitForReply(TimeSpan timeout) +99
[MessageSecurityException: The HTTP request was forbidden with client authentication scheme 'Anonymous'.]
System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) +4727747
System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) +1725
mvc.localhost.WelcomeService.IWelcomeService.SayHello(String name) +0
mvc.localhost.WelcomeService.WelcomeServiceClient.SayHello(String name) in C:\Projects\ssl.research\mvc.localhost\Service References\WelcomeService\Reference.cs:50
mvc.localhost.Controllers.HomeController.CallService(HomeModel model) in C:\Projects\ssl.research\mvc.localhost\Controllers\HomeController.cs:33
lambda_method(Closure , ControllerBase , Object[] ) +127
System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +264
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +39
System.Web.Mvc.<>c__DisplayClass15.<InvokeActionMethodWithFilters>b__12() +129
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation) +826410
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +314
System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +825632
System.Web.Mvc.Controller.ExecuteCore() +159
System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +335
System.Web.Mvc.<>c__DisplayClassb.<BeginProcessRequest>b__5() +62
System.Web.Mvc.Async.<>c__DisplayClass1.<MakeVoidDelegate>b__0() +20
System.Web.Mvc.<>c__DisplayClasse.<EndProcessRequest>b__d() +54
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +469
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +375
Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.237
在客户端,我也尝试过:
ServicePointManager.ServerCertificateValidationCallback += customXertificateValidation ... private static bool customXertificateValidation(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors error) { return true; }
没有任何效果。
我使用SSL Diagnostics 1.1验证两个Web应用程序及其证书。 没有显示错误。 SSL握手模拟很好,没有错误。
我觉得我非常接近完成测试项目(在解决其他问题的过程中)。
在网上搜索时,我发现只有HTTP WCF服务或WCF服务没有使用证书进行身份验证或使用证书身份验证但是HTTP的WCF服务。
我尝试让运行MVC网络应用程序的HTTPS调用运行WCF服务的HTTPS,该服务需要证书才能进行身份验证。
许多伟大的文章帮助我解决了这个项目的其他问题。
现在我被卡住了,似乎无法找到解决方案。
任何建议表示赞赏。
谢谢你,波格丹。
我注意到我的两张证书都有其目的: &#39;确保远程计算机的身份。 (serverAuth)但我没有看到关于clientAuth的任何信息。
此外,当我访问MVC网络应用时,Chrome浏览器会提示我选择证书。在证书列表中,我看不到我创建的两个证书。
我只能看到一个证书作为其目的之一(但与我计划使用的证书不同!): &#39;向远程计算机证明您的身份&#39;
也许这就是我收到错误的原因?也许我不能使用我新创建的证书来验证服务器的客户端?
有什么想法?如果我是对的,我如何将clientAuth目的添加到我的任何证书中? 感谢
答案 0 :(得分:3)
与Rajesh一起,我可以找到解决方案。
问题在于使用“-eku”属性生成的客户端证书(mvc.localhost),该属性为证书提供了“确保远程计算机的身份”(serverAuth)但不是“客户端身份验证“。
您可以在其详细信息的“常规”标签上验证证书目的。
所以,我必须生成一个新的客户端证书,取消了“-eku”属性,该属性为证书提供了“所有应用程序策略”(包括客户端身份验证)。
我使用以下命令执行此操作:
C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC>makecert -sr LocalMachine
-ss my -a sha1 -n "CN=mvc.localhost" -sky exchange -pe -in "Development Author
ity" -is MY -ir LocalMachine -sp "Microsoft RSA SChannel Cryptographic Provider"
-sy 12 c:\mvc.localhost.cer
Succeeded
小心!使用makecert工具生成证书后,它们将显示在“本地计算机/个人”存储中。每当您必须在不同的商店中复制/导入某个证书时,请务必先将原始证书(“本地计算机/个人”存储)导出为.pfx文件。 然后你可以导入.pfx文件在其他商店而不是.cer文件!!
在此之后,只需将两个证书添加到正确的商店:
本地计算机 - &gt;个人商店 - &gt;有两个证书(使用makecert工具创建证书时自动添加)。 IIS从此存储中选择证书(为了在创建https绑定时使用一个),因此我不建议删除客户端证书。
本地计算机 - &gt;值得信赖的人 - &gt;导入mvc.localhost.pfx
当前用户 - &gt;个人商店 - &gt;导入mvc.localhost.pfx(这也导入了此文件夹中的mvc.localhost CA)
当前用户 - &gt;受信任的根证书颁发机构 - &gt;导入wcf.localhost.pfx
感谢Rajesh。
PS:你也可以在这里查看解决方案:WCF Forum Thread
答案 1 :(得分:1)
使用证书进行身份验证时,您需要确保将证书放在相应的商店中。
您需要拥有以下客户证书:
在客户端计算机上:
当前用户 - &gt;个人文件夹应该安装客户端证书mvc.localhost.pfx
在服务器计算机上:
本地计算机 - &gt; TrusterPeople应该安装mvc.localhost.cer
403 forbidden错误是因为服务器计算机无法使用它正在接收的证书验证客户端,因为它可能不在其受信任的存储中。
如果客户端和服务器是同一台计算机,请按照以下步骤确保安装证书。在您的情况下,您需要具有以下证书:
本地计算机 - &gt;个人存储需要具有服务器证书(wcf.localhost)
本地计算机 - &gt;受信任的人存储以获得客户端证书(mvc.localhost)
当前用户 - &gt;个人存储具有客户端证书(mvc.localhost)
当前用户 - &gt;受信任的根证书授权存储区具有服务器证书(wcf.localhost)
如果您有以下情况,请尝试从IE浏览到该服务,您应该能够看到该服务及其wsdl。
还可以转到IE,然后转到工具 - &gt;互联网选项 - &gt;安全 - &gt;互联网 - &gt;自定义级别
现在向下滚动到Misc部分,找到选项“当没有证书或只有一个证书时,不要提示客户端证书选择”Diable。
现在重新启动IE并浏览到该服务,IE应该要求您从个人存储中选择一个客户端证书,并且您需要选择mvc.localhost。
如果看不到mvc.localhost,那么您的客户端证书不在相应的商店中。
答案 2 :(得分:0)
添加到Bogdan的正确答案(因为我有同样的问题),我将OID_PKIX_KP_CLIENT_AUTH OID
(1.3.6.1.5.5.7.3.2
)添加到-eku
参数中,这给了我两个目的是你可能想要的而不是暴力&#34;所有应用程序政策&#34; 。
e.g。 (删除明显的换行符)
makecert -iv SignRoot.pvk -ic signroot.cer -cy end -pe -n CN="DEV dual purpose"
-eku 1.3.6.1.5.5.7.3.1,1.3.6.1.5.5.7.3.2 -ss my
-sr localmachine -sky exchange
-sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12