这部分主要涉及企业级应用的安全问题,一般来说安全框架主要提供3个典型的安全行为:认证、授权和审核。除了典型的安全问题,对于一个以消息作为通信手段的分布式应用,还需要考虑消息保护(Message Protection)问题,消息保护机制主要包括签名和加密,前者保证消息的一致性,后者保证消息的机密性。

在介绍传输安全之前,介绍几个在分布式应用中常见的传输安全隐患:消息的篡改,敏感信息的泄露,钓鱼攻击,重放攻击。因此对于WCF来说,其传输安全主要涉及认证、消息一致性和机密性三个主题,认证不仅包括服务器对客户端的认证,也包括客户端对服务的身份验证,即双向验证,消息一致性保证消息的内容在传输过程中不被篡改,机密性确保只有希望的消息接收方才能读取其中内容。WCF为了应对这些问题,提供了两种不同的安全模式,Transport安全和Message安全。

Transport安全:基于传输层协议的安全机制,其中TLS/SSL是最常用的方式,常说的HTTPS其实就是将HTTP和TLS/SSL结合在一起,对于WCF来说,所有的基于HTTP协议的绑定在采用Transport安全的情况,对于NetTcpBinding来说,也同样支持,即组合使用TCP和TLS/SSL。该协议体系可以解决如下两个问题:客户端对服务端的验证;通过对传输层传输的数据段进行加密确保消息的机密性。接下来通过一个例子,来描述连接HTTPS的过程

步骤1:客户端向HTTPS站点发送协商请求,该请求中包含客户端所能够支持的加密算法列表。

步骤2:HTTPS站点从加密算法列表中选择自己支持的并且安全级别最高的算法,连同绑定到该站点的数字证书(X.509证书)一并发个客户端。

