CA2114: メソッドのセキュリティは型のスーパーセットにします
TypeName |
MethodSecurityShouldBeASupersetOfType |
CheckId |
CA2114 |
分類 |
Microsoft.Security |
互換性に影響する変更点 |
あり |
原因
型に宣言セキュリティがあり、その型のメソッドが同じセキュリティ アクションの宣言セキュリティを持ち、セキュリティ アクションがリンク確認要求または継承確認要求ではなく、型でチェックされているアクセス許可はメソッドでチェックされているアクセス許可のサブセットではありません。
規則の説明
メソッドには、同じアクションについて、メソッド レベルと型レベルの宣言セキュリティのいずれも含めないでください。2 つのチェックは結合されず、メソッド レベルの要求のみが適用されます。たとえば、型からアクセス許可 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)]");
}
}
}
この例を実行すると、次の出力が生成されます。