【发布时间】:2012-01-08 16:48:22
【问题描述】:
我在使用 HTTPS 获取 MVC Web 应用程序以调用也使用 HTTPS 的 WCF 服务时遇到问题。 MVC Web 应用程序必须使用 WCF 服务的证书进行身份验证。
我正在使用带有 C# 和 .NET Framework 4.0 的 Windows 7、IIS 7.5、VS 2010。
这是我到目前为止所做的:
-
我创建了一个名为“开发机构”的证书颁发机构:
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”和“wcf.localhost”证书。我使用 MMC 工具将它们导入到“个人”文件夹(用于本地计算机)。
-
在我的 Windows 主机文件中,我为将要使用 IIS 托管的两个应用程序(MVC 应用程序和 WCF 服务应用程序)创建了两个别名。我用以下几行更新了我的主机文件:
#development 127.0.0.1 mvc.localhost 127.0.0.1 wcf.localhost -
在 IIS 下,我将一个新网站“mvc.localhost”映射到一个非常简单的 MVC Web 应用程序。 我还将一个新网站“wcf.localhost”映射到一个新创建的基本 WCF 服务。
mcv.localhost:
应用程序池: .NET Framework 4.0 使用“ApplicationPoolIdentity”运行。
匿名身份验证:启用并设置为“特定用户”:“IUSR”。
-
绑定:
HTTP (hostname 'mvc.localhost', port 80) -> 可以通过 'http://mvc.localhost/' 访问
HTTPS(主机名 'mvc.localhost',端口 1234)-> 可以使用 'https://mvc.localhost:1234/' 访问。添加了“mvc.localhost”证书。
wcf.localhost:
应用程序池: .NET Framework 4.0 使用“ApplicationPoolIdentity”运行。
匿名身份验证:启用并设置为“特定用户”:“IUSR”。
-
绑定:
HTTP (hostname 'wcf.localhost', port 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”。
WelcomeService 服务公开了一个名为“SayHello(string)”的方法,该方法将“Hello”连接到输入参数并返回新字符串。
我可以毫无问题地访问“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 ... 私有静态布尔 customXertificateValidation(对象发件人,X509Certificate 证书, X509Chain 链,SslPolicyErrors 错误) { 返回真; }- 使用服务证书指纹对服务进行身份验证。
- 不同的 certificateValidationMode 值。
没有任何效果。
我使用 SSL Diagnostics 1.1 来验证这两个 Web 应用程序及其证书。 没有显示错误。 SSL 握手模拟运行良好,没有错误。
我觉得我已经非常接近完成测试项目(在此过程中解决了其他问题)。
在网上搜索时,我只能找到 HTTP WCF 服务或未使用证书进行身份验证的 WCF 服务或使用证书身份验证但为 HTTP 的 WCF 服务。
我正在尝试让一个运行 HTTPS 的 MVC Web 应用调用一个运行 HTTPS 的 WCF 服务,该服务需要证书进行身份验证。
那里的许多优秀文章帮助我解决了这个项目的其他问题。
现在我被困住了,我似乎找不到解决方案。
感谢任何建议。
谢谢你,博格丹。
更新
我注意到我的两个证书都有其用途: “确保远程计算机的身份”(serverAuth),但我没有看到任何关于 clientAuth 的信息。
此外,当我访问 MVC Web 应用程序时,Chrome 浏览器会提示我选择证书。在证书列表中,我看不到我创建的两个证书。
我只能看到一个证书作为其用途之一(但与我计划使用的证书不同!): '向远程计算机证明你的身份'
也许这就是我收到错误的原因?也许我不能使用我新创建的证书来向服务器验证客户端?
有什么想法吗?如果我是对的,如何将 clientAuth 目的添加到我的任何证书中? 谢谢
【问题讨论】:
-
您好,当您尝试从浏览器访问服务时,是否提示您输入证书?如果是这样,您作为客户证书提供的证书是什么。
-
@rauts:你是对的。它确实要求我提供证书。这有两个问题: 1. 我看不到我新创建的两个证书。 2. 如果我将客户端配置为已经使用某个证书(带有指纹..),为什么它要求我提供证书?很奇怪。
标签: wcf https iis-7.5 wcf-binding wcf-security