CA2114:方法安全性应是类型安全性的超集

类型名

MethodSecurityShouldBeASupersetOfType

CheckId

CA2114

类别

Microsoft.Security

是否重大更改

原因

某类型有声明性安全,它的某个方法有同一安全操作的声明性安全,该安全操作不是 链接需求继承需求,类型检查的权限也不是该方法检查的权限的子集。

规则说明

某方法不应同时有同一操作的方法级别和类型级别的声明性安全。 两种检查不会合并;只会应用方法级别的要求。 例如,如果一个类型要求具备权限 X,而它的某个方法要求具备权限 Y,则代码不需要具备权限 X 就可以执行该方法。

如何解决冲突

检查代码以确保同时需要这两种操作。 如果同时需要这两种操作,请确保方法级别的操作包含类型级别指定的安全性。 例如,如果类型要求权限 X,而其方法必须要求权限 Y,则该方法应当显式要求 X 和 Y。

何时禁止显示警告

如果方法不需要类型指定的安全性,则可以安全地禁止显示此规则发出的警告。 然而,这并不是一种正常的情况,可能表示需要进行仔细的设计检查。

示例

下面的示例使用环境权限演示与该规则冲突的危险。 在此示例中,应用程序代码在拒绝类型要求的权限之前创建安全类型的实例。 在现实威胁情况中,应用程序将需要另一种获取对象实例的方法。

在下面的示例中,库要求类型有写权限,方法有读权限。

using System;
using System.Security;
using System.Security.Permissions;
using System.Runtime.InteropServices;

namespace SecurityRulesLibrary
{
   [EnvironmentPermissionAttribute(SecurityAction.Demand, Write="PersonalInfo")]
   public class MyClassWithTypeSecurity
   {
      [DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
      [return:MarshalAs(UnmanagedType.Bool)]
      public static extern bool SetEnvironmentVariable(
         string lpName,
         string lpValue);

      // Constructor.
      public MyClassWithTypeSecurity(int year, int month, int day)
      {
         DateTime birthday = new DateTime(year, month, day);

         // Write out PersonalInfo environment variable.
         SetEnvironmentVariable("PersonalInfo",birthday.ToString());
      }

      [EnvironmentPermissionAttribute(SecurityAction.Demand, Read="PersonalInfo")]
      public string PersonalInformation ()
      { 
         // Read the variable.
         return Environment.GetEnvironmentVariable("PersonalInfo"); 
      }
   }
}

下面的应用程序代码通过调用方法(尽管该方法不能满足类型级别的安全要求)演示库的漏洞。

using System;
using System.Security;
using System.Security.Permissions;
using SecurityRulesLibrary;

namespace TestSecRulesLibrary
{
   public class TestMethodLevelSecurity
   {
      MyClassWithTypeSecurity dataHolder;

      void RetrievePersonalInformation(string description) 
      {
         try 
         { 
            Console.WriteLine(
               "{0} Personal information: {1}", 
               description, dataHolder.PersonalInformation());
         }
         catch (SecurityException e) 
         {
            Console.WriteLine(
               "{0} Could not access personal information: {1}", 
               description, e.Message);
         }
      }

      [STAThread]
      public static void Main() 
      {
         TestMethodLevelSecurity me = new TestMethodLevelSecurity();

         me.dataHolder = new MyClassWithTypeSecurity(1964,06,16);

         // Local computer zone starts with all environment permissions.
         me.RetrievePersonalInformation("[All permissions]");

         // Deny the write permission required by the type.
         EnvironmentPermission epw = new EnvironmentPermission(
            EnvironmentPermissionAccess.Write,"PersonalInfo");
         epw.Deny();

         // Even though the type requires write permission, 
         // and you do not have it; you can get the data.
         me.RetrievePersonalInformation(
            "[No write permission (demanded by type)]");

         // Reset the permissions and try to get 
         // data without read permission.
         CodeAccessPermission.RevertAll();  

         // Deny the read permission required by the method.
         EnvironmentPermission epr = new EnvironmentPermission(
            EnvironmentPermissionAccess.Read,"PersonalInfo");
         epr.Deny();

         // The method requires read permission, and you
         // do not have it; you cannot get the data.
         me.RetrievePersonalInformation(
            "[No read permission (demanded by method)]");
      }
   }
}

该示例产生下面的输出。

  

请参见

概念

代码安全维护指南

继承需求

链接需求

其他资源

数据访问和建模