步骤3:客户端接受到站点发回的数字证书后,通过验证证书进而确定站点身份,在验证成功的情况下,客户端会生成一个随机数,作为会话密钥(Session Key),缓存在客户端。客户端会采用站点发回的加密算法,利用从证书中提取的公钥进行加密。加密后的会话密钥发送给站点后,站点使用自己的私钥解密,至此客户端和服务端具有一个只有彼此知晓的会话密钥,所有请求消息和回复消息均用其加解密。(由于非对称加密和数字签名的知识相对基础,就不详细介绍了,如果需要,可以参见http://www.cnblogs.com/wanliwang01/p/aspnet_webapi_base01.html

Transport安全模型的最大的优点就是高性能,虽然在消息交换前需要一个协商的过程,不过可以通过硬件加速。其不足是:依赖于集体的传输协议;只能提供点到点的安全,即客户端直接连接到服务端的场景,如果需要增加消息路由的中间节点,也无法使用了;如果选择该模型,意味着需要在传输层解决对客户端的认证,但相应方案较少。

Message安全:直接将安全策略的目标对象转移到消息本身,通过对消息进行签名、加密实现消息安全传输。其不依赖与具体的协议,并可以提供端到端的安全,其是一种应用层的协议,配套方案很多。WCF的Message安全模式是围绕4个标准的WS-*规范建立的,包括WS-Security、WS-Trust、WS-Secure Conversation和WS-Security Policy。

Mixed安全:由于前两者都有着自己的优点和缺点,因此综合考虑,存在如下的解决方案:消息的一致性、机密性和客户端对服务端的认证通过Transport安全模式实现,而服务端对客户端的认证采用Message安全模式。

认证和凭证:常见的认证方式包括用户名密码认证,例如Windows认证、Membership模块、自定义认证等;NTLM,windows认证是实现单点登录的理想方式,其通过账号密码得到一个凭证,在凭证超时前,可以用于任何应用;Kerberos,其比NTLM更加高效,安全,涉及客户端、服务端和密钥分发中心3方,整个过程包括获得"认购权证"、通过"认购权证"购买"入场券"、凭票入场;数字证书认证,采用信任链的方式实现。

之前介绍的主要是安全概念,接下来则在WCF中,安全的具体实践。以最简单的BasicHttpBinding为例,其SecurityMode包括None、Transport、Message、TransportWithMessageCredential(等价Mixed)和TransportCredential。对于其中的Transport安全来说,其又包含6中客户端凭证类型,None、Basic、Digest、Ntlm、Windows、Certificate。比如如下两个基于basicHttpBinding配置,前者基于Message模式+X.509证书凭证,后者采用Mixed模式+用户名/密码凭证。其他的绑定类型虽然有不少差异,但原理一致,在这就不一一展开了。

 <system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="messageBinding">
<security mode="Message">
<message clientCredentialType="Certificate" negotiateServiceCredential="false"/>
</security>
</binding>
<binding name="transportWithMessageCredentialBinding">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
</system.serviceModel>

Tip:可以通过设置message的协商属性来决定是否需要协商。

之前也曾提到,对于认证来说包括服务端认证和客户端认证,涉及ServiceCredentials和ClientCredentials两大类凭证。首先介绍服务认证,常见的服务端认证配置如下所示。

 <system.serviceModel>
<services>
<service name="Sory.CoreFramework.Service.EmployeeService" behaviorConfiguration="serviceCertificateBehavior"></service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name ="serviceCertificateBehavior">
<serviceCredentials>
<serviceCertificate storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" findValue="Xionger-PC"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>

通过MakeCert.exe工具创建一个证书

Makecert –n "CN=RootCA" –r –sv C:\Root.pvk C:\RootCA.cer
Makecert –n "CN=Xionger-PC" –ic C:\RootCA.cer –iv C:\RootCA.pvk –sr
LocalMachine –ss My –pe –sky exchange

在WCF中,服务身份通过ServiceEndpoint表示,在Windows认证下,通常使用SPN(Service Principal Name)和UPN(User Principal Name)两种,如果采用X.509证书,可以通过X509CertificateEndpointIdentity和RsaEndpointIdentity表示。在服务引用或使用SvcUtil.exe导入元数据时,会将服务身份标识自动写入配置中,如下所示。

 <system.serviceModel>
<client>
<endpoint>
<identity>
<userPrincipalName value="xionger@126.com"/>
<servicePrincipalName value="host/xionger-PC"/>
<certificateReference storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" findValue="xionger-PC"/>
</identity>
</endpoint>
</client>
</system.serviceModel>

客户端认证主要包含三种方式:Windows,其基于SSPI,这部分曾经在连接字符串中见到;用户名,支持Windows、Membership、Custom三种,尤其是Membership的使用,请见接下来的代码示例;X.509证书,在客户端可以通过ChannelFactory.Credentials.ClientCertificate.SetCertificate方法设置,此外证书与Windows账号映射可以通过<clientCertificate>节中<authentication mapClientCertificateToWindowsAccount="true">设置。

 客户端认证,用户名方式的MembershipProvider
<system.web>
<membership defaultProvider="myProvider">
<providers>
<add name="myProvider" type="System.Web.Security.SqlMembershipProvider, System.Web" connectionStringName="AspNetDb"
applicationName="MembershipAuthenticationDemo" requiresQuestionAndAnswer="false"/>
</providers>
</membership>
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="membershipAuthentication">
<serviceCredentials>
<serviceCertificate/>
<userNameAuthentication userNamePasswordValidationMode="MembershipProvider" membershipProviderName="myProvider"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>

消息保护,这部分保证消息的一致性和机密性,在WCF中,通过消息保护级别的概念来设置,包括None、Sign和EncryptAndSign三个级别,默认为EncryptAndSign级别,这部分的功能是通过之前章节介绍过的SecurityBindingElement的相关类来实现的。此外,为了减少多次认证的开销,还有一个关于安全会话的概念,通过配置Binding->security->message中的establishSecurityContext属性来实现,可以使多次消息交换使用同一个会话信道,这部分内容很多,还需要足够的实践。不过不管是什么平台和技术,基本的安全概念是相似的,在传输过程中,就是认证、数据一致性和机密性。

在介绍完认证Authentication后,就进入了授权的模块,当然还包含所有安全过程的审核工作。对于整个.NET体系来说,其用户和角色等信息都是通过身份Identity和安全主体Principal两个概念来表述的。前者包含用户的基本令牌信息,可以是WindowsIdentity、GenericIdentity和X509三种类型,这儿值得一提的是GenericIdentity,如果采用自定义认证方式时,会选择GenericIdentity这个类型。在服务安全开启的情况下,服务端在经过认证后会创建一个上下文用于存储基于当前服务调用相关的安全相关的信息,其关系如下表所示。

None

Windows

UserName

Certificate

windows

Membership

Custom

Default

Windows Account Mapping

Generic Identity

Windows Identity

Windows Identity

Generic Identity

Generic Identity

X509 Identity

Windows Identity

接下来,介绍主体的概念,简单来说,主体是对标识的封装,增加了所属角色这一关联属性。在windows中,安全主体被保存在TLS线程本地变量上,可以通过Thread.CurrentPrincipal获取。

常见授权方式包括Windows用户组授权、ASP.NET Roles授权和自定义授权方式三种。Windows授权相对简单,设置behavior.PrincipalPermissionMode= PrincipalPermissionMode.UseWindowsGroups即可,通过在方法上添加[PrincipalPermission(SecurityAction.Demand, Role="administrators")]控制windows下用户的操作,这部分还涉及一个Impersonation身份模拟的概念,和win32有关比较复杂,就不细致介绍了。对于ASP.NET Roles提供程序来说,System.Web.Security.RoleProvider抽象类是其基础,主要使用其子类SqlRoleProvider来处理,其配置如下所示。

 <connectionStrings>
<add name="aspNetDb" connectionString="..." providerName="System.Data.SqlClient"/>
</connectionStrings>
<system.web>
<roleManager enabled="true" defaultProvider="SqlRoleProvider">
<providers>
<add name="sqlRoleProvider" type="System.Web.Security.SqlRoleProvider, System.Web" connectionStringName="aspNetDb" applicationName="AspRolesAuthorizationDemo"/>
</providers>
</roleManager>
</system.web>
<system.serviceModel>
<services>
<service behaviorConfiguration="aspNetRolesAuthorization"></service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="aspNetRolesAuthorization">
<serviceAuthorization principalPermissionMode="UseAspNetRoles" roleProviderName="sqlRoleProvider"></serviceAuthorization>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>

此外,还有自定义的授权方式,其设计AuthorizationPolicy、ServiceAuthorization、Claim和ClaimSet等多个类型,实现很复杂,需要时再查书实践。

最后介绍安全审核部分,这部分其实和windows的事件管理器关系非常紧密,最简单的配置就是在behavior节中,设置<serviceSecurityAudit auditLogLocation="Application" messageAuthenticationAuditLevel="SuccessOrFailure">。

虽然是这样的浏览学习,不过也算是圆梦之旅,棒棒哒。

参考资料:

[1]蒋金楠. WCF全面解析[M]. 上海:电子工业出版社, 2012.

快速入门系列--WCF--07传输安全、授权与审核的更多相关文章

  1. 快速入门系列--WebAPI--01基础

    ASP.NET MVC和WebAPI已经是.NET Web部分的主流,刚开始时两个公用同一个管道,之后为了更加的轻量化(WebAPI是对WCF Restful的轻量化),WebAPI使用了新的管道,因 ...

  2. [转]快速入门系列--WebAPI--01基础

    本文转自:http://www.cnblogs.com/wanliwang01/p/aspnet_webapi_base01.html ASP.NET MVC和WebAPI已经是.NET Web部分的 ...

  3. 快速入门系列--WebAPI--03框架你值得拥有

    接下来进入的是俺在ASP.NET学习中最重要的WebAPI部分,在现在流行的互联网场景下,WebAPI可以和HTML5.单页应用程序SPA等技术和理念很好的结合在一起.所谓ASP.NET WebAPI ...

  4. 快速入门系列--MVC--01概述

    虽然使用MVC已经不少年,相关技术的学习进行了多次,但是很多技术思路的理解其实都不够深入.其实就在MVC框架中有很多设计模式和设计思路的体现,例如DependencyResolver类就包含我们常见的 ...

  5. 快速入门系列--WebAPI--04在老版本MVC4下的调整

    WebAPI是建立在MVC和WCF的基础上的,原来微软老是喜欢封装的很多,这次终于愿意将http编程模型的相关细节暴露给我们了.在之前的介绍中,基本上都基于.NET 4.5之后版本,其System.N ...

  6. vue 快速入门 系列 —— vue-cli 上

    其他章节请看: vue 快速入门 系列 Vue CLI 4.x 上 在 vue loader 一文中我们已经学会从零搭建一个简单的,用于单文件组件开发的脚手架:本篇,我们将全面学习 vue-cli 这 ...

  7. vue 快速入门 系列 —— vue-cli 下

    其他章节请看: vue 快速入门 系列 Vue CLI 4.x 下 在 vue loader 一文中我们已经学会从零搭建一个简单的,用于单文件组件开发的脚手架:本篇,我们将全面学习 vue-cli 这 ...

  8. 快速入门系列--MVC--02路由

    现在补上URL路由的学习,至于蒋老师自建的MVC小引擎和相关案例就放在论文提交后再实践咯.通过ASP.NET的路由系统,可以完成请求URL与物理文件的分离,其优点是:灵活性.可读性.SEO优化.接下来 ...

  9. 快速入门系列--MVC--07与HTML5移动开发的结合

    现在移动互联网的盛行,跨平台并兼容不同设备的HTML5越来越盛行,很多公司都在将自己过去的非HTML5网站应用渐进式的转化为HTML5应用,使得一套代码可以兼容不同的物理终端设备和浏览器,极大的提高了 ...

  10. WPF快速入门系列(4)——深入解析WPF绑定

    一.引言 WPF绑定使得原本需要多行代码实现的功能,现在只需要简单的XAML代码就可以完成之前多行后台代码实现的功能.WPF绑定可以理解为一种关系,该关系告诉WPF从一个源对象提取一些信息,并将这些信 ...

随机推荐

  1. core的生成

    ubuntu12.04,默认无法生成core文件 输入ulimit -c 1024就ok了 列一下ulimit的参数,貌似这个命令是系统性能控制相关的,先不管了. 表 1. ulimit 参数说明 选 ...

  2. 模拟时钟(AnalogClock)和数字时钟(DigitalClock)

    Demo2\clock_demo\src\main\res\layout\activity_main.xml <LinearLayout xmlns:android="http://s ...

  3. http://blog.sina.com.cn/s/blog_4c3b6a070100etad.html

    http://blog.sina.com.cn/s/blog_4c3b6a070100etad.html

  4. iOS开发-NSOperation与GCD区别

    Mac OS X 10.6及iOS4.0之后导入了可以使全体线程更高效运行,并且使并行处理应用更易开发的架构,GCD(Grand Central  Dispatch),同时引入的还有Run Loop, ...

  5. 关于div弹出层的实际应用心得

    今天本人要做一个点击弹出的功能,因为这个功能是最后做的,所以写的时候很纠结, 因为本人小菜一枚, 开始尝试用 position:relative:来做一试不行呀 ,因为用这个来做的话 会打乱原有的布局 ...

  6. 快速学习C语言二: 编译自动化, 静态分析, 单元测试,coredump调试,性能剖析

    上次的Hello world算是入门了,现在学习一些相关工具的使用 编译自动化 写好程序,首先要编译,就用gcc就好了,基本用法如下 gcc helloworld.c -o helloworld.o ...

  7. LIstView 滚动 异步 加载更多 mono for android ScrollStateChanged ScrollState.Idle; Fling;TouchScroll

    今天项目需要实现一下列表的分页加载 找到了Listview的ScrollStateChanged方法. 和大家分享一下 //先找到Listview ListView order = FindViewB ...

  8. C#函数式编程之可选值

    在我们的实际开发中已经会遇到可空类型,而在C#中自从2.0之后就提供了可空类型(Nullable<T>),普通的值类型是不可以赋值为NULL,但是在类型的后面加上问号就变成了可空类型,这样 ...

  9. 【转】EntityFramework(EF)贪婪加载和延迟加载的选择和使用

    原谅:http://www.weixq.cn/Article/Detail/906 贪婪加载:顾名思议就是把所有要加载的东西一 次性读取 using (var context = new MyDbCo ...

  10. 【读书笔记】.Net并行编程高级教程(二)-- 任务并行

    前面一篇提到例子都是数据并行,但这并不是并行化的唯一形式,在.Net4之前,必须要创建多个线程或者线程池来利用多核技术.现在只需要使用新的Task实例就可以通过更简单的代码解决命令式任务并行问题. 1 ...