65.9K
CodeProject 正在变化。 阅读更多。
Home

理解 .NET 代码访问安全性

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (283投票s)

2003年12月28日

23分钟阅读

viewsIcon

941835

downloadIcon

1

一篇关于 .NET 代码访问安全性的长文

目录

引言

在过去几年里,我从 CodeProject 学到了很多东西……现在我将回馈 CodeProject。由于我没有找到关于代码访问安全性的文章,所以这是我的文章。尽情享受吧!

我不会用理论来烦你,但在我们开始之前,你需要学习一些概念和关键词。.NET 有两种安全性

  1. 基于角色的安全性(本文不讨论)
  2. 代码访问安全

公共语言运行时(CLR)只允许代码执行其有权执行的操作。因此,CAS 是 CLR 的安全系统,它通过防止未经授权访问受保护的资源操作来强制执行安全策略。使用代码访问安全性,您可以执行以下操作

  • 限制代码可以执行的操作
  • 限制哪些代码可以调用您的代码
  • 识别代码

我们将在本文中讨论这些内容。在此之前,您应该熟悉这些术语。

术语

代码访问安全性由以下元素组成

  • permissions
  • 权限集
  • 代码组
  • 证据
  • 策略

权限

权限表示对受保护资源的访问或执行受保护操作的能力。.NET Framework 提供了几种权限类,例如 FileIOPermission(处理文件时)、UIPermission(使用用户界面的权限)、SecurityPermission(执行代码所需,甚至可以用于绕过安全性)等。我不会在这里列出所有权限类,它们列在下面。

权限集

权限集是权限的集合。您可以将 FileIOPermissionUIPermission 放入您自己的权限集并将其命名为“My_PermissionSet”。权限集可以包含任意数量的权限。FullTrustLocalIntranetInternetExecutionNothing 是 .NET Framework 中一些内置的权限集。FullTrust 拥有世界上所有的权限,而 Nothing 完全没有权限,甚至没有执行的权利。

代码组

代码组是代码的逻辑分组,它具有特定的成员资格条件。来自 http://www.somewebsite.com/ 的代码可以属于一个代码组,包含特定强名称的代码可以属于另一个代码组,来自特定程序集的代码可以属于另一个代码组。有内置的代码组,如 My_Computer_ZoneLocalIntranet_ZoneInternet_Zone 等。像权限集一样,我们可以根据 .NET Framework 提供的证据创建代码组以满足我们的要求。SiteStrong NameZoneURL 是证据的一些类型。

策略

安全策略是 CLR 在确定授予代码的权限时遵循的可配置规则集。有四个策略级别 - EnterpriseMachineUserApplication Domain,每个级别独立运行。每个级别都有自己的代码组和权限集。它们具有以下层次结构。

图 1

好了,理论讲够了,是时候将理论付诸实践了。

快速示例

让我们创建一个新的 Windows 应用程序。在现有窗体中添加两个按钮。我们将使用文件系统,因此添加 System.IO 命名空间。

using System.IO;

图 2

编写以下代码

private void btnWrite_click(object sender, System.EventArgs e)
{ 
    StreamWriter myFile = new StreamWriter("c:\\Security.txt");
    myFile.WriteLine("Trust No One");
    myFile.Close();
}

private void btnRead_click(object sender, System.EventArgs e)
{ 
    StreamReader myFile = new StreamReader("c:\\Security.txt");
    MessageBox.Show(myFile.ReadLine())
    myFile.Close()
}

为了我们的示例正常工作,版本号应该始终保持不变。确保将版本号设置为固定值,否则每次编译代码时它都会递增。我们将用强名称签署此程序集,该强名称用作识别我们代码的证据。这就是为什么你需要将版本号设置为固定值的原因。

[assembly: AssemblyVersion("1.0.0.0")]

就是这样……没什么花哨的。这将在 C: 驱动器中写入一个名为 Security.txt 的文件。现在运行代码,它应该创建一个文件并写入该行,一切都应该正常……当然,除非你没有 C: 驱动器。现在我们要做的就是将我们的程序集放入一个代码组并设置一些权限。暂时不要删除 Security.txt 文件,我们稍后会用到它。我们开始吧。

.NET 配置工具

我们可以通过两种方式完成此操作:从 .NET 配置工具或从命令提示符使用 caspol.exe。首先,我们将使用 .NET 配置工具完成此操作。转到控制面板 --> 管理工具 --> Microsoft .NET Framework 配置。您也可以在 .NET 命令提示符下键入“mscorcfg.msc”。您可以使用此工具做很多很酷的事情……但现在我们只对设置代码访问安全性感兴趣。

图 3

创建新的权限集

展开运行时安全策略节点。您可以看到安全策略级别 - EnterpriseMachineUser。我们将更改 Machine 策略中的安全设置。首先,我们将创建自己的自定义权限集。右键单击权限集节点并选择新建。由于我想不出一个引人注目的名称,我将它命名为 MyPermissionSet

图 4

在下一个屏幕中,我们可以向我们的权限集添加权限。在左侧面板中,我们可以看到 .NET Framework 支持的所有权限。现在获取文件 IO 权限的属性。将文件路径设置为 C:\ 并仅选中读取,不要选中其他选项。所以我们没有赋予写入权限,我们只赋予了读取权限。请注意,还有另一个选项“授予程序集对文件系统无限制的访问权限”。如果选中此选项,则对于该特定资源(在本例中为文件系统),可以执行任何操作而没有任何限制。

图 5

现在我们必须再添加两个权限——安全用户界面。只需添加它们并记住设置“授予程序集无限制访问”。我很快就会解释这些属性。没有安全权限,我们就无权执行代码;没有用户界面权限,我们就无法显示用户界面。如果您已添加完这三个权限,您会看到已创建一个名为 MyPermissionSet 的新权限集。

创建新的代码组

现在我们将创建一个代码组并设置一些条件,以便我们的程序集将成为该代码组的成员。请注意,在代码组节点中,All_Code 是父节点。右键单击 All_Code 节点并选择新建。您将看到创建代码组向导。我将它命名为 MyCodeGroup

图 6

在下一个屏幕中,您必须为代码组提供一个条件类型。现在这些就是我之前提到的证据。对于此示例,我们将使用强名称条件类型。首先,用强名称签署您的程序集并构建项目。现在按导入按钮并选择您的程序集。公钥、名称和版本将从程序集中提取,因此我们不必担心它们。现在转到下一个屏幕。我们必须为我们的代码组指定一个权限集。由于我们已经创建了一个 - MyPermissionSet,请从列表框中选择它。

图 7

Exclusive 和 LevelFinal

如果您没有修改默认的 .NET 配置安全设置,您的程序集已经属于另一个内置代码组 - My_Computer_Zone。计算权限时,如果特定程序集属于同一策略级别内的多个代码组,则该程序集的最终权限将是这些代码组中所有权限的并集。我稍后将解释如何计算权限,目前我们只需要使用我们的权限集运行我们的程序集,即与 MyCodeGroup 关联的 MyPermissionSet。因此,我们必须设置另一个属性来做到这一点。右键单击新创建的 MyCodeGroup 节点并选择属性。选中“此策略级别将只拥有与此代码组关联的权限集中的权限。”复选框。这称为 Exclusive 属性。如果选中此选项,则运行时绝不会授予超出与此代码组关联的权限的权限。另一个选项称为 LevelFinal。这两个属性在计算权限时发挥作用,下面将详细解释它们。

图 8

我知道我们设置了很多属性,但最终(希望如此)都会有意义。

好的,是时候运行代码了。到目前为止我们所做的就是,我们将代码放入一个代码组,并且只授予从 C: 驱动器读取的权限。运行代码并尝试两个按钮。读取应该正常工作,但是当您按下写入时,会抛出异常,因为我们没有设置写入 C: 驱动器的权限。下面是您收到的错误消息。

图 9

因此,多亏了代码访问安全性,这种对资源的限制成为可能。代码访问安全性还有很多功能,我们将在本文的其余部分中讨论。

代码访问安全性的功能

