WCF分布式安全开发实践(12):消息安全模式之自定义X509证书验证

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
Digicert DV 证书 单域名,20个 3个月
简介:
    今天继续介绍WCF分布式安全开发实践(12):消息安全模式之自定义X509证书验证,Message_CustomX509Certificate_WSHttpBinding 。本文介绍的内容主要是:主要是消息安全模式的自定义证书身份验证方式,基于WSHttpBinding绑定协议的实现过程。主要内容:基本概念,然后是制作证书、服务端配置、客户端配置、总结。这里应该和Transport传输安全模式之自定义证书身份验证对应,但是消息安全模式这里不使用https。安全基于TLS,传输层安全连接。  
    和 WCF分布式安全开发实践(11):消息安全模式之Certificate身份验证:Message_Certificate_WSHttpBinding大部分过程相同。差别在于客户端证书的验证过程由我们自己提供。而不是有WCF框架自己完整。
【0】消息安全模式之自定义证书客户端身份验证:
       消息安全模式之自定义证书身份验证需要服务器需要一个有效的可用于TLS 加密和向客户端验证服务身份的 X.509 证书,并且客户端必须信任此服务器证书。而客户端同样要提供一个有效的证书,来证明自己的身份。 这里使用http协议。建议安全上下文以后,使用共享安全上下文对SOAP消息进行加密和签名。使用证书对客户端和服务进行身份验证。也就是客户端提供有效证书才可以访问此服务。
1.身份验证(服务器):提供证书,(使用 HTTP)用于初始会话协商和证明服务身份。 
2.身份验证(客户端):客户端证书进行身份验证,自定义验证代码
   WCF消息安全模式之自定义证书身份验证的架构如下:
    客户端建立TLS安全上下文以后,会使用商定的密码对消息签名,客户端使用证书加密数据,服务端使用证书解密数据,保证数据的安全和机密性,消息签名放置被篡改。
   这里客户端提供的是有效的证书,服务器端使用自定义代码对客户端证书进行验证。而不是有WCF框架自动完成。
   下面是制作证书的过程,和传输安全模式的过程一样,这里直接使用相同证书制作工具,新启用端口8001。
【1】制作证书:
(1)使用makecert 工具:Microsoft Visual Studio 2008-->Visual Studio Tools-->Visual Studio 2008 命令提示行。
输入: makecert -sr localmachine -ss My -n CN=WCFServerPK -sky exchange -pe -r
输入:makecert -sr localmachine -ss My -n CN=WCFClientPK -sky exchange -pe -r。
-这里制作了连个证书,主要只使用一个WCFServerPK,可以到出密钥文件pfx,后续我们要导入到其他存储区,设置为信任的证书。WCFClientPK -是为以后文章准备的,也是可以设置为信任的证书。

 (2) 打开浏览器---->Internet 选项----->内容----->证书----->个人,默认是保存到当前用户CurrentUser,你会看到刚才制作的证书。这个可以查看部分证书,但是功能有限。我们还是使用控制台证书管理工具。
 (3)使用MMC建立证书控制单元查看证书的信息:
  开始--运行--MMC--控制台--添加删除单元--证书--当前用户和计算机各添加一个。能查看和管理CurrentUser和LocalMachine的证书。如图:
(4)导入证书到信任的人和信任的CA机构里。步骤如下:
    1.导出证书文件,带密钥的pfx文件。使用mmc,保存到桌面位置(方便查找)。这里记住你制作证书的密码。要使用。
    2.导入证书到信任的人。使用任务-导入向导--选择证书文件,导入即可。
    3.导入证书到信任的机构,使用任务-导入向导--选择证书文件,导入即可。这个证书就被信任了。
【3】服务端配置:
   服务器证书配置完成以后,我们来配置服务端相关的文件,这里简单。也可以使用代码来完成。
    (1)服务类定义:
    重复使用以前定义的服务类代码。 这里服务类就一个方法就是更具用户的name来打印调用时间,代码如下:
 //1.服务契约
    [ServiceContract(Namespace = "http://www.cnblogs.com/frank_xl/" )]
    
public interface
 IWCFService
    {
        
//操作契约

        [OperationContract]
        
string SayHello(string
 name);

    }
    
