要求 SSL 证书和客户端证书在 WCF JSON 服务中引发异常

Posted

技术标签:

【中文标题】要求 SSL 证书和客户端证书在 WCF JSON 服务中引发异常【英文标题】:Requiring SSL certificates and client certificates throws exception in WCF JSON service 【发布时间】:2012-01-09 06:45:07 【问题描述】:

我有一个使用 JSON 的简单 WCF 服务设置。在此服务中,我想将客户端身份验证与客户端证书一起使用。我已将 IIS 6 配置为需要 SSL,并通过设置文件夹 /site/services/wcf/json/ 来要求客户端证书。这种设置通常称为 2-way SSL。

但每当我尝试使用生成的 SSL 证书测试页面时,我都会遇到异常。

服务“无”的 SSL 设置与 IIS“Ssl、SslNegotiateCert、SslRequireCert”的设置不匹配。

Stack Trace: 

[NotSupportedException: The SSL settings for the service 'None' does not match those of the IIS 'Ssl, SslNegotiateCert, SslRequireCert'.]
   System.ServiceModel.Activation.HostedAspNetEnvironment.ValidateHttpsSettings(String virtualPath, Nullable`1& requireClientCertificate) +117347
   System.ServiceModel.Channels.HttpsChannelListener.ApplyHostedContext(String virtualPath, Boolean isMetadataListener) +97
   System.ServiceModel.Activation.HostedAspNetEnvironment.ApplyHostedContext(TransportChannelListener listener, BindingContext context) +84
   System.ServiceModel.Channels.HttpsTransportBindingElement.BuildChannelListener(BindingContext context) +93
   System.ServiceModel.Channels.BindingContext.BuildInnerChannelListener() +63
   System.ServiceModel.Channels.MessageEncodingBindingElement.InternalBuildChannelListener(BindingContext context) +67
   System.ServiceModel.Channels.WebMessageEncodingBindingElement.BuildChannelListener(BindingContext context) +49
   System.ServiceModel.Channels.BindingContext.BuildInnerChannelListener() +63
   System.ServiceModel.Channels.Binding.BuildChannelListener(Uri listenUriBaseAddress, String listenUriRelativeAddress, ListenUriMode listenUriMode, BindingParameterCollection parameters) +125
   System.ServiceModel.Description.DispatcherBuilder.MaybeCreateListener(Boolean actuallyCreate, Type[] supportedChannels, Binding binding, BindingParameterCollection parameters, Uri listenUriBaseAddress, String listenUriRelativeAddress, ListenUriMode listenUriMode, ServiceThrottle throttle, IChannelListener& result, Boolean supportContextSession) +337
   System.ServiceModel.Description.DispatcherBuilder.BuildChannelListener(StuffPerListenUriInfo stuff, ServiceHostBase serviceHost, Uri listenUri, ListenUriMode listenUriMode, Boolean supportContextSession, IChannelListener& result) +668
   System.ServiceModel.Description.DispatcherBuilder.InitializeServiceHost(ServiceDescription description, ServiceHostBase serviceHost) +1228
   System.ServiceModel.ServiceHostBase.InitializeRuntime() +60
   System.ServiceModel.ServiceHostBase.OnBeginOpen() +27
   System.ServiceModel.ServiceHostBase.OnOpen(TimeSpan timeout) +50
   System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) +318
   System.ServiceModel.Channels.CommunicationObject.Open() +36
   System.ServiceModel.HostingManager.ActivateService(String normalizedVirtualPath) +184
   System.ServiceModel.HostingManager.EnsureServiceAvailable(String normalizedVirtualPath) +615

我已测试证书是否安装正确。我创建了一个需要客户端身份验证的基本虚拟目录。此虚拟目录包含一个简单的 .htm 文件。我已经确认它需要 https 并且它对我的客户证书提出质疑,当我证明有效的客户证书时,它会显示 .htm 页面,而当我没有证明有效的证书时它不会。

将 IIS 中的这些相同设置应用于我的 WCF 服务时,我得到了上述异常。我尝试将服务配置为也需要 SSL 和客户端身份验证,但我继续收到上述异常。

这是我的设置。

<system.serviceModel>
<!-- behaviors -->
<behaviors>
    <endpointBehaviors>
        <behavior name="jsonBehavior">
            <enableWebScript />
                <clientCredentials>
                <clientCertificate findValue="*.MyCompany.com" storeLocation="LocalMachine" x509FindType="FindBySubjectName" storeName="My" />
            </clientCredentials>
        </behavior>
    </endpointBehaviors>
    <serviceBehaviors>
        <behavior name="">
            <serviceDebug includeExceptionDetailInFaults="true" />
            <serviceMetadata httpsGetEnabled="true" httpGetEnabled="false" />
            <serviceCredentials>
                    <serviceCertificate  findValue="*.MyCompany.com" storeLocation="LocalMachine" x509FindType="FindBySubjectName" storeName="My" />                                              
                </serviceCredentials>
        </behavior>
    </serviceBehaviors>
</behaviors>

<!-- bindings -->
<bindings>
    <webHttpBinding>
        <binding name="webBinding">
            <security mode="Transport">
                <transport clientCredentialType="Certificate"/>
            </security> 
        </binding>
    </webHttpBinding>
</bindings>

<!-- services -->

<services>
    <service name="Service1Json" behaviorConfiguration="">
        <endpoint address="https://www.MyCompany.com/site/services/wcf/json/Service1.svc"
            behaviorConfiguration="jsonBehavior"
            binding="webHttpBinding"
            bindingConfiguration="webBinding"
            contract="MyCompany.Services.Wcf.IService1" />
    </service>
    <service name="Service2Json" behaviorConfiguration="">
        <endpoint address="https://www.MyCompany.com/site/Services/WCF/json/Service2.svc"
            behaviorConfiguration="jsonBehavior"
            binding="webHttpBinding"
            bindingConfiguration="webBinding"
            contract="MyCompany.Services.Wcf.IService2" />
    </service>
    <service name="Service3Json" behaviorConfiguration="">
        <endpoint address="https://www.MyCompany.com/site/services/wcf/json/Service3.svc"
            behaviorConfiguration="jsonBehavior"
            binding="webHttpBinding"
            bindingConfiguration="webBinding"
            contract="MyCompany.Services.Wcf.IService3" />
    </service>
</services>

<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />

</system.serviceModel>

【问题讨论】:

【参考方案1】:

问题实际上比我上面描述的更复杂。最终的解决方案非常简单。

上面原始问题中没有提到的是我们有多个端点:1. SOAP 2. JSON。这些都需要使用 2-way SSL 进行保护。

我们的错误如下:

    不需要客户端和服务器凭据。 服务名称必须与 .svc 文件的名称匹配。 端点地址必须不同。因此,对于我们的 JSON 端点,我们添加了“json”。我们还从地址中删除了完全限定的 URI,并让 WCF 自动为我们生成它。

这是我们最终得到的配置:

<system.serviceModel>

    <!-- behaviors -->
    <behaviors>
        <endpointBehaviors>
            <behavior name="jsonBehavior">
                <enableWebScript />
            </behavior>
        </endpointBehaviors>
        <serviceBehaviors>
            <behavior name="">
                <serviceDebug includeExceptionDetailInFaults="true" />
                <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
            </behavior>
        </serviceBehaviors>
    </behaviors>

    <!-- bindings -->
    <bindings>
        <basicHttpBinding>
            <binding name="httpBinding">
                <security mode="None">
                </security>
            </binding>
        </basicHttpBinding>
        <webHttpBinding>
            <binding name="webBinding">
                <security mode="None">
                </security>
            </binding>
        </webHttpBinding>
    </bindings>

    <!-- services -->
    <services>
        <service name="MyCompany.Services.Wcf.Service1" behaviorConfiguration="">
            <endpoint address="json"
                behaviorConfiguration="jsonBehavior"
                binding="webHttpBinding"
                bindingConfiguration="webBinding"
                contract="MyCompany.Services.Wcf.IService1" />
            <endpoint address=""
                behaviorConfiguration=""
                binding="basicHttpBinding"
                bindingConfiguration="httpBinding"
                contract="MyCompany.Services.Wcf.IService1" />
        </service>

        <service name="MyCompany.Services.Wcf.Service2" behaviorConfiguration="">
            <endpoint address="json"
                behaviorConfiguration="jsonBehavior"
                binding="webHttpBinding"
                bindingConfiguration="webBinding"
                contract="MyCompany.Services.Wcf.IService2" />
            <endpoint address=""
                behaviorConfiguration=""
                binding="basicHttpBinding"
                bindingConfiguration="httpBinding"
                contract="MyCompany.Services.Wcf.IService2" />
        </service>

    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />

</system.serviceModel>

如果我们选择让 SOAP 不使用 2-way SSL 并且 JSON 需要 2-way SSL,那么配置会复杂得多。

【讨论】:

您可以将此答案标记为“解决方案”,即使它是您自己的。这将进一步帮助将来发现此问题的其他人。 好的,谢谢。我没有意识到这是必要的。我仍然在这里学习绳索。 欢迎来到 SO,请尽情享受 :)

以上是关于要求 SSL 证书和客户端证书在 WCF JSON 服务中引发异常的主要内容,如果未能解决你的问题,请参考以下文章

使用ssl和客户端证书的Wcf:请求svc succes wcf调用返回403.16

如何在 WCF 客户端中接受自签名 SSL 证书?

WCF 消息安全证书

WCF 客户端证书身份验证,服务“SslRequireCert”的 SSL 设置与 IIS“Ssl,SslNegotiateCert”的设置不匹配

WCF 自签名证书在客户端上不受信任

简单的 WCF SSL Web 服务