根据文档,代码访问安全性执行以下功能:(直接引自文档)

  • 定义表示访问各种系统资源的权利的权限权限集
  • 使管理员能够通过将权限集与代码组(代码组)关联来配置安全策略
  • 使代码能够请求其运行所需的权限,以及有用的权限,并指定代码绝不能拥有的权限
  • 根据代码请求的权限和安全策略允许的操作,授予加载的每个程序集权限
  • 使代码能够要求其调用者具有特定权限。使代码能够要求其调用者拥有数字签名,从而只允许特定组织或站点的调用者调用受保护的代码。
  • 在运行时通过将调用堆栈上每个调用者的授予权限与调用者必须拥有的权限进行比较来强制执行代码限制

我们已经完成了前两项,那是管理部分。还有一个我们还没有看过的独立命名空间 - System.Security,它专门用于实现安全性。

安全命名空间

这些是 System.Security 命名空间中的主要类

描述
CodeAccessPermission 定义所有代码访问权限的基础结构。
PermissionSet 表示一个可以包含多种不同类型权限的集合。
SecurityException 检测到安全错误时抛出的异常。

这些是 System.Security.Permissions 命名空间中的主要类

描述
EnvironmentPermission 控制对系统和用户环境变量的访问。
FileDialogPermission 控制通过文件对话框访问文件或文件夹的能力。
FileIOPermission 控制访问文件和文件夹的能力。
IsolatedStorageFilePermission 指定私有虚拟文件系统的允许用法。
IsolatedStoragePermission 表示对通用独立存储功能的访问。
ReflectionPermission 通过 System.Reflection API 控制对元数据的访问。
RegistryPermission 控制访问注册表变量的能力。
SecurityPermission 描述应用于代码的一组安全权限。
UIPermission 控制与用户界面和剪贴板相关的权限。

您可以在其他命名空间中找到更多权限类。例如,System.Net 命名空间中的 SocketPermissionWebPermissionSystem.Data.SqlClient 命名空间中的 SqlClientPermissionSystem.Diagnostics 命名空间中的 PerformanceCounterPermission 等。所有这些类都表示一个受保护的资源。

接下来,我们将看看如何使用这些类。

声明式与命令式

编码时可以使用两种不同的语法:声明式和命令式。

声明式语法

声明式语法使用属性来标记方法、类或程序集以提供必要的安全信息。因此,编译时,这些信息被放置在程序集的元数据部分。

[FileIOPermission(SecurityAction.Demand, Unrestricted=true)]
public calss MyClass 
{
    public MyClass() {...}   // all these methods
    public void MyMethod_A() {...} // demands unrestricted access to 
    public void MyMethod_B() {...} // the file system
}

命令式语法

命令式语法使用运行时方法调用来创建安全类的新实例。

public calss MyClass 
{
    public MyClass() { }

    public void Method_A() 
    {
        // Do Something

        FileIOPermission myPerm = 
          new FileIOPermission(PermissionState.Unrestricted);
        myPerm.Demand(); 
        // rest of the code won't get executed if this failed

        // Do Something
    }

    // No demands
    public void Method_B()
    {
        // Do Something
    }
}

这两种方法的主要区别在于,声明式调用在编译时评估,而命令式调用在运行时评估。请注意,编译时是指 JIT 编译(IL 到原生)期间。

可以对权限采取多种操作。

首先,让我们看看如何使用声明式语法。以 UIPermission 类为例。声明式语法意味着使用属性。所以我们实际上使用的是 UIPermissionAttribute 类。当您参考 MSDN 文档时,您可以看到这些公共属性

  • Action - SecurityAction enum 中的值之一(常用)
  • Unrestricted - 对资源的无限制访问(常用)
  • Clipboard - 对剪贴板的访问类型,UIPermissionClipboard enum 中的值之一(UIPermission 特有)
  • Window - 对窗口的访问类型,UIPermissionWindow enum 中的值之一(UIPermission 特有)。

ActionUnrestricted 属性是所有权限类共有的。ClipboardWindow 属性是 UIPermission 类特有的。您必须提供您正在执行的操作以及您正在使用的权限类特有的其他属性。因此,在这种情况下,您可以像下面这样编写

[UIPermission(SecurityAction.Demand,
      Clipboard=UIPermissionClipboard.AllClipboard)]

或同时使用 ClipboardWindow 属性

