【读书笔记】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 = 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 = false;
23 using (CngKey key = CngKey.Import(pubKey, CngKeyBlobFormat.GenericPublicBlob))
24 using (var signingAlg =new ECDsaCng(key))
25 {
26 retValue = 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();
}
}
}
(五)代码访问安全性
在基于角色的安全性中,可以定义用户允许做什么。在基于代码的安全性中,可以规定代码能做什么。
1、第2级安全透明性
使用SecurityRules特性注解程序集,并设置SecurityRuleSet.Level2,以应用.NET4新增的级别。
[assembly: SecurityRules(SecurityRuleSet.Level2)]
2、权限
如果代码运行在沙盒中,沙盒就可以定义.NET权限,以定义代码允许执行的操作。权限是允许(或禁止)每个代码组执行的动作(例:读取文件系统中的文件)。.NET权限独立于操作系统权限。.NET权限仅由CLR验证。
(1)权限集
权限集是权限的集合。
(2)通过编程要求权限
程序集可以用声明或编程的方式要求权限。
(3)使用沙盒API包含未授权的代码
(五)使用证书发布代码
可以利用数字证书来对程序集进行签名,让软件的消费者验证软件发布者的身份。
博客园-本文作者(好先生FX http://www.cnblogs.com/hxsfx)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。