Compartir a través de


Los campos de matrices no deberían ser de sólo lectura

Actualización: noviembre 2007

Nombre de tipo

ArrayFieldsShouldNotBeReadOnly

Identificador de comprobación

CA2105

Categoría

Microsoft.Security

Cambio problemático

Motivo

Un campo público o protegido que contiene una matriz se declara como de sólo lectura.

Descripción de la regla

Cuando se aplica el modificador readonly (ReadOnly en Visual Basic) a un campo que contiene una matriz, el campo no se modifica para hacer referencia a una matriz distinta. Sin embargo, se pueden cambiar los elementos de la matriz almacenados en un campo de sólo lectura. El código que toma decisiones o realiza operaciones basadas en los elementos de una matriz de sólo lectura accesible públicamente podría contener una vulnerabilidad de seguridad explotable.

Observe que al tener un campo público, también se infringe la regla de diseño No declarar campos de instancias visibles.

Cómo corregir infracciones

Para corregir la vulnerabilidad de seguridad identificada por esta regla, no confíe en el contenido de una matriz de sólo lectura accesible públicamente. Se recomienda que realice uno de los procedimientos siguientes:

  • Reemplace la matriz con una colección con establecimiento inflexible de tipos que no se puede cambiar. Para obtener más información, vea System.Collections.ReadOnlyCollectionBase

  • Reemplace el campo público con un método que devuelve un clon de una matriz privada. Dado que el código no confía en el clon, no hay peligro si se modifican los elementos.

Si eligiera el segundo método, no reemplace el campo con una propiedad; las propiedades que devuelven matrices afectan negativamente al rendimiento. Para obtener más información, vea Las propiedades no deberían devolver matrices.

Cuándo suprimir advertencias

Se desaconseja totalmente excluir una advertencia de esta regla. Son muy pocos los escenarios donde el contenido de un campo de sólo lectura no sea importante. Si éste es el caso de su escenario, quite el modificador readonly en lugar de excluir el mensaje.

Ejemplo

Este ejemplo muestra los peligros de infringir esta regla. La primera parte muestra una biblioteca de ejemplos con un tipo, MyClassWithReadOnlyArrayField, que contiene dos campos (grades y privateGrades) que no son seguros. El campo grades es público y por consiguiente vulnerable a cualquier llamador. El campo privateGrades es privado, pero todavía es vulnerable porque se devuelve a los llamadores por el método GetPrivateGrades. El método GetSecurePrivateGrades expone el campo securePrivateGrades de forma segura. Se declara como privado para seguir los procedimientos de diseño recomendados. La segunda parte muestra el código que cambia los valores almacenados en los miembros grades y privateGrades.

En el ejemplo siguiente se incluye la biblioteca de clases de ejemplo.

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]);
      }     
   }
}

El código siguiente utiliza la biblioteca de clases de ejemplo para mostrar los problemas de seguridad de la matriz de sólo lectura.

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());
      }
   }
}

El resultado de este ejemplo es:

Before tampering: Grades: 90, 90, 90 Private Grades: 90, 90, 90  Secure Grades, 90, 90, 90
After tampering: Grades: 90, 555, 90 Private Grades: 90, 555, 90  Secure Grades, 90, 90, 90

Vea también

Referencia

System.Array

System.Collections.ReadOnlyCollectionBase