[UIPermission(SecurityAction.Demand,
      Clipboard=UIPermissionClipboard.AllClipboard, 
      Window=UIPermissionWindow.AllWindows)]

如果要声明具有无限制访问权限的权限,可以按以下方式进行

[UIPermission(SecurityAction.Demand, Unrestricted=true)]

使用命令式语法时,您可以使用构造函数传递值,然后调用适当的操作。我们将以 RegistryPermission 类为例。

RegistryPermission myRegPerm = 
   new RegistryPermission(RegistryPermissionAccess.AllAccess,
   "HKEY_LOCAL_MACHINE\\Software");
myRegPerm.Demand();

如果您想要对资源的无限制访问,可以使用 PermissionState enum,如下所示:

RegistryPermission myRegPerm = new 
  RegistryPermission(PermissionState.Unrestricted);
myRegPerm.Demand();

这是您在使用 .NET Framework 中的任何权限类时所需了解的所有知识。现在,我们将详细讨论这些操作。

安全需求

需求用于确保调用您的代码(直接或间接)的每个调用者都已获得所需权限。这是通过执行堆栈遍历来完成的。什么……猫步?不,那是你女朋友做的。我指的是堆栈遍历。当请求权限时,运行时的安全系统会遍历调用堆栈,将每个调用者的授予权限与请求的权限进行比较。如果在调用堆栈中发现任何调用者没有请求的权限,则会抛出 SecurityException。请看下面这张来自 MSDN 文档的图。

图 10

堆栈遍历会检查不同的程序集以及同一程序集中的不同方法。

现在回到需求。这些是三种类型的需求。

  • 需求(Demand)
  • 链接需求(Link Demand)
  • 继承需求(Inheritance Demand)

需求(Demand)

试试这个示例代码。我们之前没有使用安全命名空间,但现在我们将使用它们。

using System.Security;
using System.Security.Permissions;

向现有窗体添加另一个按钮。

private void btnFileRead_Click(object sender, System.EventArgs e)
{
    try
    {
        InitUI(1); 
    }
    catch (SecurityException err)
    {
        MessageBox.Show(err.Message,"Security Error");
    }
    catch (Exception err)
    {
        MessageBox.Show(err.Message,"Error");
    } 
}

InitUI 仅调用 ShowUI 函数。请注意,它已被拒绝读取 C: 驱动器的权限。

// Access is denied for this function to read from C: drive
// Note: Using declrative syntax
[FileIOPermission(SecurityAction.Deny,Read="C:\\")]
private void InitUI(int uino)
{
    // Do some initializations
    ShowUI(uino);    // call ShowUI
}

ShowUI 函数接收 uino 并显示相应的 UI。

private void ShowUI(int uino)
{
    switch (uino)
    {
        case 1: // That's our FileRead UI
            ShowFileReadUI();
            break;
        case 2:
            // Show someother UI
            break;            
    }
}

ShowFileReadUI 显示与文件读取相关的 UI。

private void ShowFileReadUI()
{
    MessageBox.Show("Before calling demand");
    FileIOPermission myPerm = new 
      FileIOPermission(FileIOPermissionAccess.Read, "C:\\");
    myPerm.Demand();
       // All callers must have read permission to C: drive
      // Note: Using imperative syntax
      
    // code to show UI
    MessageBox.Show("Showing FileRead UI");
    // This is excuted if only the Demand is successful.
}

我知道这是一个愚蠢的例子,但这足以完成任务。

现在运行代码。您应该会看到“Before calling demand”消息,紧接着是自定义错误消息 - “Security Error”。哪里出了问题?请看下图

图 11

我们拒绝了 InitUI 方法的读取权限。因此,当 ShowFileReadUI 请求读取 C: 驱动器的权限时,它会触发堆栈遍历,并发现并非所有调用者都已获得请求的权限,从而抛出异常。只需注释掉 InitUI 方法中的 Deny 语句,然后它应该可以正常工作,因为所有调用者都拥有请求的权限。

请注意,根据文档,.NET Framework 中的大多数类都已与它们相关联了需求。例如,以 StreamReader 类为例。StreamReader 会自动要求 FileIOPermission。因此,在其前面放置另一个需求会导致不必要的堆栈遍历。