//2.服务类,继承接口。实现服务契约定义的操作

    public class  WCFService : IWCFService
    {
        
//实现接口定义的方法

        public string SayHello(string  name)
        {
            Console.WriteLine(
"Hello! {0},Calling at {1} "
, name,DateTime.Now.ToLongTimeString());
            
return "Hello! " +
 name;
        }
    }
    (2)消息安全模式配置:
       使用消息安全模式,采用客户端证书身份验证策略,Message安全模式下的证书验证方式配置信息如下:
    <wsHttpBinding>
      
<binding name="BindingConfigration">
        
<security mode="Message">
          
<transport clientCredentialType="None"/>
          
<message clientCredentialType="Certificate" negotiateServiceCredential="true" establishSecurityContext="true"/>
        
</security>
      
</binding>
    
</wsHttpBinding>
   这里允许启用安全协商和建立安全上下文。这个配置要应用到服务的终结点配置上。才会生效。
    (1)服务验证代码:
    证书制作完整以后,就需要来实现自定义用户名和密码的验证程序。这里要重写X509CertificateValidator类的 Validate(X509Certificate2 certificate)方法。具体代码如下:
  //证书验证程序,这里可以访问证书数据库或者其他证书存储机构,来验证客户端证书的真伪。
        public class  CustomX509CertificateValidator : X509CertificateValidator
        {
            
public override void
 Validate(X509Certificate2 certificate)
            {
                Console.WriteLine(
"Certificate Subject is :{0}"
, certificate.Subject);
                Console.WriteLine(
"Certificate Thumbprint is :{0}"
, certificate.Thumbprint);
                
//This is the Client  Certificate Thumbprint,In Production,We can validate the Certificate With CA

                if (certificate.Thumbprint != "748e3f8d07f14750460244045e21633cf1f5b211" )
                {

                    Console.WriteLine(
"CertificateValidatation is failed !{0}"
, certificate.Subject);
                    
throw new SecurityTokenException("Unknown Certificate"
);
                }
                
else

                {
                    Console.WriteLine(
"CertificateValidatation is sucessfully !:{0}" , certificate.Subject);
                }
            } 
        }
    这里客户端证书的指纹是748e3f8d07f14750460244045e21633cf1f5b211。如果客户端提供的证书信息不对,就直接抛出异常,验证失败,实际应用我们可以到CA证书机构或者证书数据库查询数据,来判定客户端证书的有效性。传输安全保证了用户名密码的机密性,而验证代码可以灵活地访问我们系统的数据库或者CA来判定客户端是否是有效的客户端。可以很好的保护WCF服务。与自定义用户名密码的方式一样,验证程序比较灵活。服务器不需要导入客户端证书。
    自定义客户端代码我们在配置文件里设置。代码如下:
             < clientCertificate  >
              
< authentication   certificateValidationMode = " Custom "   customCertificateValidatorType = " WCFService.CustomX509CertificateValidator,WCFService " />
            
</ clientCertificate >

    (4)服务器证书使用:
        服务器端证书主要是在建立TLS连接会话的时候,证明服务端的身份合法性。
    在服务行为节点属性里配置使用证书WCFServerPK,其它设置采用默认方式。这里和 WCF分布式安全开发实践(7):消息安全模式之匿名客户端:Message_None_WSHttpBinding 配置一样。具体代码如下:
<serviceBehaviors> 
                <behavior name="WCFService.WCFServiceBehavior"> 
                    <serviceMetadata httpGetEnabled="true" /> 
                    <serviceDebug includeExceptionDetailInFaults="false" /> 
                    <serviceCredentials> 
                            <serviceCertificate    storeName="My"    x509FindType="FindBySubjectName" findValue="WCFServerPK" storeLocation="LocalMachine"/> 
                        <clientCertificate > 
                            <authentication     certificateValidationMode="Custom"    customCertificateValidatorType="WCFService.CustomX509CertificateValidator,WCFService"/> 
                        </clientCertificate> 
                    </serviceCredentials> 
                </behavior> 
                
            </serviceBehaviors>
    这里指定了服务端证书的查找位置和查找条件,我们证书存储在LocalMachine 个人区域。使用标题进行查找。如果相同标题,需要制定唯一的查找条件。保证查找证书的唯一性。否则会出异常。
   (5)这里我们不需要使用Https传输协议,直接使用http协议即可,服务终结点的配置信息如下:
    <services>
      
