CA2105: 配列フィールドは読み取り専用にできません
TypeName |
ArrayFieldsShouldNotBeReadOnly |
CheckId |
CA2105 |
[カテゴリ] |
Microsoft.Security |
互換性に影響する変更点 |
あり |
原因
配列を含むパブリック フィールドまたはプロテクト フィールドが、読み取り専用と宣言されています。
規則の説明
配列を含むフィールドに readonly (Visual Basic では ReadOnly) 修飾子を適用すると、そのフィールドで参照先の配列を変更できません。ただし、読み取り専用フィールドに格納された配列の要素は変更できます。パブリックにアクセスできる読み取り専用の配列で、その要素に基づいてコードで条件判断または操作を行うと、セキュリティ上の脆弱性が生じます。
パブリック フィールドが存在すること自体も、デザイン規則「CA1051: 参照できるインスタンス フィールドを宣言しないでください」に違反しています。
違反の修正方法
この規則で特定されるセキュリティ上の脆弱性を修正するには、パブリックにアクセスできる読み取り専用の配列の要素に依存しないようにします。次の手順のいずれかを実行することを強くお勧めします。
変更できない、厳密に型指定されたコレクションで、配列を置換します。詳細については、「System.Collections.ReadOnlyCollectionBase」を参照してください。
プライベート配列のクローンを返すメソッドで、パブリック フィールドを置換します。コードはクローンに依存しないため、要素が変更されても危険はありません。
2 つ目の方法を選択した場合、フィールドをプロパティで置換しないでください。配列を返すプロパティの場合、パフォーマンスに悪影響を及ぼすことがあります。詳細については、「CA1819: プロパティは、配列を返すことはできません」を参照してください。
警告を抑制する状況
この規則からは、できるだけ警告を除外しないでください。読み取り専用フィールドの内容が重要ではない場合はほとんどありません。読み取り専用フィールドの内容が重要ではない場合、メッセージを除外するのではなく、readonly 修飾子を削除します。
使用例
この規則に違反した場合の危険性について、例を説明します。最初の部分には、MyClassWithReadOnlyArrayField という型のサンプル ライブラリが表示されます。安全ではない 2 つのフィールド (grades と privateGrades) が含まれています。grades フィールドはパブリックであるため、どのような呼び出し元に対しても脆弱性があります。privateGrades フィールドはプライベートですが、GetPrivateGrades メソッドで呼び出し元に返されるため、脆弱性があります。securePrivateGrades フィールドは、GetSecurePrivateGrades メソッドを使用すると安全な方法で公開されます。適切なデザイン方法に従って、プライベートと宣言します。2 つ目の部分には、grades メンバーと privateGrades メンバーに格納されている値を変更するコードが表示されます。
サンプルのクラス ライブラリを次に示します。
using System;
namespace SecurityRulesLibrary
{
public class MyClassWithReadOnlyArrayField
{
public readonly int[] grades = {90, 90, 90};
private readonly int[] privateGrades = {90, 90, 90};
private readonly int[] securePrivateGrades = {90, 90, 90};
// Making the array private does not protect it because it is passed to others.
public int[] GetPrivateGrades()
{
return privateGrades;
}
//This method secures the array by cloning it.
public int[] GetSecurePrivateGrades()
{
return (int[])securePrivateGrades.Clone();
}
public override string ToString()
{
return String.Format("Grades: {0}, {1}, {2} Private Grades: {3}, {4}, {5} Secure Grades, {6}, {7}, {8}",
grades[0], grades[1], grades[2], privateGrades[0], privateGrades[1], privateGrades[2], securePrivateGrades[0], securePrivateGrades[1], securePrivateGrades[2]);
}
}
}
次のコードでは、サンプルのクラス ライブラリを使用して、読み取り専用の配列が持つセキュリティ問題を表しています。
using System;
using SecurityRulesLibrary;
namespace TestSecRulesLibrary
{
public class TestArrayReadOnlyRule
{
[STAThread]
public static void Main()
{
MyClassWithReadOnlyArrayField dataHolder =
new MyClassWithReadOnlyArrayField();
// Get references to the library's readonly arrays.
int[] theGrades = dataHolder.grades;
int[] thePrivateGrades = dataHolder.GetPrivateGrades();
int[] theSecureGrades = dataHolder.GetSecurePrivateGrades();
Console.WriteLine(
"Before tampering: {0}", dataHolder.ToString());
// Overwrite the contents of the "readonly" array.
theGrades[1]= 555;
thePrivateGrades[1]= 555;
theSecureGrades[1]= 555;
Console.WriteLine(
"After tampering: {0}",dataHolder.ToString());
}
}
}
このサンプルによる出力は次のとおりです。