【问题标题】:UnmanagedCode permission. What is it?非托管代码权限。它是什么?
【发布时间】:2013-03-25 02:23:44
【问题描述】:

以下代码存在于企业库的日志记录应用程序块中的 LogEntry.cs 中:

private bool UnmanagedCodePermissionAvailable
{
  get
  {
    if (!unmanagedCodePermissionAvailableInitialized)
    {
      // check whether the unmanaged code permission is available to avoid three potential stack walks
      bool internalUnmanagedCodePermissionAvailable = false;
      SecurityPermission unmanagedCodePermission = 
                  new SecurityPermission(SecurityPermissionFlag.UnmanagedCode);
      // avoid a stack walk by checking for the permission on the current assembly. this is safe because there are no
      // stack walk modifiers before the call.
      if (SecurityManager.IsGranted(unmanagedCodePermission))
      {
        try
        {
          unmanagedCodePermission.Demand();
          internalUnmanagedCodePermissionAvailable = true;
        }
        catch (SecurityException)
        { }
      }

      this.UnmanagedCodePermissionAvailable = 
          internalUnmanagedCodePermissionAvailable;
    }

    return this.unmanagedCodePermissionAvailable;
  }
  set
  {
    this.unmanagedCodePermissionAvailable = value;
    unmanagedCodePermissionAvailableInitialized = true;
  }
}

在进行多次 P/Invoke 调用之前调用该函数以检索各种信息以帮助填写 LogEntry 结构。如果“UnmanagedCodePermission”不可用,则将相应的 LogEntry 属性设置为指示这种情况的字符串(“XXX 不可用”)。

例如,LogEntry 想要获取 Win32 线程 ID,它使用 P/Invoke 调用的 Win32 函数 GetCurrentThreadId 来获取它。在调用 GetCurrentThreadId 之前,它会检查“未管理的代码权限”是否可用。如果是,它会调用,如果不是,它不会。像这样的:

private void InitializeWin32ThreadId()
{
  if (this.UnmanagedCodePermissionAvailable)
  {
    try
    {
      this.Win32ThreadId = LogEntryContext.GetCurrentThreadId();
    }
    catch (Exception e)
    {
      this.Win32ThreadId = string.Format(
                                  CultureInfo.CurrentCulture,
                                  Properties.Resources.IntrinsicPropertyError,
                                  e.Message);
    }
  }
  else
  {
    this.Win32ThreadId = string.Format(CultureInfo.CurrentCulture,
                Properties.Resources.IntrinsicPropertyError,
                Properties.Resources.
                LogEntryIntrinsicPropertyNoUnmanagedCodePermissionError);
  }
}

据我了解,诚然,这并不多,由于安全/权限/信任,调用非托管代码(例如 P/Invoke)并不总是可能的。通过检查是否可以进行非托管代码调用,可以以统一的方式保护所有非托管调用。

当我编译这段代码时,我在这一行收到警告:

          if (SecurityManager.IsGranted(unmanagedCodePermission))

这里是警告:

System.Security.SecurityManager.IsGranted(System.Security.IPermission)' 已过时:'IsGranted 已过时,将在 .NET Framework 的未来版本中删除。请改用 AppDomain 或 Assembly 的 PermissionSet 属性。

(请注意,我是在 .Net 4.0 上使用 VS2010 构建的)。

所以,看起来 IsGranted 已经过时了。我查看了 AppDomain 和 Assembly 的 PermissionSet 属性,并不清楚如何进行相同的检查。

在 LogEntry 的情况下,该信息看起来并不重要,因此如果非托管权限不可用,则不会将其视为严重故障。从相同的角度考虑以下问题。也就是说,如果非托管代码权限不可用,也不是什么大不了的事,没有信息我也可以活下去。

最后,有几个问题:

  1. 尝试保护对非托管代码(例如 P/Invoke)的调用是否是个好主意?有时,总是,从不?

  2. 如果保护这些调用是个好主意,那么这样做是否合理?有没有更好的办法?

  3. 在 .Net 4.0 中进行等效检查的正确(即不过时)方法是什么?

【问题讨论】:

    标签: c# .net security pinvoke unmanaged


    【解决方案1】:

    在 .NET 4 之前,代码访问安全 (CAS) 是 .NET Fx 使用的安全模型。想法是根据证据确定代码可以做什么,并且不允许做任何其他事情(沙盒)。例如,默认情况下本地计算机上的代码会获得完全信任(基本上它可以做任何事情),而来自互联网的代码将具有受限权限(部分信任)场景。

    IMO,如果您编写的代码不太可能在部分受信任的环境中运行,那么您可能不会太在意。但是对于部分受信任的程序集,

    1. 如果他们可以告诉他们的主机(例如 IE),它需要什么权限,那么主机可以根据安全策略等决定是否授予这些权限。或者主机可以提示用户并允许他覆盖。或者管理员会通过检查程序集知道权限集,他可能会决定更新策略以允许它。
    2. 如果主机没有授予代码所需的权限,那么代码可以检查并优雅地处理它,而不是生成安全异常。

    因此,上面的代码说明了在 .NET 4 之前实现此目的的方法。在 .NET 4 中,有一种更易于使用的新安全模型。请参阅thisthis 文章了解更多信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多