代码改变世界

安全探索——.NET 3.0 中的标识模型(1)

2009-03-16 23:14 by G yc {Son of VB.NET}, ... 阅读, ... 评论, 收藏, 编辑

(写在之前,唉,这篇文章,真是出产的拖泥带水。搁置了到现在才写出来,原因也是很有很多了,不过 自己也是主因吧。)

上回说完了 .NET 中的角色模型,作为.NET 的基础安全模型,其已经深入大部分地方,并且也在后续版本中提供了支持。但即使如此,角色模型,也有不适用的地方。

(在这里说个题外话,虽然.NET自带的角色安全,但其并不适合直接使用,虽然在小应用上看不出什么,但在大范围的地方, 就会有些局限。如果参考一下Windows的安全结构,就能发现,虽然使用的角色,但实际控制访问的是 “访问控制列表(ACL)” ,因此,要想有更好的灵活性,应该自己设计一个ACL出来,然后在结合自带的角色 就应该比原来好了——这仅是我个人的感觉,有问题话可以和我讨论)

你可能要问,角色安全有什么地方不使用?怎么不灵活?

实际上,我只能说,三个字:“不知道!” (板砖飞来。。。。。。)

。。。。。。。

—__—!

 

好吧,我现在知道的不多。大致了解到的。

虽然角色安全不错,但在分布式的应用程序后出现了一些维护问题。

 

例如: 假设 网站 A 和网站 B 之间,做了合作,希望共享用户登录信息(即可以在网站B 上使用 网站 A的帐号登录),但不能整合数据库(因为是2家)。

如果是角色模式的话,就需要在 A站点上,使用 网站B的用户信息建立相同的账户,同样也需要在B站点上 做相同的操作。

那么现在,如果,网站 A 的用户 UserA 注销了(删了) 那么网站B 上对应的 UserA 会怎么样呢?

答案是:直到管理员来清除之前,UserA 还存在。

 

现在你应该知道了,如果使用角色模型话,在这种情况下, 维护起来,将会变得复杂。为此,在WCF中引入了新的安全模型 —— 标识模型。

 

标识模型是基于声明的系统。声明描述与系统中某个实体关联的功能,该实体通常为该系统中的某个用户。与给定实体关联的声明集可视为密钥。特定的声明定义该密钥的形状,类似于现实中用于打开门锁的钥匙。声明用于获取访问资源的权限。通过比较访问该资源所需的声明和与试图进行访问的实体关联的声明,确定对给定的受保护资源的权限。

声明是针对特定值的权限表达式。权限可能类似于“Read”(读取)、“Write”(写入)或“Execute”(执行)。值可以是数据库、文件、邮箱或属性。声明还具有声明类型。声明类型和权限的组合提供用于指定针对该值的功能的机制。例如,如果一个声明的类型为“File”(文件),对值“Biography.doc”具有“Read”(读取)权限,则指示与此声明关联的实体具有读取 Biography.doc 文件的权限。一个声明的类型为“Name”,对值“Martin”具有“PossessProperty”权限,指示与这种声明关联的实体拥有值为“Martin”的 Name 属性。

标识声明

一种特定权限是标识权限。拥有此权限的声明对实体的标识进行声明。例如,类型为“user principal name”(用户主要名称,UPN)、值为“someone@example.com”、权限为“Identity”(标识)的声明指示特定域中的特定标识。

System 标识声明

标识模型定义一个标识声明:System.System 标识声明指示实体为当前应用程序或系统。(这个是系统自带的静态常量)

声明集

代表标识的声明的模型很重要,因为总是由系统中的某个实体颁发声明,即使该实体最终是某种“自我”的概念。声明以集的形式组合在一起,每个集具有一个颁发者。颁发者只是一个声明集。这样一种递归关系最终必须结束,任何声明集都可以是其自己的颁发者。

下图显示了一个包含三个声明集的示例,其中一个声明集以另一个声明集为其颁发者,而那个声明集又以 System 声明集为其颁发者。因此,声明集形成一个任意深度的层次结构。

clip_image001[4]

多个声明集具有相同的颁发声明集,如下图所示。

clip_image002[4]

除了是自已的颁发者的声明集之外,标识模型绝不支持声明集形成循环。这样永远不会出现声明集 A 由声明集 B 颁发,而声明集 B 本身又由声明集 A 颁发的情况。而且,标识模型也绝不支持声明集具有多个颁发者。如果两个或多个颁发者都必须颁发某个给定的声明集,那么必须使用多个声明集,使每个声明集包含相同的声明,但具有不同的颁发者。

 

实际上,WCF中的安全模型改用了标识模型(虽然也兼容以前的主体)。可以通过调用OperationContext的ServiceSecurityContext 获得当前 安全上下文 来检查标识。

事例是一个使用用户名和密码模式认证的WCF服务(如果不使用用户名/密码模式, 默认使用是Windows 安全),实现过程如下:

1、生成临时证书

makecert.exe -sr LocalMachine -ss MY -a sha1 -n CN=MyServiceTestCA -sky exchange -pe

2、修改Config文件

a.修改服务行为
将userNameAuthentication的userNamePasswordValidationMode设置成MembershipProvider并设定membershipProviderName 使用的Provider的名字 “AspNetSqlMembershipProvider”
之后设置服务证书,这里指定的是查找指纹

 

               <behavior name="FormsIdentityandRolePrincipal.IdentityServiceBehavior">
                  
<serviceMetadata httpGetEnabled="true" />
                  
<serviceDebug includeExceptionDetailInFaults="false" />
                  
<serviceCredentials>
                    
<clientCertificate>
                      
<authentication certificateValidationMode="None" />
                    
</clientCertificate>
                    
<serviceCertificate findValue="7d 30 43 4c db 47 96 90 89 1b 24 f3 d9 f9 36 99 98 91 6d b9"
                      storeLocation
="LocalMachine" storeName="TrustedPeople" x509FindType="FindByThumbprint" />
                    
<userNameAuthentication userNamePasswordValidationMode="MembershipProvider"
                      membershipProviderName
="AspNetSqlMembershipProvider" />
                  
</serviceCredentials>
                  
<serviceAuthorization principalPermissionMode="UseAspNetRoles"
                    roleProviderName
="AspNetSqlRoleProvider" />
                
</behavior>

 

b.修改服务标识
将服务的EndPoint的DNS 设置成证书中的值 (如果不做这个话,在程序运行后,会报错,并提示修改)

 

             <service behaviorConfiguration="FormsIdentityandRolePrincipal.IdentityServiceBehavior"
                name
="FormsIdentityandRolePrincipal.IdentityService">
                
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="IdentityBinding"
                  contract
="FormsIdentityandRolePrincipal.IIdentityService">
                  
<identity>
                    
<dns value="MyServiceTestCA" />
                  
</identity>
                
</endpoint>
                
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
              
</service>

 

到这为止服务端的更改已经完成了。

但由于我们用的是临时证书,因此,客户都调用时需要加入以下语句

 

 

client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode =X509CertificateValidationMode.None

 

否者,会提示建立证书信任链失败的错误。

 

还有,如果HOST在IIS中,会提示找不到密钥。实际原因是IIS工作进程没有对RSA 密钥的磁盘访问权限。需要手动设置

这个位置在 C:\Documents and Settings\All Users\Application Data\Microsoft\Crypto\RSA 或 C:\Users\All Users\Application Data\Microsoft\Crypto\RSA\ (Win Vista/2008)

可以只为个别文件设置访问权限,只要有读权限,就可以工作了。

 

clip_image003[6]

clip_image004[5]