方法安全性应是类型安全性的超集
更新:2007 年 11 月
TypeName |
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)]");
}
}
}
该示例产生下面的输出。
[All permissions] Personal information: 6/16/1964 12:00:00 AM
[No write permission (demanded by type)] Personal information: 6/16/1964 12:00:00 AM
[No read permission (demanded by method)] Could not access personal information: Request failed.