Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
| Właściwości | Wartość |
|---|---|
| Identyfikator reguły | CA1060 |
| Tytuł | Przenieś metody P/Invoke do klasy NativeMethods |
| Kategoria | Projektowanie |
| Poprawka łamiąca lub nienaruszająca | Przełomowe |
| Domyślnie włączone na platformie .NET 10 | Nie. |
| Zastosowane języki | C# i Visual Basic |
Przyczyna
Metoda używa usług wywoływania platformy do uzyskiwania dostępu do kodu niezarządzanego i nie jest członkiem jednej z klas NativeMethods.
Opis reguły
Metody wywołania platformy, takie jak metody oznaczone za pomocą atrybutu System.Runtime.InteropServices.DllImportAttribute lub metody zdefiniowane za pomocą słowa kluczowego Declare w języku Visual Basic, uzyskują dostęp do niezarządzanych kodów. Te metody powinny znajdować się w jednej z następujących klas:
NativeMethods — ta klasa nie pomija przechodzenia stosu dla uprawnień do niezarządzanego kodu. (System.Security.SuppressUnmanagedCodeSecurityAttribute nie powinien być stosowany do tej klasy). Ta klasa jest przeznaczona dla metod, które mogą być używane w dowolnym miejscu, ponieważ zostanie wykonane przechodzenie po stosie.
SafeNativeMethods — ta klasa blokuje wykonywanie przejść stosu dla uprawnień kodu niezarządzanego. (System.Security.SuppressUnmanagedCodeSecurityAttribute jest zastosowany do tej klasy). Ta klasa jest dla metod, które są bezpieczne do wywołania przez każdego. Wywołujący te metody nie muszą przeprowadzać pełnego przeglądu zabezpieczeń w celu upewnienia się, że ich użycie jest bezpieczne, ponieważ metody są nieszkodliwe dla każdego, kto je wywołuje.
UnsafeNativeMethods — ta klasa pomija przejścia stosu dla niezarządzanych uprawnień kodu. (System.Security.SuppressUnmanagedCodeSecurityAttribute jest stosowany do tej klasy). Ta klasa dotyczy metod, które są potencjalnie niebezpieczne. Każdy, kto wywołuje te metody, musi przeprowadzić pełny przegląd zabezpieczeń, aby upewnić się, że użycie jest bezpieczne, ponieważ nie zostanie wykonane żadne sprawdzenie stosu.
Te klasy są deklarowane jako internal (Friend w Visual Basic) i deklarują konstruktor prywatny, aby zapobiec tworzeniu nowych wystąpień. Metody w tych klasach powinny mieć wartość static i internal (Shared i Friend w Visual Basic).
Jak naprawić naruszenia
Aby naprawić naruszenie tej reguły, przenieś metodę do odpowiedniej klasy NativeMethods . W przypadku większości aplikacji wystarczy przeniesienie operacji P/Invoke do nowej klasy o nazwie NativeMethods .
Jeśli jednak tworzysz biblioteki do użycia w innych aplikacjach, rozważ zdefiniowanie dwóch innych klas o nazwie SafeNativeMethods i UnsafeNativeMethods. Te klasy przypominają klasę NativeMethods , jednak są one oznaczone za pomocą specjalnego atrybutu o nazwie SuppressUnmanagedCodeSecurityAttribute. Po zastosowaniu tego atrybutu środowisko uruchomieniowe nie wykonuje pełnego przechodzenia stosu, aby upewnić się, że wszyscy wywołujący mają uprawnienia UnmanagedCode. Środowisko uruchomieniowe zwykle sprawdza to uprawnienie podczas uruchamiania. Ponieważ sprawdzanie nie jest przeprowadzane, może to znacznie poprawić wydajność wywołań tych niezarządzanych metod. Umożliwia również kod, który ma ograniczone uprawnienia do wywoływania tych metod.
Należy jednak użyć tego atrybutu z wielką starannością. Może to mieć poważne konsekwencje dla bezpieczeństwa, jeśli jest on implementowany nieprawidłowo.
Aby uzyskać informacje o sposobie implementowania metod, zobacz przykład NativeMethods , przykład SafeNativeMethods i UnsafeNativeMethods .
Kiedy pomijać ostrzeżenia
Nie pomijaj ostrzeżeń dla tej reguły.
Przykład
Poniższy przykład deklaruje metodę, która narusza tę regułę. Aby rozwiązać ten błąd, należy przenieść element RemoveDirectory P/Invoke do odpowiedniej klasy, która jest przeznaczona do przechowywania tylko wywołań P/Invoke.
' Violates rule: MovePInvokesToNativeMethodsClass.
Friend Class UnmanagedApi
Friend Declare Function RemoveDirectory Lib "kernel32" (
ByVal Name As String) As Boolean
End Class
// Violates rule: MovePInvokesToNativeMethodsClass.
internal class UnmanagedApi
{
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
internal static extern bool RemoveDirectory(string name);
}
Przykład NativeMethods
Ponieważ klasa NativeMethods nie powinna być oznaczona przy użyciu atrybutu SuppressUnmanagedCodeSecurityAttribute, wprowadzone w nim elementy P/Invoke będą wymagać uprawnienia UnmanagedCode. Ponieważ większość aplikacji działa z komputera lokalnego i działa razem z pełnym zaufaniem, zwykle nie jest to problem. Jeśli jednak tworzysz biblioteki wielokrotnego użytku, rozważ zdefiniowanie klasy SafeNativeMethods lub UnsafeNativeMethods .
W poniższym przykładzie przedstawiono metodę Interaction.Beep, która opakowuje funkcję MessageBeep z user32.dll. Element MessageBeep P/Invoke jest umieszczany w klasie NativeMethods .
Public NotInheritable Class Interaction
Private Sub New()
End Sub
' Callers require Unmanaged permission
Public Shared Sub Beep()
' No need to demand a permission as callers of Interaction.Beep
' will require UnmanagedCode permission
If Not NativeMethods.MessageBeep(-1) Then
Throw New Win32Exception()
End If
End Sub
End Class
Friend NotInheritable Class NativeMethods
Private Sub New()
End Sub
<DllImport("user32.dll", CharSet:=CharSet.Auto)>
Friend Shared Function MessageBeep(ByVal uType As Integer) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
End Class
public static class Interaction
{
// Callers require Unmanaged permission
public static void Beep()
{
// No need to demand a permission as callers of Interaction.Beep
// will require UnmanagedCode permission
if (!NativeMethods.MessageBeep(-1))
throw new Win32Exception();
}
}
internal static class NativeMethods
{
[DllImport("user32.dll", CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool MessageBeep(int uType);
}
Przykład SafeNativeMethods
Metody P/Invoke, które mogą być bezpiecznie narażone na dowolną aplikację i które nie mają żadnych skutków ubocznych, należy umieścić w klasie o nazwie SafeNativeMethods. Nie musisz zwracać dużej uwagi na to, skąd są wywoływane.
W poniższym przykładzie przedstawiono właściwość Environment.TickCount, która opakowuje funkcję GetTickCount z kernel32.dll.
Public NotInheritable Class Environment
Private Sub New()
End Sub
' Callers do not require Unmanaged permission
Public Shared ReadOnly Property TickCount() As Integer
Get
' No need to demand a permission in place of
' UnmanagedCode as GetTickCount is considered
' a safe method
Return SafeNativeMethods.GetTickCount()
End Get
End Property
End Class
<SuppressUnmanagedCodeSecurityAttribute()>
Friend NotInheritable Class SafeNativeMethods
Private Sub New()
End Sub
<DllImport("kernel32.dll", CharSet:=CharSet.Auto, ExactSpelling:=True)>
Friend Shared Function GetTickCount() As Integer
End Function
End Class
public static class Environment
{
// Callers do not require UnmanagedCode permission
public static int TickCount
{
get
{
// No need to demand a permission in place of
// UnmanagedCode as GetTickCount is considered
// a safe method
return SafeNativeMethods.GetTickCount();
}
}
}
[SuppressUnmanagedCodeSecurityAttribute]
internal static class SafeNativeMethods
{
[DllImport("kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
internal static extern int GetTickCount();
}
Przykład UnsafeNativeMethods
Metody P/Invoke, których nie można bezpiecznie wywołać i które mogą powodować skutki uboczne, należy umieścić w klasie o nazwie UnsafeNativeMethods. Te metody powinny być rygorystycznie sprawdzane, aby upewnić się, że nie są one widoczne dla użytkownika przypadkowo.
W poniższym przykładzie przedstawiono metodę Cursor.Hide , która opakowuje funkcję ShowCursor z user32.dll.
Public NotInheritable Class Cursor
Private Sub New()
End Sub
Public Shared Sub Hide()
UnsafeNativeMethods.ShowCursor(False)
End Sub
End Class
<SuppressUnmanagedCodeSecurityAttribute()>
Friend NotInheritable Class UnsafeNativeMethods
Private Sub New()
End Sub
<DllImport("user32.dll", CharSet:=CharSet.Auto, ExactSpelling:=True)>
Friend Shared Function ShowCursor(<MarshalAs(UnmanagedType.Bool)> ByVal bShow As Boolean) As Integer
End Function
End Class
public static class Cursor
{
public static void Hide()
{
UnsafeNativeMethods.ShowCursor(false);
}
}
[SuppressUnmanagedCodeSecurityAttribute]
internal static class UnsafeNativeMethods
{
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
internal static extern int ShowCursor([MarshalAs(UnmanagedType.Bool)] bool bShow);
}