Поделиться через


CA2105: поля массивов не должны быть доступны только для чтения

TypeName

ArrayFieldsShouldNotBeReadOnly

CheckId

CA2105

Категория

Microsoft.Security

Критическое изменение

Критическое изменение

Причина

Открытое или защищенное поле, в котором содержится массив, объявлено как доступное только для чтения.

Описание правила

При использовании модификатора readonly (ReadOnly в Visual Basic) к полю, содержащему массив, это поле нельзя изменить для связи с другим массивом. Однако элементы массива, хранящегося в доступном только для чтения поле, можно будет изменить. Код, используемый для принятия решений или выполнения действий на основе элементов общедоступного массива только для чтения, может содержать уязвимые места.

Следует обратить внимание, что наличие открытых полей также приводит к нарушению правила разработки CA1051: не объявляйте видимые поля экземпляров.

Устранение нарушений

Чтобы устранить нарушения системы безопасности, выявленные данным правилом, не следует полагаться на содержимое массива только для чтения, который может быть общедоступным. Настоятельно рекомендуется воспользоваться одной из следующих процедур.

  • Замените массив типобезопасной неизменяемой коллекцией. Дополнительные сведения см. в разделе System.Collections.ReadOnlyCollectionBase.

  • Замените открытое поле методом, возвращающим копию закрытого массива. Поскольку код не использует копию, изменение элементов не будет представлять никакой опасности.

При выборе второго подхода не нужно заменять поле свойством; свойства, возвращающие массивы, оказывают негативное влияние на производительность. Дополнительные сведения см. в разделе CA1819: свойства не должны возвращать массивы.

Отключение предупреждений

Отключение вывода предупреждения для данного правила крайне нежелательно. Случаев, в которых содержимое поля, доступного только для чтения, является маловажным, практически не существует. Если это так в текущей ситуации, вместо отключения сообщения удалите модификатор readonly.

Пример

В следующем примере показана опасность нарушения данного правила. В первой части представлена библиотека с типом MyClassWithReadOnlyArrayField, где содержатся два поля (grades и privateGrades), безопасность которых не гарантируется. Поле grades является открытым и, следовательно, уязвимым к вызывающим методам. Поле privateGrades является закрытым, но все еще уязвимым, поскольку оно возвращается вызывающим методам с помощью метода GetPrivateGrades. Поле securePrivateGrades доступно в безопасном режиме за счет методаGetSecurePrivateGrades. Для соответствия рекомендациям разработки оно объявляется закрытым. Во второй части представлен код, изменяющий значения, которые хранятся в членах 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