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)]");
}
}
}
這個範例產生下列輸出。