<service behaviorConfiguration="WCFService.WCFServiceBehavior" name="WCFService.WCFService" >
        
< endpoint 
          address
="WCFService"
 
          binding
="wsHttpBinding"
 
          bindingConfiguration
="BindingConfigration"

          contract
="WCFService.IWCFService">
        
</endpoint>
        
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
        
<host>
          
<baseAddresses>
            
<add baseAddress="http://localhost:8001/"/>
          
</baseAddresses>
        
</host>
      
</service>
    
</services>
   我们的服务元数据终结点使用基地址: http://localhost:8001/。消息安全模式基本使用的都是相同的端口。
【4】客户端配置:
    这个过程和之前的传输安全模式下,参考WCF分布式安全开发实践(11):消息安全模式之Certificate身份验证:Message_Certificate_WSHttpBinding , 添加服务的过程一样。直接引用。
    (1)引用元数据:
    因为服务的元数据交换节点启用了Http协议,我们在客户端项目添加元数据地址 http://localhost:8001/mex查找服务信息的时候,界面如下:
   继续就会添加完毕服务引用。过程和普通的添加服务元数据引用一样,会产生客户端相关代码文件。输入命名空间,现在我们点击Ok。等待完成即可。   
    (2)配置文件:
    客户端配置文件使用默认设置,主要是安全模式的设置要如下,与服务端匹配。使用证书验证方式。
bindings>
            
<wsHttpBinding>
                
<binding name="WSHttpBinding_IWCFService">
                    
<security mode="Message">
                        
<transport clientCredentialType="None" proxyCredentialType="None"
                            realm
="" />
                        
<message clientCredentialType="Certificate" negotiateServiceCredential="true"
                            algorithmSuite
="Default" establishSecurityContext="true" />
                    
</security>
                
</binding>
            
</wsHttpBinding>
        
</bindings>
    (3)客户端证书:
        这里我们要在配置文件里提供客户端的证书,也可以采用代码方式提供客户端证书。配置文件的方式比较简单。
直接在endpointBehaviors里设置以后,应用到终结点行为配置上就可以了。代码如下:
      <behaviors>
        
<endpointBehaviors>
          
<behavior name="endpointBehavior">
            
<clientCredentials>
              
<clientCertificate storeName="My"
                                 x509FindType
="FindBySubjectName"
                                 findValue
="WCFClientPK"
                                 storeLocation
="CurrentUser"/>
            
</clientCredentials>
          
</behavior>
        
</endpointBehaviors>
      
</behaviors>
    (4)测试代码:
      等待代码生成结束,我们这里就直接生成客户端代理类的实例来调用服务进行测试。这里客户端在调用服务以前,必须信任证书,这里我们使用了一段通用的代码,来建立TLS使用。这里会信任服务器的证书。代码如下:
 public static class  Util
    {
        
/// <summary>

        
///  Sets the cert policy.
        
/// </summary>

        public static void  SetCertificatePolicy()
        {
            ServicePointManager.ServerCertificateValidationCallback
                       
+=
 RemoteCertificateValidate;
        }

        
/// <summary>

        
///  Remotes the certificate validate.
        
/// </summary>

        private static bool  RemoteCertificateValidate(
           
object
 sender, X509Certificate cert,
            X509Chain chain, SslPolicyErrors error)
        {
            
// trust any certificate!!!

            System.Console.WriteLine("Warning, trust any certificate" );
            
return true
;
        }
    }
   客户端测试代码很简单,我们不需要提供客户端证书了,因为配置文件里已经设置完毕。接下来就是通过客户端代理来调用WCF服务。代码如下:
       static void Main(string [] args)
        {

            
try

            {
                Console.ForegroundColor 
=  ConsoleColor.Green;
                WCFClient.ClientProxy.WCFServiceClient wcfServiceProxy 
= new WCFClient.ClientProxy.WCFServiceClient("WSHttpBinding_IWCFService"
);
                
//通过代理调用SayHello服务

                string sName = "Frank Xu Lei  Message Certificate WSHttpBinding" ;
                
string sResult = string
.Empty;
                Util.SetCertificatePolicy();
                sResult 
=
 wcfServiceProxy.SayHello(sName);
                Console.WriteLine(
"Returned Result is {0}"
, sResult);
            }
            
catch
 (Exception e)
            {
               Console.WriteLine(
"Exception : {0}"
, e.Message);
            }
            
//For Debug

            Console.WriteLine("Press any key to exit" );
            Console.Read();
            
        }
    这里也可以使用代码来设置证书wcfServiceProxy.ClientCredentials.ClientCertificate.Certificate = new X509Certificate2(" WCFClientPK.pfx", "password"); WCFClientPK.pfx是导出的客户端证书的文件,包含密钥,密码为保护密码。
  (4)测试结果:
   启动宿主程序,然后启动客户端程序,客户端成功调用服务,宿主打印的消息。如图:
【5】总结
     Windows Communication Foundation (WCF) 服务和客户端。WCF安全机制都是依赖现有的安全体系和框架来完成的。这里的消息安全模式下的客户端证书身份验证,其实没有太大的变化。就是使用证书来验证客户端的有效性,合法性。
   (1)服务器需要一个证明服务器身份和有效的可用于TLS传输层安全的 X.509 证书,并且客户端必须信任此服务器证书。
   (2)客户端提交证书的方式与传输安全之证书验证方式一样,服务器端需要提供证书,但是不需要httpcfg.exe设置。
   (3)初始协商需要服务器证书来建立TLS连接,协商完毕以后,建立共享安全上下文,这里使用商定的加密算法对SOAP消息进行加密和签名。
   (4)如果你启用协商,而不把服务器证书在客户端设置信任,导入信任的办法机构,会出现SOAP安全协商失败的异常。
   (5)和消息安全模式的客户端证书验证,过程基本一样。差别只是在于客户端证书有效性验证,前者使用的是WCF框架自定来验证,这里我们使用的是自定义验证程序,重新实现了CustomX509CertificateValidator : X509CertificateValidator的Validate(X509Certificate2 certificate)方法。这里我们可以方便的定义具体的验证策略,也可以把证书信息存在特定的数据库,或者直接代码从证书存贮区域获取证书信息进行验证。
   (6)参考代码: 
/Files/frank_xl/6.5.WCFServiceSecurityDemoFrankXuLei_Message_CustomX.509Certificate_WSHttpBinding.rar   
     以上就是消息安全模式下的自定义X509证书的验证过程。这个安全系列的Demo程序基本结束。我会再整理一个总结性的文章给《WCF分布式安全开发实践》做个总结。 这些例子都可以扩展,比如更换绑定,等等,但是开发过程基本类似。。有什么建议可以提出,欢迎留言交流~
参考文章:
1.WCF分布式安全开发实践(11):消息安全模式之Certificate身份验证:Message_Certificate_WSHttpBinding 
2.WCF分布式安全开发实践(6):传输安全模式之自定义X509Certificate证书验证:Transport_X509Certificate_WSHttpBinding 
3.http://social.microsoft.com/Forums/zh-CN/wcfzhchs/thread/e1aa7bea-90d8-41e6-b91b-7addba44f8e3
4.WSE3.0构建Web服务安全(2):非对称加密、公钥、密钥、证书、签名的区别和联系以及X.509 证书的获得和管理




 本文转自 frankxulei 51CTO博客,原文链接:http://blog.51cto.com/frankxulei/320884,如需转载请自行联系原作者




