CA2105: Los campos de matrices no deberían ser de solo lectura
Nombre de tipo |
ArrayFieldsShouldNotBeReadOnly |
Identificador de comprobación |
CA2105 |
Categoría |
Microsoft.Security |
Cambio problemático |
Sí |
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 solo lectura.El código que toma decisiones o realiza operaciones basadas en los elementos de una matriz de solo lectura a la que se puede acceder 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 CA1051: No declarar campos de instancia 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 solo lectura accesible públicamente.Se recomienda que realice uno de los procedimientos siguientes:
Reemplace la matriz con una colección fuertemente tipada 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 CA1819: 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 en los que el contenido de un campo de solo 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 ejemplo que tiene 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: