CA2105:陣列欄位不應為唯讀

型別名稱

ArrayFieldsShouldNotBeReadOnly

CheckId

CA2105

分類

Microsoft.Security

中斷變更

中斷

原因

儲存陣列的公用 (Public) 或保護 (Protected) 的欄位宣告為唯讀。

規則描述

當您將 readonly (在 Visual Basic 中是 ReadOnly) 修飾詞套用至包含陣列的欄位時,欄位就不能變更為參考不同的陣列。 但是,儲存在唯讀欄位的陣列元素則可以變更。 根據可公開存取的唯讀陣列元素進行決策或執行作業的程式碼,可能會包含可利用的安全性弱點。

請注意,具有公用欄位也會違反設計規則CA1051:不要宣告可見的執行個體欄位

如何修正違規

若要修正此規則所定義的安全性弱點,請勿依賴可公開存取的唯讀陣列內容。 強烈建議您使用下列其中一個程序:

  • 以無法變更的強型別 (Strongly Typed) 集合取代此陣列。 如需詳細資訊,請參閱System.Collections.ReadOnlyCollectionBase

  • 以會傳回私用陣列複製品 (Clone) 的方法取代公用欄位。 因為您的程式碼並不依賴此複製品,因此修改元素就不會有危險。

如果您選擇第二種方式,請勿以屬性取代欄位,因為傳回陣列的屬性會對效能造成負面影響。 如需詳細資訊,請參閱CA1819:屬性不應傳回陣列

隱藏警告的時機

強烈建議您排除問題而不是移除規則警告項目。 幾乎在所有情況中,唯讀欄位的內容都很重要。 如果您也有相同的情況,則請移除 readonly 修飾詞,而非排除訊息。

範例

下列會示範違反這項規則的危險性。 第一個部分會顯示具有型別 MyClassWithReadOnlyArrayField 的範例程式庫,其中包含兩個不安全的欄位 (grades 和 privateGrades)。 grades 為公用欄位,因此容易遭受任何呼叫端攻擊。 雖然 privateGrades 為私用欄位,但因它是由 GetPrivateGrades 方法傳回給呼叫端,所以仍易遭受攻擊。 GetSecurePrivateGrades 方法會以安全的方式公開 securePrivateGrades 欄位。 此欄位宣告為私用,並且在上述方法中會複製另一份實體將該欄位傳回,此法有遵循良好的設計法則。 第二個部分所顯示的程式碼會變更儲存在 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());
      }
   }
}

本範例的輸出如下:

  

請參閱

參考

System.Array

System.Collections.ReadOnlyCollectionBase