[原创]x.509证书在WCF中的应用(Web/IIS篇)

在上一篇"x.509证书在WCF中的应用(CS篇)"里,我们知道了如何在应用程序中,利用x.509证书来验证WCF的消息安全(没看过的朋友建议先看下,地址http://www.cnblogs.com/yjmyzz/archive/2008/08/20/1272550.html),这一篇我们将尝试把x.509证书放到IIS里来验证WCF。

WCF宿主在IIS和普通应用程序里,原理虽然没什么不同,但在实际测试中发现,如果服务端与客户端都采用x.509证书来验证,服务端设置的自定义验证客户端证书的方法总是不起作用,无奈之下,只能在客户端采用了一种变相的方法来验证客户端证书。

废话不多说,还是来看具体步骤吧:

开发环境: Windows2003 + VS2008(SP1)

一.申请/颁发服务端证书和客户端证书
默认情况下,用makecert制作的证书,我经过多次尝试,在IE7里始终被认为不信任的证书(也许是我makecert的参数不对),导致在IE7里测试SSL时,总是显示"证书错误,导航已阻止"之类,所以在本例中,我们换一种方式,用windows2003自带的证书服务来申请/颁发服务端证书和客户端证书,对这一块不熟悉的朋友,请参见"[原创图解]Win2003证书服务配置/客户端(服务端)证书申请/IIS站点SSL设置"一文(地址:http://www.cnblogs.com/yjmyzz/archive/2008/08/21/1273201.html),这里要注意的是服务端证书的"颁发给"的对象一定要和最后运行的url里的计算机名(或域名)信息一致,如下图,否则IE7会认为该证书有问题

二.Wcf web服务端开发
1.vs2008启动后,新建一个web Application(本例命名为WebServer),添加一个wcf服务,命名为MyService,同样系统会自动增加一个IMyService的接口,这二个文件的内容如下:
MyService.svc.cs(代码很简单,返回服务端时间而已)

using System;
using System.ServiceModel;

namespace WebServer
{
    // NOTE: If you change the class name "MyService" here, you must also update the reference to "MyService" in Web.config.
    public class MyService : IMyService
    {
        public string Test()
        {           
            return "服务端时间:<br/>" + DateTime.Now.ToString();
        }
    }
}

IMyService.cs内容

using System;
using System.ServiceModel;
using System.Text;

namespace WebServer
{
    // NOTE: If you change the interface name "IMyService" here, you must also update the reference to "IMyService" in Web.config.
    [ServiceContract]
    public interface IMyService
    {
        [OperationContract]
        string Test();
    }
}

配置文件Web.Config关键节点内容如下:

<system.serviceModel>
        <behaviors>
            <serviceBehaviors>
                <behavior name="WebServer.MyServiceBehavior">
                    
                    <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" httpsGetUrl="https://jimmycntvs/MyService.svc"/>
                        <serviceDebug includeExceptionDetailInFaults="false"/>
                    <serviceCredentials>
                        <!--下面这一行,在测试过程中,发现始终不起作用,只能放弃,转而在客户端的配置中用findValue="ec0aa48043eab64714c92a0ff7fa0365e1b594af" x509FindType="FindByThumbprint" 类似这样的方法来验证指定的客户端证书-->
                        <!--<clientCertificate>
                            <authentication certificateValidationMode="Custom" customCertificateValidatorType="WebServer.CustomX509CertificateValidator,WebServer"/>
                        </clientCertificate>-->
                        <serviceCertificate findValue="JimmyCntvs" storeLocation="LocalMachine"  x509FindType="FindBySubjectName" storeName="My"/>
                    </serviceCredentials>
                    
                </behavior>                
            </serviceBehaviors>
        </behaviors>
        <bindings>            
            <wsHttpBinding>
                <binding name="wsHttpBinding_MyService">
                    <security mode="Transport">
                        <transport clientCredentialType="None"/>
                        <!--设置成Certificate后,启动WCF时,总是提示出错[ 服务“SslRequireCert”的 SSL 设置与 IIS“Ssl”的 SSL 设置不匹配。]无奈只能设置成None-->
                        <!--<transport clientCredentialType="Certificate"/>-->
                        <message clientCredentialType="Certificate"/>                                                          
                    </security>                   
                </binding>
            </wsHttpBinding>
        </bindings>
        <services>
           <service behaviorConfiguration="WebServer.MyServiceBehavior"
            name="WebServer.MyService">
               <endpoint address="https://jimmycntvs/MyService.svc" binding="wsHttpBinding"
                bindingConfiguration="wsHttpBinding_MyService" contract="WebServer.IMyService" >
                   <identity>
                       <dns value="jimmycntvs"/>
                   </identity>
               </endpoint>           
           </service>
  </services>
    </system.serviceModel>

 解释一下:
 <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" httpsGetUrl="https://jimmycntvs/MyService.svc%22/>这行表明,只能用https方式取得wcf的元数据,httpsGetUrl标明了取得WCF元数据的地址
 
 
 <serviceCertificate findValue="JimmyCntvs" storeLocation="LocalMachine"  x509FindType="FindBySubjectName" storeName="My"/>这一句指wcf服务启动时,先验证服务端是否在LocalMachine这个位置有一个SubjectName为JimmyCntvs的服务端证书
 
 <security mode="Transport">
      <transport clientCredentialType="None"/>                      
      <message clientCredentialType="Certificate"/>                                                         
  </security> 这里表示用Transport模式来进行安全验证,详细安全参数含义可参见http://www.cnblogs.com/yjmyzz/archive/2008/08/19/1271133.html

2.IIS服务端配置
为方便测试,在IIS中直接把WebServer项目配置为一个站点(本例为http://localhost/),同时正确安装第一步颁发的服务端证书,同时把"要求安全通道(SSL)"选中,这样站点就必须用https://来访问了

这些都弄好以后,就可以测试了,浏览https://localhost/MyService.svc,如果是IE7,可能会报一个"证书错误:导航已阻止"的错误,没关系,把localhost换成计算机名(本例中为jimmycntvs)就正常了,如下图:

三.Web 客户端开发
1.先生成服务端WCF的代理
vs2008命令行下运行
svcutil.exe https://jimmycntvs/MyService.svc?wsdl /d:c:\123 即把代理文件和配置文件输出到c:\123下

2.安装客户端证书
把第一步颁发的客户端证书正确安装,同时查看该证书的详细信息,记下"微缩图"去掉空格后的值(本例为ec0aa48043eab64714c92a0ff7fa0365e1b594af,每个证书的这个值都是唯一的),后面会用到

3.vs.net2008新建一个WebClient的webApplication,把刚才的这二个文件加到WebClient中,同时output.config改名为Web.config,关键节点调整如下:

<system.serviceModel>
        <behaviors>
            <endpointBehaviors>
                <behavior name="NewBehavior">
                    <clientCredentials>
                        <!--<clientCertificate findValue="Jimmy.Yang" x509FindType="FindBySubjectName" storeLocation="CurrentUser" storeName="My"/>-->
                        <!--由于服务端设置的<authentication certificateValidationMode="Custom" customCertificateValidatorType="WebServer.CustomX509CertificateValidator,WebServer"/>在测试中发现总是不起作用,所以只能转而用下面的方式从客户端来验证特定的证书,理论上讲这样有安全隐患,建议实际操作时,可将本节加密后,再连同客户端证书一起分发给客户端,若用于安全性较高的环境,建议还是用UserName方式,到数据库里验证用户名和密码-->
                        <clientCertificate findValue="ec0aa48043eab64714c92a0ff7fa0365e1b594af" x509FindType="FindByThumbprint" storeLocation="CurrentUser" storeName="My"/>                        <serviceCertificate>
                            <authentication certificateValidationMode="None" />
                        </serviceCertificate>
                    </clientCredentials>
                </behavior>
            </endpointBehaviors>
        </behaviors>
        <bindings>
            <wsHttpBinding>
                <binding name="WSHttpBinding_IMyService" 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" proxyCredentialType="None"
                            realm="" />
                        <message clientCredentialType="Certificate" negotiateServiceCredential="true"
                            establishSecurityContext="true" />
                    </security>
                </binding>
            </wsHttpBinding>
        </bindings>
        <client>
            <endpoint address="https://jimmycntvs/MyService.svc" binding="wsHttpBinding"
                bindingConfiguration="WSHttpBinding_IMyService" contract="IMyService"
                name="WSHttpBinding_IMyService" behaviorConfiguration="NewBehavior">
                <identity>
                    <dns value="jimmycntvs" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>

主要是增加了behaviors这一节,用于查询客户端机器是否有微缩图为ec0aa48043eab64714c92a0ff7fa0365e1b594af的证书
<behaviors>
            <endpointBehaviors>
                <behavior name="NewBehavior">
                    <clientCredentials>                        
                        <clientCertificate findValue="ec0aa48043eab64714c92a0ff7fa0365e1b594af" x509FindType="FindByThumbprint" storeLocation="CurrentUser" storeName="My"/>                        <serviceCertificate>
                            <authentication certificateValidationMode="None" />
                        </serviceCertificate>
                    </clientCredentials>
                </behavior>
            </endpointBehaviors>
        </behaviors>     
       
最后,我们在Default.aspx.cs中加几行代码,用来调用WebServer中的WCF

protected void Page_Load(object sender, EventArgs e)
{
    using (MyServiceClient _client = new MyServiceClient()) 
    {
        string _test = _client.Test();
        Response.Write(_test);
    }
}

运行一下,正常的话,应该会返回服务端的时间。 欢迎转载,转载请注明来自cnblogs"菩提树下的杨过"

编后语:
本文演示了如何将WCF Host在IIS中,并对服务端和客户端都采用x.509证书方式来验证,当然这种方式要求每个客户端机器上都必须安装服务端颁发的证书。在互联网环境下,这可能会给客户端的使用带来麻烦,这时可以采用服务端用x.509方式验证,客户端用经典的用户名/密码的方式来验证,详情可参见http://www.cnblogs.com/fineboy/archive/2008/03/26/1122650.html,写得很详细,一看就知.

时间: 2024-07-29 04:48:08

[原创]x.509证书在WCF中的应用(Web/IIS篇)的相关文章

[原创]x.509证书在WCF中的应用(CS篇)

为什么要用x.509证书?WCF的服务端和客户端之间,如果不作任何安全处理(即服务端的<security mode="None">),则所有传输的消息将以明文方式满天飞,在internet/intranet环境下无疑是很不安全的,这就是用证书的目的.(当然WCF还有其它安全机制,比如最常见的UserName方式,但通常每次都要从数据库读取用户名/密码信息进行验证,比较麻烦,开销也大,个人觉得还是证书最为方便)--关于x.509证书 的基本知识,可参见http://www.c

WCF中引用其他Web Service部署IIS后调用报错

问题描述 在WCF中引用了其他WebService,本机测试一切正常,调用正常.发布部署IIS后,可以正常访问,其他方法也正常,调用这个引用了其他WebService的方法就报错.错误信息如下:Therewasnoendpointlisteningathttp://XX.XXXX:8899/sms_hb/services/Sms/thatcouldacceptthemessage.ThisisoftencausedbyanincorrectaddressorSOAPaction.SeeInner

[WCF安全系列]认证与凭证:X.509证书

在<上篇>中,我们谈到了常用的认证方式:用户名/密码认证和Windows认证.在下篇中,我们着重来介绍另外一种重要的凭证类型:X.509证书,以及针对X.509证书的认证方式.不过为了让读者能够真正地全面地了解X.509证书,我们需要先了解一些关于非对称密码学的背景知识. 目录 一.非对称密码学(Asymmetric Cryptography)     消息加密(Encryption)     数字签名(Digital Signature) 二.数字证书     数字证书的颁发机制     创

[WCF安全系列]谈谈WCF的客户端认证[X.509证书认证]

前面介绍Windows认证和用户名/密码认证这两种典型的客户端认证模式,我们最后来介绍最后一种客户端认证方式,即客户端凭证类型为X.509证书时服务端采用的认证,简称为证书认证.我们照例先看看看客户端证书凭证如何设置设置. 一.客户端证书凭证的设置 在服务认证一文中,我们知道了基于X.509证书证书的服务凭证通过X509CertificateRecipientServiceCredential类型表示.与之对应地,客户端凭证对应的类型是X509CertificateInitiatorClient

艾伟:[原创]谈谈WCF中的Data Contract(4):WCF Data Contract Versioning

软件工程是一门独特的工程艺术,需要解决的是不断改变的需求变化.而对于WCF,对于SOA,由于涉及的是对多个系统之间的交互问题,如何有效地解决不断改变的需求所带来的问题就显得更为重要:Service端版本的变化能否保持现有Consumer的正常调用,Consumer端的改变不至于影响对Service 的正常调用.对于Data Contract来说就是要解决这样的问题:Service端或者Client对Data Type的改变不会影响Service的正常调用. 在系统开发过程中,通过对Data Ty

[WCF安全系列]实例演示:TLS/SSL在WCF中的应用[SSL over TCP]

在接下来的系列文章中我们正是讨论关于身份认证的主题.在前面我们已经谈到了,WCF中的认证属于"双向认证",既包括服务对客户端的认证(以下简称客户端认证),也包括客户端对服务的认证(以下简称服务认证).客户端认证和服务认证从本质上并没有什么不同,无非都是被认证一方提供相应的用户凭证供对方对自己的身份进行验证.我们先来讨论服务认证,客户端认证放在后续的文章中. 在<从两种安全模式谈起>中,我们对TLS/SSL进行了简单的介绍.我们知道,客户端和服务在为建立安全上下文而进行的协商

我的WCF之旅(3):在WCF中实现双向通信(Bi-directional Communication)

昨天写了一篇Remoting中如何实现双向通信的文章<[原创].NET Remoting: 如何通过Remoting实现双向通信(Bidirectional Communication) >,作为对比,今天我们来讨论一下WCF的双向通信. 为了使我们能够更好地对比双向通信在Remoting中和WCF中的实现,我们的Sample采用一样的业务逻辑--调用一个数学计算的远程调用,除了传递相应的操作数之外,我们还传递一个对象,这个对象可以在Server端中回调 (Callback) 把运算结果在Cl

WCF中的Binding模型之六(完结篇):从绑定元素认识系统预定义绑定

由于绑定对象由一系列有序的绑定元素组成,绑定元素最终决定着信道栈中信道的组成,而信道的组成最终又决定了信道栈对消息进行处理的方式和能力,所有要确定绑定的特性和能力,我们可以通过查看其绑定元素的构成来一窥究竟.为此我们我们写了一个简单的方法,用于列出一个具体的绑定对象所有的绑定元素,在介绍一个个具体的系统绑定中,我会使用该方法: 1: static void ListAllBindingElements(Binding binding) 2: { 3: BindingElementCollecti

我的WCF之旅(4):WCF中的序列化[上篇]

SOA 和Message Windows Communication Foundation (WCF) 是基于面向服务架构(Service Orientation Architecture--SOA)的一种理想的分布式技术(Distributed Technology), 相信在今后在建立基于SOA企业级别的解决方案和进行系统集成方面将会大有作为.一个基于SOA结构的互联系统(Connected System)通常由若干相互独立的子系统(Sub-System)组成,这些子系统可能一个独立的App