链接需求(Link Demand)

链接需求仅检查代码的直接调用者(直接调用者)。这意味着它不执行堆栈遍历。链接发生在您的代码绑定到类型引用时,包括函数指针引用和方法调用。链接需求只能以声明方式应用。

[FileIOPermission(SecurityAction.LinkDemand,Read="C:\\")]
private void MyMethod()
{
    // Do Something 
}

继承需求(Inheritance Demand)

继承需求可以应用于类或方法。如果应用于类,则所有从该类派生的类都必须具有指定的权限。

[SecurityPermission(SecurityAction.InheritanceDemand)]
private class MyClass()
{
    // what ever
}

如果应用于方法,则所有从该类派生的类都必须具有指定权限才能覆盖该方法。

private class MyClass()
{
    public class MyClass() {}
    
    [SecurityPermission(SecurityAction.InheritanceDemand)]
    public virtual void MyMethod()
    {
        // Do something
    }
}

与链接需求一样,继承需求也只能使用声明式语法应用。

请求权限

想象一下这样的情况。您向用户提供了一个包含 20 多个字段的精美表单,供其输入,最后所有信息都将保存到文本文件中。用户填写完所有必要的字段后,当他尝试保存时,他会收到一条友好的消息,告知他没有必要的权限来创建文本文件!当然,您可以尝试通过解释这一切都是因为堆栈遍历……由需求引起……来安抚他,如果您足够幸运,甚至可以通过指责微软来脱身(相信我……有时这招管用!)。

如果在加载程序集之前就可以请求权限,那岂不是更容易?是的,您可以。代码访问安全性中有三种方法可以做到这一点。

  • RequestMinimum
  • RequestOptional
  • RequestRefuse

请注意,这些只能在程序集级别使用声明式语法应用,不能应用于方法或类。请求权限的最佳之处在于,管理员可以在部署程序集后使用 permview.exe(权限查看工具)查看请求的权限,因此可以授予所需的任何权限。

RequestMinimum

您可以使用 RequestMinimum 来指定代码运行必须拥有的权限。只有当安全策略授予所有必需权限时,代码才会被允许运行。在以下代码片段中,已请求对注册表中某个键进行写入的权限。如果安全策略不授予此权限,程序集甚至不会加载。如上所述,这种请求只能在程序集级别以声明方式进行。

using System;
using System.Windows.Forms;
using System.IO;

using System.Security;
using System.Security.Permissions;

// placed in assembly level
// using declarative syntax
[assembly:RegistryPermission(SecurityAction.RequestMinimum, 
         Write="HKEY_LOCAL_MACHINE\\Software")]

namespace SecurityApp
{
    // Rest of the implementation
}

RequestOptional

使用 RequestOptional,您可以指定代码可以使用的权限,但这些权限不是运行所必需的。如果您的代码以某种方式未获得可选权限,则必须处理在执行需要这些可选权限的代码段时抛出的任何异常。在使用 RequestOptional 时,需要牢记一些事项。

如果您将 RequestOptionalRequestMinimum 一起使用,则除了这两个权限之外,如果安全策略允许,将不会授予任何其他权限。即使安全策略允许您的程序集拥有额外的权限,它们也不会被授予。请看此代码段

[assembly:FileIOPermission(SecurityAction.RequestMinimum, Read="C:\\")]
[assembly:FileIOPermission(SecurityAction.RequestOptional, Write="C:\\")]

此程序集将拥有的唯一权限是文件系统的读写权限。如果它需要显示 UI 怎么办?那么程序集仍然会被加载,但是当显示 UI 的行执行时会抛出异常,因为即使安全策略允许 UIPermission,它也没有被授予此程序集。

请注意,与 RequestMinimum 一样,RequestOptional 不会阻止程序集的加载,但如果未授予可选权限,则会在运行时抛出异常。

RequestRefuse

您可以使用 RequestRefuse 来指定您希望确保永远不会授予您的代码的权限,即使安全策略授予了它们。如果您的代码只想读取文件,那么拒绝写入权限将确保您的代码不会被恶意攻击或错误滥用以修改文件。

[assembly:FileIOPermission(SecurityAction.RequestRefuse, Write="C:\\")]

