.NET(C#)中不同级别的安全透明代码对类型的影响


测试代码将测试一个方法和类默认在全部信任权限下和部分信任权限下的代码类型。

上面说的默认就是指未加入其他安全透明类型的特性。

代码类型可以是:

  1. 透明代码(Transparent Code)
  2. 关键代码(Critical Code)
  3. 可靠关键代码(Safe-critical Code)

测试这三项用到Type类和MethodInfo类中的IsSecurityTransparent,IsSecurityCritical和IsSecuritySafeCritical。注意这些属性不是从它们的共同基类MemberInfo中继承来的,因为某些MemberInfo比如属性(Property)是不属于可标识的。(但是属性的get和set可以,他们属于方法)

 

至于模拟部分受信任代码,我们通过创建一个给予部分权限的应用程序域然后在该应用程序域中执行代码。

 

测试代码框架:

    using System;

    using System.Reflection;

    using System.Security;

    using System.Security.Permissions;

 

    class Program

    {

        static void Main()

        {

            //在全部受信任环境中运行

            test();

 

            //创建部分受信任应用程序域

            var d = CreateSandbox();

            //在部分受信任环境中运行

            d.DoCallBack(() =>

                {

                    test();

                });

        }

 

        //测试方法

        static void test()

        {

            if (AppDomain.CurrentDomain.IsFullyTrusted)

                Console.WriteLine("全部受信任环境");

            else

                Console.WriteLine("部分受信任环境");

            var method = MethodBase.GetCurrentMethod();

            //判断方法

            Console.WriteLine("默认方法 - 透明代码:{0,-5} 关键代码:{1,-5} 关键可靠代码:{2}",

                method.IsSecurityTransparent,

                method.IsSecurityCritical,

                method.IsSecuritySafeCritical);

            //判断类型

            Console.WriteLine("默认类型 - 透明代码:{0,-5} 关键代码:{1,-5} 关键可靠代码:{2}\n",

                method.DeclaringType.IsSecurityTransparent,

                method.DeclaringType.IsSecurityCritical,

                method.DeclaringType.IsSecuritySafeCritical);

        }

 

        //创建部分受信任环境

        static AppDomain CreateSandbox()

        {

            //初始化空的权限集

            var pset = new PermissionSet(PermissionState.None);

            //添加Execution(执行)安全权限,没有此权限代码不会执行

            pset.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));

            //添加其他权限

            pset.AddPermission(new FileIOPermission(PermissionState.Unrestricted));

            pset.AddPermission(new UIPermission(PermissionState.Unrestricted));

            pset.AddPermission(new ReflectionPermission(PermissionState.Unrestricted));

 

            //必须设置AppDomainSetup.ApplicationBase,否则无法成功创建应用程序域

            var adSetup = new AppDomainSetup();

            adSetup.ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;

 

            var domain = AppDomain.CreateDomain("新的AppDomain",

                null,

                adSetup,

                pset);

 

            return domain;

        }

    }

 

 

在级别2中的结果是这样的(.NET 4.0后(包括4.0)CLR默认会使用级别2类型)

运行结果:

全部受信任环境

默认方法 - 透明代码:False 关键代码:True  关键可靠代码:False

默认类型 - 透明代码:False 关键代码:True  关键可靠代码:False

 

部分受信任环境

默认方法 - 透明代码:True  关键代码:False 关键可靠代码:False

默认类型 - 透明代码:True  关键代码:False 关键可靠代码:False

可以看出来,在级别2中,全部信任环境下,类型和成员都是关键代码。而部分信任环境下,它们都是透明代码。

 

 

如果手动在程序集中添加SecurityTransparent或AllowPartiallyTrustedCallers,则默认全部是透明代码:

using System.Security;

//[assembly: SecurityRules(SecurityRuleSet.Level1)]

//[assembly: SecurityCritical]

//.NET 4.0 +

[assemblyAllowPartiallyTrustedCallers]

//或者

[assemblySecurityTransparent]

运行结果:

全部受信任环境

默认方法 - 透明代码:True  关键代码:False 关键可靠代码:False

默认类型 - 透明代码:True  关键代码:False 关键可靠代码:False

 

部分受信任环境

默认方法 - 透明代码:True  关键代码:False 关键可靠代码:False

默认类型 - 透明代码:True  关键代码:False 关键可靠代码:False

即便是全部信任环境,默认仍是透明代码。

 

 

在级别1中,首先得通过SecurityRules特性调节CLR运行程序集时采用级别1策略。

using System.Security;

[assemblySecurityRules(SecurityRuleSet.Level1)]

然后再运行程序,结果:

全部受信任环境

默认方法 - 透明代码:False 关键代码:True  关键可靠代码:True

默认类型 - 透明代码:True  关键代码:False 关键可靠代码:False

 

部分受信任环境

默认方法 - 透明代码:True  关键代码:False 关键可靠代码:False

默认类型 - 透明代码:True  关键代码:False 关键可靠代码:False

 

在受限环境下,同级别1一样都一律视为透明代码。但在全部信任环境下,类型会被视为透明代码。但方法(或者其他类型成员)会被视为关键可靠代码(SecuritySafeCritical),由于是SecuritySafeCritical所以一定也属于SecurityCritical,因此关键代码也是True。

 

所以在级别1中,全部信任环境的代码是默认可以被部分受信任的代码访问的,如果你不想这样做,可以强命名整个程序集,级别1中强命名的程序集的所有公共成员会有隐式的全部权限的Link Demand,这样部分信任环境的程序集就无法访问了。当然手动添加Link Demand或者全部调用堆栈遍历(full demand)也可以。

 

在级别1中,SecurityTransparent特性和级别2一样,都会使整个程序集的全部成员成为透明代码。而AllowPartiallyTrustedCallers特性则不一样,它主要用来用在强命名的程序集中强制取消隐式的Link Demand。这样的话,程序集又可以被部分受信任代码所访问。如果想保护某些成员,可以手动添加SecurityCritical特性或者显示的Link Demand。

 

级别1中的SecurityCritical特性也有其他用处:

using System.Security;

[assemblySecurityRules(SecurityRuleSet.Level1)]

[assemblySecurityCritical]

如果这样使用,那么它和SecurityTransparent一样,只不过你可以手动在成员上再加SecurityCritical来指定它不是透明代码。

 

如果你想使整个程序集全部是关键代码的话(在级别2,默认就是这样的),使用SecurityCritical的Scope属性为Everything(在.NET 4.0中已废弃,由于.NET 4.0默认是使用级别2的):

using System.Security;

[assemblySecurityRules(SecurityRuleSet.Level1)]

[assemblySecurityCritical(SecurityCriticalScope.Everything)]

 

再运行代码,全部成员就是关键代码了(仅在全部权限下,部分权限下始终是透明代码)

全部受信任环境

默认方法 - 透明代码:False 关键代码:True  关键可靠代码:False

默认类型 - 透明代码:False 关键代码:True  关键可靠代码:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值