Bagikan melalui


CA1060: Pindahkan P/Invokes ke kelas NativeMethods

Properti Nilai
ID Aturan CA1060
Judul Memindahkan P/Invokes ke kelas NativeMethods
Golongan Desain
Perbaikan bersifat disruptif atau non-disruptif Merusak
Diaktifkan secara default di .NET 8 Tidak

Penyebab

Metode menggunakan Platform Invocation Services untuk mengakses kode yang tidak dikelola dan bukan anggota salah satu kelas NativeMethods.

Deskripsi aturan

Metode Pemanggilan Platform, seperti metode yang ditandai dengan menggunakan atribut System.Runtime.InteropServices.DllImportAttribute, atau metode yang ditentukan dengan menggunakan kata kunci Declare di Visual Basic, mengakses kode yang tidak dikelola. Metode ini harus berada di salah satu kelas berikut:

  • NativeMethods - Kelas ini tidak menekan stack walk untuk izin kode yang tidak dikelola. (System.Security.SuppressUnmanagedCodeSecurityAttribute tidak boleh diterapkan ke kelas ini.) Kelas ini ditujukan untuk metode yang dapat digunakan di mana saja karena stack walk akan dilakukan.

  • SafeNativeMethods - Kelas ini menekan stack walk untuk izin kode yang tidak dikelola. (System.Security.SuppressUnmanagedCodeSecurityAttribute diterapkan ke kelas ini.) Kelas ini adalah untuk metode yang aman bagi siapa saja untuk menelepon. Pemanggil metode ini tidak diperlukan untuk melakukan tinjauan keamanan penuh untuk memastikan bahwa penggunaannya aman karena metodenya tidak berbahaya bagi pemanggil apa pun.

  • UnsafeNativeMethods - Kelas ini tidak menekan stack walk untuk izin kode yang tidak dikelola. (System.Security.SuppressUnmanagedCodeSecurityAttribute diterapkan ke kelas ini.) Kelas ini untuk metode yang berpotensi berbahaya. Setiap pemanggil metode ini harus melakukan tinjauan keamanan penuh untuk memastikan bahwa penggunaan aman karena tidak ada stack walk yang akan dilakukan.

Kelas-kelas ini dinyatakan sebagai internal (Friend dalam Visual Basic) dan mendeklarasikan konstruktor privat untuk mencegah instans baru dibuat. Metode dalam kelas-kelas ini harus static dan internal (Shared dan Friend di Visual Basic).

Cara memperbaiki pelanggaran

Untuk memperbaiki pelanggaran aturan ini, pindahkan metode ke kelas NativeMethods yang sesuai. Untuk sebagian besar aplikasi, memindahkan P/Invokes ke kelas baru yang diberi nama NativeMethods sudah cukup.

Namun, jika Anda mengembangkan pustaka untuk digunakan dalam aplikasi lain, Anda harus mempertimbangkan untuk menentukan dua kelas lain yang disebut SafeNativeMethods dan UnsafeNativeMethods. Kelas-kelas ini menyerupai kelas NativeMethods ; namun, mereka ditandai dengan menggunakan atribut khusus yang disebut SuppressUnmanagedCodeSecurityAttribute. Ketika atribut ini diterapkan, runtime bahasa umum tidak melakukan stack berjalan penuh untuk memastikan bahwa semua penelepon memiliki izin UnmanagedCode. Runtime bahasa umum biasanya memeriksa izin ini saat startup. Karena pemeriksaan tidak dilakukan, pemeriksaan dapat sangat meningkatkan performa untuk panggilan ke metode yang tidak dikelola ini. Ini juga memungkinkan kode yang memiliki izin terbatas untuk memanggil metode ini.

Namun, Anda harus menggunakan atribut ini dengan sangat hati-hati. Ini dapat memiliki implikasi keamanan yang serius jika diimplementasikan dengan tidak benar.

Untuk informasi tentang cara menerapkan metode, lihat contoh NativeMethods, contoh SafeNativeMethods, dan contoh UnsafeNativeMethods.

Kapan harus menekan peringatan

Jangan menyembunyikan peringatan dari aturan ini.

Contoh

Contoh berikut mendeklarasikan metode yang melanggar aturan ini. Untuk memperbaiki pelanggaran, RemoveDirectory P/Invoke harus dipindahkan ke kelas yang sesuai yang dirancang untuk hanya menahan 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);
}

Contoh NativeMethods

Karena kelas NativeMethods tidak boleh ditandai dengan menggunakan SuppressUnmanagedCodeSecurityAttribute, P/Invokes yang dimasukkan ke dalamnya akan memerlukan izin UnmanagedCode. Karena sebagian besar aplikasi berjalan dari komputer lokal dan berjalan bersama dengan kepercayaan penuh, ini biasanya tidak menjadi masalah. Namun, jika Anda mengembangkan pustaka yang dapat digunakan kembali, Anda harus mempertimbangkan untuk menentukan kelas SafeNativeMethods atau UnsafeNativeMethods.

Contoh berikut menunjukkan metode Interaction.Beep yang membungkus fungsi MessageBeep dari user32.dll. MessageBeep P/Invoke dimasukkan ke dalam kelas 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);
}

Contoh SafeNativeMethods

Metode P/Invoke yang dapat diekspos dengan aman ke aplikasi apa pun dan yang tidak memiliki efek samping harus dimasukkan ke dalam kelas yang bernama SafeNativeMethods. Anda tidak perlu terlalu memperhatikan dari mana mereka dipanggil.

Contoh berikut menunjukkan properti Environment.TickCount yang membungkus fungsi GetTickCount dari 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();
}

Contoh UnsafeNativeMethods

Metode P/Invoke yang tidak dapat dipanggil dengan aman dan itu dapat menyebabkan efek samping harus dimasukkan ke dalam kelas yang bernama UnsafeNativeMethods. Metode ini harus diperiksa dengan ketat untuk memastikan bahwa metode tersebut tidak diekspos ke pengguna secara tidak sengaja.

Contoh berikut menunjukkan metode Cursor.Hide yang membungkus fungsi ShowCursor dari 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);
}

Baca juga