首页 > 代码库 > 【读书笔记】C#高级编程 第二十二章 安全性

【读书笔记】C#高级编程 第二十二章 安全性

(一)身份验证和授权

安全性的两个基本支柱是身份验证和授权。身份验证是标识用户的过程,授权在验证了所标识用户是否可以访问特性资源之后进行的。

 

1、标识和Principal

使用标识可以验证运行应用程序的用户。Principal是一个包含用户的标识和用户所属角色的对象。

AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);

 
var principal = WindowsPrincipal.Current as WindowsPrincipal;
var identity = principal.Identity as WindowsIdentity;
Console.WriteLine("身份类型:{0}",identity.ToString());
Console.WriteLine("名称:{0}",identity.Name);
Console.WriteLine("角色是否为用户:{0}",principal.IsInRole(WindowsBuiltInRole.User));
Console.WriteLine("角色是否为超级管理员:{0}", principal.IsInRole(WindowsBuiltInRole.Administrator));
Console.WriteLine("是否身份验证:{0}",identity.IsAuthenticated);
Console.WriteLine("身份验证类型:{0}", identity.AuthenticationType);
Console.WriteLine("是否匿名:{0}", identity.IsAnonymous);
Console.WriteLine("账户标记:{0}", identity.Token);

 

2、角色

基于角色的安全性可以很好地解决资源访问问题。

 

3、声明基于角色的安全性

如果使用非本地User组中的账户运行以下代码,ShowMessage()方法将会抛出一个异常。

static void Main(string[] args)
{
    AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
 
    try
    {
        ShowMessage();
    }
    catch (SecurityException exception)
    {
        Console.WriteLine("捕捉安全异常:({0})",exception.Message);
        Console.WriteLine("当前主体应放置入本地用户组");
    }
    Console.ReadKey();
}
[PrincipalPermission(SecurityAction.Demand,Role ="BUILTIN\\Users")]
private static void ShowMessage()
{
    Console.WriteLine("当前主体已登录本地");
    Console.WriteLine("(本地用户组中成员是)");
}

 

4、声称

除了使用角色之外,还可以使用声称访问用户信息。声称与实体有关,描述实体的能力。实体通常是用户,也可以是应用程序。能力描述了实体允许执行的操作。这样声称比角色模型灵活得多。

var principal = WindowsPrincipal.Current as ClaimsPrincipal;
 
Console.WriteLine();
Console.WriteLine("获取包含所有声明的集合,这些声明都来自于此声明主体关联的声明标识符。");
foreach (var claim in principal.Claims)
{
    Console.WriteLine("主题:{0}", claim.Subject)
    Console.WriteLine("颁发者:{0}", claim.Issuer);
    Console.WriteLine("声称类型:{0}", claim.Type);
    Console.WriteLine("值类型:{0}", claim.ValueType);
    Console.WriteLine("值:{0}", claim.Value);
    foreach (var prop in claim.Properties)
    {
        Console.WriteLine("\t属性:{0} {1}", prop.Key, prop.Value);
    }
    Console.WriteLine();
}

 

5、客户端应用程序服务

代码过长不贴文章里

服务端源码:Download

客户端源码:Download