覆盖安全性

有时您需要覆盖某些安全检查。您可以通过使用这三种方法更改权限堆栈遍历的行为来做到这一点。它们被称为堆栈遍历修改器

  • 断言(Assert)
  • 拒绝(Deny)
  • 仅允许(PermitOnly)

断言(Assert)

您可以调用 Assert 方法来阻止堆栈遍历超出当前堆栈帧。因此,不会检查使用 Assert 的方法上方的调用者。如果您信任上游调用者,那么使用 Assert 不会造成任何危害。您可以使用前面的示例来测试这一点。修改 ShowUI 方法中的代码,只需添加下面显示的两行新代码

private void ShowUI(int uino)
{
    // using imperative syntax to create a instance of FileIOPermission
    FileIOPermission myPerm = new 
      FileIOPermission(FileIOPermissionAccess.Read, "C:\\");
    myPerm.Assert();    // don't check above stack frames.

    switch (uino)
    {
        case 1: // That's our FileRead UI
            ShowFileReadUI();
            break;
        case 2:
            // Show someother UI
            break;            
    }

    CodeAccessPermission.RevertAssert();    // cancel assert
}

确保 InitUI 方法中的 Deny 语句仍然存在。现在运行代码。它应该可以正常工作而不会抛出任何异常。请看下图

图 12

即使 InitUI 没有所要求的权限,它也从未被检查,因为堆栈遍历从 ShowUI 停止。看最后一行。RevertAssertCodeAccessPermission 的一个静态方法。它用于在 Assert 之后取消 Assert 语句。因此,如果 RevertAssert 下方的代码正在访问一些受保护的资源,那么将执行正常的堆栈遍历并检查所有调用者。如果当前堆栈帧没有 Assert,则 RevertAssert 无效。将 RevertAssert 放置在 finally 块中是一个好习惯,这样它总是会被调用。

请注意,要使用 AssertSecurityPermissionAssertion 标志应设置为 true。

微软警告!:如果断言处理不当,可能导致诱导攻击,即恶意代码可以通过受信任代码调用我们的代码。

拒绝(Deny)

我们已经在前面的示例中使用了这个方法。以下代码示例展示了如何使用命令式语法拒绝连接受限制网站的权限

WebPermission myWebPermission = 
        new WebPermission(NetworkAccess.Connect, 
        "http://www.somewebsite.com");
myWebPermission.Deny();

// Do some work

CodeAccessPermission.RevertDeny(); // cancel Deny

RevertDeny 用于从当前堆栈帧中删除先前的 Deny 语句。

仅允许(PermitOnly)

在某些需要限制安全策略授予的权限的情况下,您可以使用 PermitOnly。以下代码片段演示了如何以命令式方式使用它。使用 PermitOnly 意味着只能访问您指定的资源。

WebPermission myWebPermission = 
  new WebPermission(NetworkAccess.Connect, 
  "http://www.somewebsite.com");
myWebPermission.PermitOnly();

// Do some work

CodeAccessPermission.PermitOnly(); // cancel PermitOnly

当描述可以访问的资源比描述不能访问的资源更方便时,您可以使用 PermitOnly 代替 Deny

计算权限

在第一个例子中,我们配置了机器策略级别来为我们的代码设置权限。现在我们将看看当您的代码属于同一策略级别或不同策略级别的多个代码组时,运行时如何计算和授予这些权限。

CLR 通过以下方式计算程序集允许的权限集:

  1. All_Code 代码组开始,使用证据提供的身份信息,搜索所有子组以确定代码属于哪些组。(如果父组不匹配,则不检查该组的子组。)
  2. 当确定特定策略级别中的所有匹配项时,与这些组关联的权限将以加法方式(并集)组合。
  3. 每个策略级别重复此操作,并且与每个策略级别关联的权限相互交叉

因此,与一个策略级别中匹配的代码组相关联的所有权限都会加在一起(并集),并且每个策略级别的结果会相互交叉。使用交叉是为了确保层次结构中较低级别的策略不能添加较高级别未授予的权限。

请参阅下面这张来自 MSDN 文章的图,以便更好地理解

图 13

快速查看 Machine 策略级别中 All_Code 代码组关联的权限集。希望现在你已经明白了。

图 14

如果 ExclusiveLevelFinal 属性应用于代码组,则运行时计算允许的权限集的方式会有所不同。如果您没有短期记忆力丧失,您应该还记得我们在之前的示例中为我们的代码组 MyCodeGroup 设置了 Exclusive 属性。

如果设置了这些属性,会发生以下情况。

  • Exclusive - 标记为 Exclusive 的代码组的权限被视为该策略级别的唯一权限。因此,在计算权限时,不考虑与其他代码组关联的权限。
  • LevelFinal - 包含此代码组的策略级别(应用程序域级别除外)以下的策略级别在检查代码组成员资格和授予权限时不予考虑。

现在您应该清楚我们为什么之前设置了 Exclusive 属性。

.NET 配置工具中的出色功能

.NET 配置工具有一些不错的功能。只需右键单击运行时安全策略节点,您就会明白我在说什么。

图 15

除了其他选项,还有两个重要的。

  • 评估程序集 - 这可以用于找出特定程序集属于哪个(或哪些)代码组,或者它拥有哪些权限。
  • 创建部署包 - 此向导将创建一个策略部署包。只需选择策略级别,此向导就会将其打包成一个 Windows 安装程序包(.msi 文件),因此您开发 PC 中的所有代码组和权限都可以轻松地传输到任何其他机器,省去麻烦。

工具

权限查看工具 - permview.exe

权限查看工具用于查看程序集请求的最小、可选和拒绝的权限集。可选地,您可以使用 permview.exe 查看程序集使用的所有声明性安全性。请参阅 MSDN 文档以获取更多信息。

示例

  • permview SecurityApp.exe - 显示程序集 SecurityApp.exe 请求的权限。

代码访问安全策略工具 - caspol.exe

代码访问安全策略工具使用户和管理员能够修改机器策略级别、用户策略级别和企业策略级别的安全策略。有关更多信息,请参阅 MSDN 文档。

示例

以下是运行“caspol -listgroups”时的输出,它将列出属于默认策略级别 - 机器级别的代码组。

图 16

请注意,“1.”标签代表 All_Code 节点,因为它是一个父节点。其子节点标记为“1.x”,它们的子节点标记为“1.x.x”,明白了吗?

  • caspol -listgroups - 显示代码组
  • caspol -machine -addgroup 1. -zone Internet Execution - 在机器策略代码组层次结构的根部添加一个子代码组。新的代码组是 Internet 区域的成员,并与 Execution 权限集关联。
  • caspol -user -chggroup 1.2. Execution - 将标签为 1.2 的代码组在用户策略中的权限集更改为 Execution 权限集。
  • caspol -security on - 打开代码访问安全性。
  • caspol -security off - 关闭代码访问安全性。

摘要

  • 使用 .NET 代码访问安全性,您可以限制代码可以执行的操作,限制哪些代码可以调用您的代码以及识别代码。
  • 有四个策略级别 - EnterpriseMachineUserApplication Domain,它们包含带有相关权限的代码组。
  • 可以使用声明式语法或命令式语法。
  • 需求可以用来确保每个调用者都拥有所要求的权限。
  • 请求可以在授予时间请求(或拒绝)权限。
  • 授予的权限可以被覆盖。

就是这样。再次查看代码访问安全性的功能。现在您应该比第一次看到它时有更清晰的理解。本文没有讨论诸如创建自定义代码访问权限以及使用代码访问安全性的最佳实践等内容。如果您想了解更多信息,可以参考以下内容

我建议你再完整地看一遍这篇文章,确保你没有遗漏任何内容。如果仍然不清楚,别担心,这不是你的错,是我的错。:)

编码愉快!!!

历史

  • 2003年12月22日 - 原始版本
  • 2004年1月12日 - 修正了代码中的一个错误。(安全需求部分 - 将 btnFileRead_Click 事件中的 ShowUI1(1) 改为 InitUI(1)) - 由 Mark Focas 指出,非常感谢 Mark!更新了屏幕截图(文件大小缩小了 4 倍)。添加了“NET 配置工具中的出色功能”部分。添加了图 16 (caspol 屏幕截图)。
© . All rights reserved.