发布时间:2025-12-09 12:05:46 浏览次数:2
值
规则 ID
CA1060
类别
设计
修复是中断修复还是非中断修复
重大
原因
方法使用平台调用服务访问非托管代码,不是 NativeMethods 类之一的成员。
规则说明
平台调用方法(如使用 System.Runtime.InteropServices.DllImportAttribute 属性标记的方法)或在 Visual Basic 中使用 declare 关键字定义的方法可访问非托管代码。 这些方法应是处于以下一个类中:
NativeMethods - 此类不会对非托管代码权限取消堆栈审核。 (System.Security.SuppressUnmanagedCodeSecurityAttribute 不得应用于此类。)此类用于可在任何位置使用的方法,因为会执行堆栈审核。
SafeNativeMethods - 此类会对非托管代码权限取消堆栈审核。 (System.Security.SuppressUnmanagedCodeSecurityAttribute 应用于此类。)此类用于可供任何人安全调用的方法。 这些方法的调用方不需要执行完整安全评审以确保使用是安全的,因为这些方法对于任何调用方都无害。
UnsafeNativeMethods - 此类会对非托管代码权限取消堆栈审核。 (System.Security.SuppressUnmanagedCodeSecurityAttribute 应用于此类。)此类用于有潜在危险的方法。 这些方法的任何调用方都必须执行完整安全检查,以确保使用是安全的,因为不会执行任何堆栈审核。
这些类声明为 internal(在 Visual Basic 中为 Friend),并声明一个私有构造函数来阻止创建新实例。 这些类中的方法应是 static 和 internal(在在 Visual Basic 中是 Shared 和 Friend)。
如何解决冲突
若要解决与此规则的冲突,请将方法移动到合适的 NativeMethods 类中。 对于大多数应用程序,将 P/Invoke 移动到名为 NativeMethods 的新类便足够了。
但是,如果要开发在其他应用程序中使用的库,应考虑定义两个名为 SafeNativeMethods 和 UnsafeNativeMethods 的其他类。 这些类与 NativeMethods 类相似;但是,它们使用名为 SuppressUnmanagedCodeSecurityAttribute 的特殊属性进行标记 。 应用此属性时,运行时不会执行完整堆栈审核来确保所有调用方都具有 UnmanagedCode 权限。 运行时通常会在启动时检查是否具有此权限。 因此可极大地提高对这些非托管方法的调用的性能,还使具备有限权限的代码可以调用这些方法。
不过,应非常小心地使用此属性。 如果未正确实现,则可能会产生严重的安全隐患。
有关如何实现这些方法的信息,请参阅 NativeMethods 示例、SafeNativeMethods 示例和 UnsafeNativeMethods 示例 。
何时禁止显示警告
不禁止显示此规则发出的警告。
示例
下面的示例声明了违反此规则的方法。 若要更正该冲突,应将 RemoveDirectory P/Invoke 移动到设计为仅保存 P/invoke 的适当类。
' Violates rule: MovePInvokesToNativeMethodsClass.Friend Class UnmanagedApi Friend declare Function RemoveDirectory Lib "kernel32" ( ByVal Name As String) As BooleanEnd Class// Violates rule: MovePInvokesToNativeMethodsClass.internal class UnmanagedApi{ [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] internal static extern bool RemoveDirectory(string name);}NativeMethods 示例
由于 NativeMethods 类不应使用 SuppressUnmanagedCodeSecurityAttribute 进行标记,因此,置于其中的 P/invoke 需要 UnmanagedCode 权限 。 由于大多数应用程序从本地计算机运行并随完全信任一起运行,因此这通常不会成为问题。 但是,如果要开发可重用的库,则应考虑定义 SafeNativeMethods 或 UnsafeNativeMethods 类 。
下面的示例演示了一个 Interaction.Beep 方法,它可包装来自 user32.dll 的 MessageBeep 函数 。 MessageBeep P/Invoke 会置于 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 SubEnd ClassFriend 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 FunctionEnd Classpublic 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);}SafeNativeMethods 示例
可以安全地向任何应用程序公开并且没有任何副作用的 P/Invoke 方法应置于名为 SafeNativeMethods 的类中。 不必要求获得权限,也不必过多注意从其处调用权限。
下面的示例演示了一个 Environment.TickCount 属性,它可包装来自 kernel32.dll 的 GetTickCount 函数 。
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 PropertyEnd 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 FunctionEnd Classpublic 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();}UnsafeNativeMethods 示例
不能安全调用并且可能导致副作用的 P/Invoke 方法应置于名为 UnsafeNativeMethods 的类中。 应严格检查这些方法,以确保不会无意中向用户公开它们。 此外,这些方法在使用时,还应具有所需的其他权限,而不是 UnmanagedCode。
下面的示例演示了一个 Cursor.Hide 方法,它可包装来自 user32.dll 的 ShowCursor 函数 。
Public NotInheritable Class Cursor Private Sub New() End Sub ' Callers do not require Unmanaged permission, however, ' they do require UIPermission.AllWindows Public Shared Sub Hide() ' Need to demand an appropriate permission ' in place of UnmanagedCode permission as ' ShowCursor is not considered a safe method Dim permission As New UIPermission(UIPermissionWindow.AllWindows) permission.Demand() UnsafeNativeMethods.ShowCursor(False) End SubEnd 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 FunctionEnd Classpublic static class Cursor{ // Callers do not require UnmanagedCode permission, however, // they do require UIPermissionWindow.AllWindows. public static void Hide() { // Need to demand an appropriate permission // in place of UnmanagedCode permission as // ShowCursor is not considered a safe method. new UIPermission(UIPermissionWindow.AllWindows).Demand(); 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);}另请参阅
设计规则