在运行之前需要注意的是:客户端的app.config要修改 serviceUri的连接位置为服务端运行的连接,例子:源代码中的serviceUri为serviceUri="http://localhost:59514/Role_JSON_Appservice.axd",要修改为你运行网站以后的链接地址(假设为http://localhost:9999/)加Role_JSON_Appservice.axd,最终serviceUri="http://localhost:9999/Role_JSON_Appservice.axd"。

 

(二)加密

1、签名

 1 internal static CngKey aliceKeySignature;
 2 internal static byte[] alicePubKeyBlob;
 3 static void Main(string[] args)
 4 {
 5     CreateKeys();
 6  
 7     byte[] aliceData = http://www.mamicode.com/Encoding.UTF8.GetBytes("Alice");
 8     byte[] aliceSignature = CreateSignatrue(aliceData,aliceKeySignature);
 9  
10     Console.WriteLine("Alice创建了签名:{0}",Convert.ToBase64String(aliceSignature));
11  
12     if (VerifySignature(aliceData,aliceSignature,alicePubKeyBlob))
13     {
14         Console.WriteLine("Alice的签名验证成功");
15     }
16  
17     Console.ReadKey();
18 }
19  
20 private static bool VerifySignature(byte[] data, byte[] signature, byte[] pubKey)
21 {
22     bool retValue = http://www.mamicode.com/false;
23     using (CngKey key = CngKey.Import(pubKey, CngKeyBlobFormat.GenericPublicBlob))
24     using (var signingAlg =new ECDsaCng(key))
25     {
26         retValue =http://www.mamicode.com/ signingAlg.VerifyData(data, signature);
27         signingAlg.Clear();
28     }
29     return retValue;
30 }
31  
32 private static byte[] CreateSignatrue(byte[] data, CngKey key)
33 {
34     byte[] signature;
35     using (var signingAlg=new ECDsaCng(key))
36     {
37         signature = signingAlg.SignData(data);
38         signingAlg.Clear();
39     }
40     return signature;
41 }
42 
43  
44 private static void CreateKeys()
45 {
46     aliceKeySignature = CngKey.Create(CngAlgorithm.ECDiffieHellmanP256);
47     alicePubKeyBlob = aliceKeySignature.Export(CngKeyBlobFormat.GenericPublicBlob);
48 }

 

 

2、交换秘钥和安全传输

使用DiffieHellman算法交换一个对称秘钥,以进行安全的传输。

 

(三)资源的访问控制

在操作系统中,资源都使用访问控制列表(ACL)来保护。资源有一个关联的安全描述符。安全描述符包含了资源拥有者的信息,并引用了两个访问控制列表:自由访问控制列表(DACL,确定谁拥有访问权)和系统访问控制列表(SACL,确定安全事件日志的审核规则)。ACL包含一个访问控制项(ACE,包含类型、安全标识符和权限)列表。在DACL中,ACE的类型可以是允许访问或拒绝访问。可以用文件设置和获得的权限是创建、读取、写入、删除、修改、改变许可和获得许可。

获取一个文件的访问控制列表:

static void Main(string[] args)
{
    string fileName = @"C:\Users\Administrator\Desktop\1.txt";
    using (FileStream fs=File.Open(fileName,FileMode.Open))
    {
        FileSecurity securityDescriptor = fs.GetAccessControl();
        AuthorizationRuleCollection rules = securityDescriptor.GetAccessRules(true, true, typeof(NTAccount));
 
        foreach (AuthorizationRule rule in rules)
        {
            var fileRule = rule as FileSystemAccessRule;
            Console.WriteLine("访问类型:{0}",fileRule.AccessControlType);
            Console.WriteLine("权限:{0}",fileRule.FileSystemRights);
            Console.WriteLine("身份:{0}",fileRule.IdentityReference.Value);
            Console.WriteLine();
        }
    }
}

 

修改访问权限参考:http://www.cnblogs.com/wolf-sun/p/4591734.html

 

 

(五)代码访问安全性

在基于角色的安全性中,可以定义用户允许做什么。在基于代码的安全性中,可以规定代码能做什么。

1、第2级安全透明性

使用SecurityRules特性注解程序集,并设置SecurityRuleSet.Level2,以应用.NET4新增的级别。

[assembly: SecurityRules(SecurityRuleSet.Level2)]

 

2、权限

如果代码运行在沙盒中,沙盒就可以定义.NET权限,以定义代码允许执行的操作。权限是允许(或禁止)每个代码组执行的动作(例:读取文件系统中的文件)。.NET权限独立于操作系统权限。.NET权限仅由CLR验证。

 

(1)权限集

权限集是权限的集合。

 

(2)通过编程要求权限

程序集可以用声明或编程的方式要求权限。

 

(3)使用沙盒API包含未授权的代码

 

 

(五)使用证书发布代码

可以利用数字证书来对程序集进行签名,让软件的消费者验证软件发布者的身份。

【读书笔记】C#高级编程 第二十二章 安全性