相关文章
|
16天前
|
运维 Kubernetes 调度
阿里云容器服务 ACK One 分布式云容器企业落地实践
阿里云容器服务ACK提供强大的产品能力,支持弹性、调度、可观测、成本治理和安全合规。针对拥有IDC或三方资源的企业,ACK One分布式云容器平台能够有效解决资源管理、多云多集群管理及边缘计算等挑战,实现云上云下统一管理,提升业务效率与稳定性。
|
23天前
|
机器学习/深度学习 存储 运维
分布式机器学习系统:设计原理、优化策略与实践经验
本文详细探讨了分布式机器学习系统的发展现状与挑战,重点分析了数据并行、模型并行等核心训练范式,以及参数服务器、优化器等关键组件的设计与实现。文章还深入讨论了混合精度训练、梯度累积、ZeRO优化器等高级特性,旨在提供一套全面的技术解决方案,以应对超大规模模型训练中的计算、存储及通信挑战。
57 4
|
27天前
|
NoSQL Java 数据处理
基于Redis海量数据场景分布式ID架构实践
【11月更文挑战第30天】在现代分布式系统中,生成全局唯一的ID是一个常见且重要的需求。在微服务架构中,各个服务可能需要生成唯一标识符,如用户ID、订单ID等。传统的自增ID已经无法满足在集群环境下保持唯一性的要求,而分布式ID解决方案能够确保即使在多个实例间也能生成全局唯一的标识符。本文将深入探讨如何利用Redis实现分布式ID生成,并通过Java语言展示多个示例,同时分析每个实践方案的优缺点。
58 8
|
3月前
|
运维 Kubernetes 调度
阿里云容器服务 ACK One 分布式云容器企业落地实践
3年前的云栖大会,我们发布分布式云容器平台ACK One,随着3年的发展,很高兴看到ACK One在混合云,分布式云领域帮助到越来越多的客户,今天给大家汇报下ACK One 3年来的发展演进,以及如何帮助客户解决分布式领域多云多集群管理的挑战。
阿里云容器服务 ACK One 分布式云容器企业落地实践
|
4月前
|
存储 分布式计算 Hadoop
【揭秘Hadoop背后的秘密!】HDFS读写流程大曝光:从理论到实践,带你深入了解Hadoop分布式文件系统!
【8月更文挑战第24天】Hadoop分布式文件系统(HDFS)是Hadoop生态系统的关键组件,专为大规模数据集提供高效率存储及访问。本文深入解析HDFS数据读写流程并附带示例代码。HDFS采用NameNode和DataNode架构,前者负责元数据管理,后者承担数据块存储任务。文章通过Java示例演示了如何利用Hadoop API实现数据的写入与读取,有助于理解HDFS的工作原理及其在大数据处理中的应用价值。
126 1
|
4月前
|
机器学习/深度学习 人工智能 负载均衡
【AI大模型】分布式训练:深入探索与实践优化
在人工智能的浩瀚宇宙中,AI大模型以其惊人的性能和广泛的应用前景,正引领着技术创新的浪潮。然而,随着模型参数的指数级增长,传统的单机训练方式已难以满足需求。分布式训练作为应对这一挑战的关键技术,正逐渐成为AI研发中的标配。
214 5
|
4月前
|
存储 Kubernetes 监控
深入浅出分布式事务:理论与实践
在数字化时代的浪潮中,分布式系统如同星辰大海般浩瀚而深邃。本文将带你航行于这片星辰大海,探索分布式事务的奥秘。我们将从事务的基本概念出发,逐步深入到分布式事务的核心机制,最后通过一个实战案例,让你亲自体验分布式事务的魅力。让我们一起揭开分布式事务的神秘面纱,领略其背后的科学与艺术。
97 1
|
4月前
|
UED 存储 数据管理
深度解析 Uno Platform 离线状态处理技巧:从网络检测到本地存储同步,全方位提升跨平台应用在无网环境下的用户体验与数据管理策略
【8月更文挑战第31天】处理离线状态下的用户体验是现代应用开发的关键。本文通过在线笔记应用案例,介绍如何使用 Uno Platform 优雅地应对离线状态。首先,利用 `NetworkInformation` 类检测网络状态;其次,使用 SQLite 实现离线存储;然后,在网络恢复时同步数据;最后,通过 UI 反馈提升用户体验。
115 0
|
4月前
|
机器学习/深度学习 TensorFlow 数据处理
分布式训练在TensorFlow中的全面应用指南:掌握多机多卡配置与实践技巧,让大规模数据集训练变得轻而易举,大幅提升模型训练效率与性能
【8月更文挑战第31天】本文详细介绍了如何在Tensorflow中实现多机多卡的分布式训练,涵盖环境配置、模型定义、数据处理及训练执行等关键环节。通过具体示例代码,展示了使用`MultiWorkerMirroredStrategy`进行分布式训练的过程,帮助读者更好地应对大规模数据集与复杂模型带来的挑战,提升训练效率。
115 0
|
4月前
|
消息中间件 存储 Kafka
微服务实践之分布式定时任务
微服务实践之分布式定时任务