CA2105: Pola tablicy nie powinny być tylko do odczytu
TypeName |
ArrayFieldsShouldNotBeReadOnly |
CheckId |
CA2105 |
Kategoria |
Microsoft.Security |
Zmiana kluczowa |
Kluczowa |
Przyczyna
Pola publiczne lub chronione zawierające tablicę jest zadeklarowane jako tylko do odczytu.
Opis reguły
Po zastosowaniu modyfikatora readonly (ReadOnly w Visual Basic) do pola, które zawiera tablicę pola nie można zmienić tak, aby odnosiło się do innej tablicy.Można jednak zmienić elementy tablicy, które są przechowywane w polu tylko do odczytu.Kod, który podejmuje decyzje lub wykonuje operacje, które są oparte na elementach tablicy tylko do odczytu, które są publicznie dostępne może zawierać lukę w zabezpieczeniach.
Należy zauważyć, że pole publiczne również narusza regułę projektowania CA1051: Nie deklaruj widocznych pól wystąpień.
Jak naprawić naruszenia
Aby rozwiązać lukę w zabezpieczeniach identyfikowaną przez tę regułę, nie należy polegać na zawartości tablicy tylko do odczytu, która jest publicznie dostępna.Zdecydowanie zaleca się użycie jednej z następujących procedur:
Zamień tablicę na silnie typowaną, niezmienną kolekcję.Aby uzyskać więcej informacji, zobacz ReadOnlyCollectionBase.
Zastąp pole publiczne metodą, która zwraca klon prywatnej tablicy.Ponieważ kod nie jest zależny od klonu, nie istnieje już niebezpieczeństwo, jeśli elementy są modyfikowane.
Jeśli wybrano drugie podejście, nie zastępować pola właściwością; właściwości, które zwracają tablice niekorzystnie wpływają na wydajność.Aby uzyskać więcej informacji, zobacz CA1819: Właściwości nie powinny zwracać tablic.
Kiedy pomijać ostrzeżenia
Wyłączenie ostrzeżenia od tej reguły jest zdecydowanie niezalecane.Prawie nie istnieją scenariusze, gdy zawartość pola tylko do odczytu nie jest istotna.Jeśli dotyczy to tego przypadku, należy usunąć modyfikator readonly zamiast wyłączania wiadomości.
Przykład
Ten przykład demonstruje niebezpieczeństwa związane z naruszeniem zasady.Pierwsza część zawiera przykładową bibliotekę, która ma typ MyClassWithReadOnlyArrayField, który zawiera dwa pola (grades i privateGrades), które nie są bezpieczne.Pole grades jest publiczne i dlatego zagrożone przez dowolnego wywołującego.Pole privateGrades jest prywatne, ale jest nadal zagrożony, ponieważ jest ono zwracane do wywołujących przez metodę GetPrivateGrades.Pole securePrivateGrades jest odsłonięte w bezpieczny sposób przez metodę GetSecurePrivateGrades.Jest zadeklarowane jako prywatne, zgodnie z dobrymi praktykami projektowymi.Druga część zawiera kod, który zmienia wartości przechowywane w elementach członkowskich grades i privateGrades.
Przykładowa biblioteka klas pojawia się w następującym przykładzie.
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]);
}
}
}
Następujący kod używa przykładowej biblioteki klas do ilustrowania problemów z zabezpieczeniem tablicy tylko do odczytu.
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());
}
}
}
Wynikiem z przykładu jest: