zoukankan      html  css  js  c++  java
  • 基于证书的WCF安全开发详解

    前几天成功建立起了一套基于证书的安全的WCF服务,很兴奋,现在做一下总结,希望大侠们指点,也希望能帮助到一些菜鸟,哈哈。

    一、安全通信的基本过程

    这里只做定性的理论上的分析,因为再详细一点的我也不懂。一个通信分为客户端A和服务端B,A发送请求,B响应请求。安全通信必须满足3个方面的要 求,1是保密性,即数据要经过加密,防止第三者偷窥到。2是防篡改(不知道用完整性来表示合适不),即保证B收到的数据与A发出的数据是一样的,3是抗否 认,即如果A向B发送了数据,要从技术上保证A没办法抵赖说A没发,或者说A发的与B收到的不一样。2和3从某种意义上是同义词,因为既然没人能冒充A发 数据,那么A就不能抵赖。

    二、PKI系统

    PKI系统由信息发送方,接收方,和CA(证书认证中心)3部分组成。PKI系统可以满足以上安全通信的所有要求。

    发送方A和接收方B都有一对密钥,A有公钥A和私钥A,B有公钥B和私钥B,这些密码是由CA签发的,A和B都信任CA,信任的关系是建立在证书链 的基础上的,CA有自己的根证书Root(包含公钥Root和私钥Root),A和B的密钥实际上是由CA根据自己的密钥所签发的子密钥。PKI系统实现 了这样一个逻辑,就是如果一个PC信任一个Root证书,那么它也信任由Root签发的子证书。这一逻辑由系统软件(比如浏览器、WCF框架)所实现,我 们不必实现和管理此逻辑。所以,A和B机里的受信任的根证书区里都要包含Root的公钥,此外A和B都有自己的公钥和私钥,因为A和B都信任Root,所 以这样配置下来,A就会信任B,B也会信任A。

    (1)发送信息I之前,A首先生成某种对称加密算法(比如DES,AES)的密钥Q,Q是用来加密信息I的,因为对称加密比非对称加密快很多,所以虽然我们可以用私钥A来对I加密,但却不这么做。

    (2)A用公钥B对Q加密,生成Q’。

    (3)A用Q对I加密,生成I’。

    (4)A用私钥A做签名。具体过程是:先对(Q’+I’)做哈希(MD5、SHA1等)得S,再用私钥A对S做加密,得S’。

    (5)A把(Q’+I’+S’)发给B。

    (6)B用公钥A对签名做验证。具体过程是:先对((Q’+I’)做哈希(MD5、SHA1等)得S,再用公钥A对S’做解密得S’’,看S是否等于S’’,相等则有效,不等则验证失败。

    (7)B用私钥B对Q’做解密得Q。

    (8)用Q对I’做解密,得I。至此,A完成了向B发送I,B完成了接收I。

    在第5步,信息流传于公网上,所以(Q’+I’+S’)可能被黑客X所截获,但我们可以证明,X不可能获得有用的信息(即保密性),X也不能篡改I并发给B(防篡改,检测篡改),A也不能抵赖(抗否认):

    1. X要想知道I,则必须先知道Q,但它只知道Q’,所以它还要知道私钥B才能得到Q,但这是不可能的,因为只有B和CA才知道私钥B,而CA是绝对公正和安全的,B又不会把私钥B告诉别人。

    2. 如果第(6)步验证成功,我们可以断定I没有被篡改过。因为假如I被篡改过,则签名S’经过公钥A解密后得的S’’,一定不会等于(Q’+I’)的哈希值S,而这与已知的条件不符,所以是不可能的。

    3. 假如A要想否认自己发过I,则说明A可能把私钥A泄露给了别人Y,Y就是坏蛋。如果A说没有告诉别人,则A就在说谎,因为签名S’只有A才能生成。所以A不能抵赖。

    三、一个Case

    有3台PC(W,Y,P),W为客户端,W请求Y,Y又请求P,那么Y即是服务端又是客户端,P是服务端,Y和P上布署的有WCF。

    要保证这三台PC间的安全通信还必须有个CA,我们可以自己架设,也可以买第三方的服务。在开发阶段,我们可以用makecert来模拟CA签发证书的过程。

    具体过程如下:

    (1)生成根证书

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

    TempCA就是模拟的Root证书

    (2)生成W,Y,P子证书

    makecert -n "CN=W" -iv TempCA.pvk -ic TempCA.cer -sv W.pvk W.cer -pe -sky exchange
    pvk2pfx.exe -pvk W.pvk -spc W.cer -pfx W.pfx

    ==========================================================
    makecert -n "CN=Y" -iv TempCA.pvk -ic TempCA.cer -sv Y.pvk Y.cer -pe -sky exchange
    pvk2pfx.exe -pvk Y.pvk -spc Y.cer -pfx Y.pfx

    ==========================================================
    makecert -n "CN=P" -iv TempCA.pvk -ic TempCA.cer -sv P.pvk P.cer -pe -sky exchange
    pvk2pfx.exe -pvk P.pvk -spc P.cer -pfx P.pfx

    (3)导入证书

    把TempCA.cer导入W,Y,P的受信任的根证书区,把各自的pfx导入各自的个人证书区,这样每台机器都有2个证书,一个根证书,一个自己的证书。

    (4)创建WCF

    首先在P上创建WCF服务,再在Y上创建WCF服务并引入P的服务,再在W上创建客户端引入Y的服务。

    (5)配置安全选项

    W上的配置类似于:


        
    <system.serviceModel>
            
    <bindings>
                
    <wsHttpBinding>
                    
    <binding name="ServerBinding">
                        
    <security mode="Message">
                            
    <message clientCredentialType="Certificate" negotiateServiceCredential="true" algorithmSuite="Default" establishSecurityContext="true"/>
                        
    </security>
                    
    </binding>
                
    </wsHttpBinding>
            
    </bindings>
            
    <client>
                
    <endpoint address="http://Y/Test.svc" binding="wsHttpBinding" bindingConfiguration="ServerBinding" contract="WcfClients.ITest" name="WSHttpBinding_ITest" behaviorConfiguration="TestEndpointBehavior">
                    
    <identity>
                        
    <dns value="Y"/>
                    
    </identity>
                
    </endpoint>
            
    </client>
            
    <behaviors>
                
    <endpointBehaviors>
                    
    <behavior name="TestEndpointBehavior">
                        
    <clientCredentials>
                            
    <clientCertificate findValue="W" storeLocation="LocalMachine" x509FindType="FindBySubjectName" />
                            
    <serviceCertificate>
                                
    <authentication certificateValidationMode="ChainTrust" revocationMode="NoCheck" />
                            
    </serviceCertificate>
                        
    </clientCredentials>
                    
    </behavior>
                
    </endpointBehaviors>
            
    </behaviors>
        
    </system.serviceModel>

    简单解释一下:

    binding节配置了消息的传输方式和安全策略,并配置有name,在后面的endpoint里可以引用。服务端和客户端的binding要一致。

    client节点代表客户端引用了哪些endpoint,每个endpoint的binding是什么。

    endpointBehavior节点是一种扩展,针对本例,只需要配置客户端需要的具体身份凭据。服务端和客户端都可以定义 endpointBehavior,它是针对endpoint的。另外还有针对service的serviceBehavior,它只需配置在服务端,客 户端不需要。

    ==========================================================

    Y的配置:


        
    <system.serviceModel>
            
    <client>
                
    <endpoint address="http://P/Service1.svc" binding="wsHttpBinding" bindingConfiguration="ServerBinding" contract="IService1" name="WSHttpBinding_IService1" behaviorConfiguration="ServiceBehavior">
                    
    <identity>
                        
    <dns value="P" />
                    
    </identity>
                
    </endpoint>
            
    </client>
            
    <bindings>
                
    <wsHttpBinding>
                    
    <binding name="ServerBinding">
                        
    <security mode="Message">
                            
    <message clientCredentialType="Certificate" />
                        
    </security>
                    
    </binding>
                
    </wsHttpBinding>
            
    </bindings>
            
    <services>
                
    <service behaviorConfiguration="WcfSample.TestBehavior" name="WcfSample.Test">
                    
    <endpoint address="" binding="wsHttpBinding" contract="WcfSample.ITest" bindingConfiguration="ServerBinding">
                    
    </endpoint>
                    
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
                
    </service>
            
    </services>
            
    <behaviors>
                
    <serviceBehaviors>
                    
    <behavior name="WcfSample.TestSecureBehavior">
                        
    <serviceMetadata httpGetEnabled="true"/>
                        
    <serviceDebug includeExceptionDetailInFaults="false"/>
                        
    <serviceCredentials>
                            
    <serviceCertificate storeName="My"
                            storeLocation
    ="LocalMachine"
                            x509FindType
    ="FindBySubjectName"
                            findValue
    ="TomYang-PC"/>
                            
    <clientCertificate>
                                
    <authentication certificateValidationMode="ChainTrust" revocationMode="NoCheck" />
                            
    </clientCertificate>
                        
    </serviceCredentials>
                    
    </behavior>
                
    </serviceBehaviors>
                
    <endpointBehaviors>
                    
    <behavior name="ServiceBehavior">
                        
    <clientCredentials>
                            
    <clientCertificate storeName="My"
                            storeLocation
    ="LocalMachine"
                            x509FindType
    ="FindBySubjectName"
                            findValue
    ="Y"/>
                            
    <serviceCertificate>
                                
    <authentication certificateValidationMode="ChainTrust" revocationMode="NoCheck"/>
                            
    </serviceCertificate>
                        
    </clientCredentials>
                    
    </behavior>
                
    </endpointBehaviors>
            
    </behaviors>
        
    </system.serviceModel>

    Y的配置之所以如此之长,是因为它既要配置服务端,又要配置客户端。其中的service节和serviceBehavior节是与W的对应之处,也就是服务端需要什么样的凭据,客户端就要提供,反过来,客户端需要服务端提供什么样的凭据,服务端也要提供相应的配置。

    ==========================================================

    P的配置:


        
    <system.serviceModel>
            
    <bindings>
                
    <wsHttpBinding>
                    
    <binding name="ServerBinding">
                        
    <security>
                            
    <message clientCredentialType="Certificate" />
                        
    </security>
                    
    </binding>
                
    </wsHttpBinding>
            
    </bindings>
            
    <services>
                
    <service name="Service1" behaviorConfiguration="Service1Behavior">
                    
    <endpoint address="" binding="wsHttpBinding" contract="IService1" bindingConfiguration="ServerBinding">
                    
    </endpoint>
                    
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
                
    </service>
            
    </services>
            
    <behaviors>
                
    <serviceBehaviors>
                    
    <behavior name="Service1Behavior">
                        
    <serviceMetadata httpGetEnabled="true" />
                        
    <serviceDebug includeExceptionDetailInFaults="true" />
                        
    <serviceCredentials>
                            
    <clientCertificate>
                                
    <authentication certificateValidationMode="ChainTrust" revocationMode="NoCheck" />
                            
    </clientCertificate>
                            
    <serviceCertificate findValue="P" storeName="My" x509FindType="FindBySubjectName" />
                        
    </serviceCredentials>
                    
    </behavior>
                
    </serviceBehaviors>
            
    </behaviors>
        
    </system.serviceModel>

    OK, 所有代码与配置均写好了,还有要注意的一点是防火墙的问题,假如你所做的WCF使用了被防火墙屏蔽的端口时,你需要配置一下防火墙,方法可以是添加例外的 应用程序,或者添加端口。还有元数据的配置(即address为mex的那些东东),在正式的生产环境中是需要去掉的,它们可能会泄露系统敏感信息。

    四、剩余的工作

    这个Case只做到了安全通信,没有实现更详细的控制,比如身份识别(服务端收到请求后如何知道请求者是谁),权限控制(如何把一个用户映射到角 色,某个功能只对某些用户名角色开放)。身份识别可以使用证书的thumbprint,权限控制可以用代码访问安全性设置。这方面还没深入了解,有谁有这 方面的经验可以分享啊?

    对于有些应用,比如不需要太详细的控制,只要求实现两点间的安全通信即可,那么这个Case已经够用了。

    与老外讨论WCF

    与老外讨论安全通信

  • 相关阅读:
    [LeetCode] Power of Three 判断3的次方数
    [LeetCode] 322. Coin Change 硬币找零
    [LeetCode] 321. Create Maximum Number 创建最大数
    ITK 3.20.1 VS2010 Configuration 配置
    VTK 5.10.1 VS2010 Configuration 配置
    FLTK 1.3.3 MinGW 4.9.1 Configuration 配置
    FLTK 1.1.10 VS2010 Configuration 配置
    Inheritance, Association, Aggregation, and Composition 类的继承,关联,聚合和组合的区别
    [LeetCode] Bulb Switcher 灯泡开关
    [LeetCode] Maximum Product of Word Lengths 单词长度的最大积
  • 原文地址:https://www.cnblogs.com/bighuiwolf/p/1808020.html
Copyright © 2011-2022 走看看