CA1060: Přesuňte volání nespravovaných kódů do třídy NativeMethods

Vlastnost Hodnota
ID pravidla CA1060
Název Přesuňte volání nespravovaných kódů do třídy NativeMethods
Kategorie Návrh
Oprava způsobující chybu nebo chybu způsobující chybu Narušující
Povoleno ve výchozím nastavení v .NET 8 No

Příčina

Metoda používá platformu Invocation Services pro přístup k nespravovanému kódu a není členem jedné z nativních třídMethods .

Popis pravidla

Metody volání platformy, například metody označené atributem System.Runtime.InteropServices.DllImportAttribute nebo metody definované pomocí klíčového Declare slova v jazyce Visual Basic, mají přístup k nespravovanému kódu. Tyto metody by měly být v jedné z následujících tříd:

  • NativeMethods – Tato třída nepotlačí procházky zásobníku pro nespravované oprávnění kódu. (System.Security.SuppressUnmanagedCodeSecurityAttribute nesmí být použita pro tuto třídu.) Tato třída je určená pro metody, které lze použít kdekoli, protože bude provedena procházka zásobníkem.

  • Sejf NativeMethods – Tato třída potlačí procházky zásobníku pro nespravované oprávnění kódu. (System.Security.SuppressUnmanagedCodeSecurityAttribute je použit pro tuto třídu.) Tato třída je určena pro metody, které jsou bezpečné pro každého volání. Volající z těchto metod nemusí provádět úplnou kontrolu zabezpečení, aby se ujistili, že je použití zabezpečené, protože metody jsou neškodné pro všechny volající.

  • UnsafeNativeMethods – Tato třída potlačí procházky zásobníku pro nespravované oprávnění ke kódu. (System.Security.SuppressUnmanagedCodeSecurityAttribute je použit pro tuto třídu.) Tato třída je určena pro metody, které jsou potenciálně nebezpečné. Každý volající těchto metod musí provést úplnou kontrolu zabezpečení, aby se zajistilo, že je využití zabezpečené, protože se neprovádí žádná procházka zásobníkem.

Tyto třídy jsou deklarovány jako internal (Friend v jazyce Visual Basic) a deklarují privátní konstruktor, aby se zabránilo vytváření nových instancí. Metody v těchto třídách by měly být static a internal (Shared a Friend v jazyce Visual Basic).

Jak opravit porušení

Chcete-li opravit porušení tohoto pravidla, přesuňte metodu do příslušné třídy NativeMethods . U většiny aplikací stačí přesunutí volání nespravovaných volání do nové třídy s názvem NativeMethods .

Pokud ale vyvíjíte knihovny pro použití v jiných aplikacích, měli byste zvážit definování dvou dalších tříd, které se nazývají Sejf NativeMethods a UnsafeNativeMethods. Tyto třídy se podobají NativeMethods třídy, ale jsou označeny pomocí speciální atribut s názvem SuppressUnmanagedCodeSecurityAttribute. Při použití tohoto atributu modul runtime neprovádí úplnou procházku zásobníkem, aby se zajistilo, že všichni volající mají oprávnění Nespravovaný kód . Modul runtime obvykle kontroluje toto oprávnění při spuštění. Vzhledem k tomu, že se kontrola neprovádí, může výrazně zlepšit výkon volání těchto nespravovaných metod. Umožňuje také kód, který má omezená oprávnění k volání těchto metod.

Tento atribut byste ale měli používat s velkou opatrností. Pokud je implementovaná nesprávně, může to mít vážné bezpečnostní důsledky.

Informace o tom, jak implementovat metody, naleznete v příkladu NativeMethods, Sejf NativeMethods příklad a UnsafeNativeMethods příklad.

Kdy potlačit upozornění

Nepotlačujte upozornění na toto pravidlo.

Příklad

Následující příklad deklaruje metodu, která porušuje toto pravidlo. Chcete-li opravit porušení, removeDirectory P/Invoke by se měl přesunout do příslušné třídy, která je navržena tak, aby držela pouze volání P/Invokes.

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

Příklad NativeMethods

Vzhledem k tomu, že NativeMethods třída by neměla být označena pomocí SuppressUnmanagedCodeSecurityAttribute, P/Invokes, které jsou vloženy, budou vyžadovat oprávnění UnmanagedCode. Vzhledem k tomu, že většina aplikací běží z místního počítače a běží společně s úplným vztahem důvěryhodnosti, obvykle to není problém. Pokud ale vyvíjíte opakovaně použitelné knihovny, měli byste zvážit definování třídy Sejf NativeMethods nebo UnsafeNativeMethods.

Následující příklad ukazuje Interaction.Beep metoda, která zabalí messageBeep funkce z user32.dll. MessageBeep P/Invoke je vložen do NativeMethods třídy.

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

příklad Sejf NativeMethods

Metody P/Invoke, které mohou být bezpečně vystaveny jakékoli aplikaci a které nemají žádné vedlejší účinky by měly být vloženy do třídy s názvem Sejf NativeMethods. Nemusíte věnovat velkou pozornost tomu, odkud jsou volána.

Následující příklad ukazuje Environment.TickCount vlastnost, která zabalí GetTickCount funkce 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();
}

Příklad NebezpečnéNativeMethods

Metody P/Invoke, které nelze bezpečně volat a které by mohly způsobit vedlejší účinky by měly být vloženy do třídy s názvem UnsafeNativeMethods. Tyto metody by měly být pečlivě kontrolovány, aby se ujistily, že nejsou uživateli neúmyslně vystaveny.

Následující příklad ukazuje Cursor.Hide metoda, která zabalí ShowCursor funkce 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);
}

Viz také